diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index bcf134fc731fe..90398cdcc7407 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -108,11 +108,14 @@ pub trait StorageValue { /// Take a value from storage, removing it afterwards. fn take(storage: &S) -> Self::Query; - /// Store a value under this key into the provded storage instance. + /// Store a value under this key into the provided storage instance. fn put(val: &T, storage: &S) { storage.put(Self::key(), val) } + /// Mutate this value + fn mutate(f: F, storage: &S); + /// Clear the storage value. fn kill(storage: &S) { storage.kill(Self::key()) @@ -180,6 +183,9 @@ pub trait StorageMap { fn remove(key: &K, storage: &S) { storage.kill(&Self::key_for(key)[..]); } + + /// Mutate the value under a key. + fn mutate(key: &K, f: F, storage: &S); } // TODO: Remove this in favour of `decl_storage` macro. @@ -188,103 +194,103 @@ pub trait StorageMap { macro_rules! storage_items { // simple values ($name:ident : $key:expr => $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() () (Option<$ty>) (get) (take) $name: $key => $ty); + __storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident : $key:expr => $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) () (Option<$ty>) (get) (take) $name: $key => $ty); + __storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() () ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + __storage_items_internal!(() () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) () ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + __storage_items_internal!((pub) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() () ($ty) (require) (take_or_panic) $name: $key => $ty); + __storage_items_internal!(() () (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) () ($ty) (require) (take_or_panic) $name: $key => $ty); + __storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() ($getfn) (Option<$ty>) (get) (take) $name: $key => $ty); + __storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) ($getfn) (Option<$ty>) (get) (take) $name: $key => $ty); + __storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() ($getfn) ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + __storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) ($getfn) ($ty) (get_or_default) (take_or_default) $name: $key => $ty); + __storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { - __storage_items_internal!(() ($getfn) ($ty) (require) (take_or_panic) $name: $key => $ty); + __storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { - __storage_items_internal!((pub) ($getfn) ($ty) (require) (take_or_panic) $name: $key => $ty); + __storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); storage_items!($($t)*); }; // maps ($name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() () (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) () (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() () ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!(() () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) () ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!((pub) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() () ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!(() () (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) () ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() ($getfn) (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) ($getfn) (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() ($getfn) ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) ($getfn) ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!(() ($getfn) ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __storage_items_internal!((pub) ($getfn) ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + __storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; @@ -301,15 +307,26 @@ macro_rules! storage_items { () => () } +#[macro_export] +#[doc(hidden)] +macro_rules! __handle_wrap_internal { + (RAW_TYPE { $($raw:tt)* } { $($option:tt)* }) => { + $($raw)*; + }; + (OPTION_TYPE { $($raw:tt)* } { $($option:tt)* }) => { + $($option)*; + }; +} + #[macro_export] #[doc(hidden)] macro_rules! __storage_items_internal { // generator for values. - (($($vis:tt)*) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { - __storage_items_internal!{ ($($vis)*) () ($gettype) ($getter) ($taker) $name : $key => $ty } + (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { + __storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $key => $ty } pub fn $get_fn() -> $gettype { <$name as $crate::storage::generator::StorageValue<$ty>> :: get(&$crate::storage::RuntimeStorage) } }; - (($($vis:tt)*) () ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { + (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { $($vis)* struct $name; impl $crate::storage::generator::StorageValue<$ty> for $name { @@ -329,16 +346,34 @@ macro_rules! __storage_items_internal { fn take(storage: &S) -> Self::Query { storage.$taker($key) } + + /// Mutate this value. + fn mutate(f: F, storage: &S) { + let mut val = >::get(storage); + + f(&mut val); + + __handle_wrap_internal!($wraptype { + // raw type case + >::put(&val, storage) + } { + // Option<> type case + match val { + Some(val) => >::put(&val, storage), + None => >::kill(storage), + } + }); + } } }; // generator for maps. - (($($vis:tt)*) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { - __storage_items_internal!{ ($($vis)*) () ($gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] } + (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { + __storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] } pub fn $get_fn>(key: K) -> $gettype { <$name as $crate::storage::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage) } }; - (($($vis:tt)*) () ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { + (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { $($vis)* struct $name; impl $crate::storage::generator::StorageMap<$kty, $ty> for $name { @@ -367,6 +402,24 @@ macro_rules! __storage_items_internal { let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); storage.$taker(&key[..]) } + + /// Mutate the value under a key. + fn mutate(key: &$kty, f: F, storage: &S) { + let mut val = >::take(key, storage); + + f(&mut val); + + __handle_wrap_internal!($wraptype { + // raw type case + >::insert(key, &val, storage) + } { + // Option<> type case + match val { + Some(val) => >::insert(key, &val, storage), + None => >::remove(key, storage), + } + }); + } } }; // generator for lists. @@ -503,103 +556,103 @@ macro_rules! decl_storage { macro_rules! __decl_storage_items { // simple values ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: $ty); + __decl_storage_item!(() ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: $ty); + __decl_storage_item!((pub) ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : default $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: $ty); + __decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : default $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: $ty); + __decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : required $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: $ty); + __decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : required $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: $ty); + __decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: $ty); + __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: $ty); + __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : default $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: $ty); + __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : default $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: $ty); + __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : required $ty:ty; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: $ty); + __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : required $ty:ty; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: $ty); + __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; // maps ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); + __decl_storage_item!(() ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); + __decl_storage_item!((pub) ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); + __decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); + __decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); + __decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); + __decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); + __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); + __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); + __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); + __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); + __decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; ($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); + __decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]); __decl_storage_items!($cratename $traittype $traitinstance $($t)*); }; @@ -611,10 +664,10 @@ macro_rules! __decl_storage_items { #[doc(hidden)] macro_rules! __decl_storage_item { // generator for values. - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => { - __decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($gettype) ($getter) ($taker) $cratename $name : $ty } + (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => { + __decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($wraptype $gettype) ($getter) ($taker) $cratename $name : $ty } }; - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => { + (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => { $($vis)* struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>); impl<$traitinstance: $traittype> $crate::storage::generator::StorageValue<$ty> for $name<$traitinstance> { @@ -634,13 +687,31 @@ macro_rules! __decl_storage_item { fn take(storage: &S) -> Self::Query { storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) } + + /// Mutate the value under a key. + fn mutate(f: F, storage: &S) { + let mut val = >::get(storage); + + f(&mut val); + + __handle_wrap_internal!($wraptype { + // raw type case + >::put(&val, storage) + } { + // Option<> type case + match val { + Some(val) => >::put(&val, storage), + None => >::kill(storage), + } + }) + } } }; // generator for maps. - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => { - __decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($gettype) ($getter) ($taker) $cratename $name : map [$kty => $ty] } + (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => { + __decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($wraptype $gettype) ($getter) ($taker) $cratename $name : map [$kty => $ty] } }; - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => { + (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => { $($vis)* struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>); impl<$traitinstance: $traittype> $crate::storage::generator::StorageMap<$kty, $ty> for $name<$traitinstance> { @@ -669,6 +740,22 @@ macro_rules! __decl_storage_item { let key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); storage.$taker(&key[..]) } + + /// Mutate the value under a key + fn mutate(key: &$kty, f: F, storage: &S) { + let mut val = >::take(key, storage); + + f(&mut val); + + __handle_wrap_internal!($wraptype { + >::insert(key, &val, storage); + } { + match val { + Some(val) => >::insert(key, &val, storage), + None => >::remove(key, storage), + } + }); + } } }; } diff --git a/substrate/runtime-support/src/storage/mod.rs b/substrate/runtime-support/src/storage/mod.rs index 0d2460297fa82..86f136c58a1b9 100644 --- a/substrate/runtime-support/src/storage/mod.rs +++ b/substrate/runtime-support/src/storage/mod.rs @@ -180,9 +180,12 @@ pub trait StorageValue { /// Load the value from the provided storage instance. fn get() -> Self::Query; - /// Store a value under this key into the provded storage instance. + /// Store a value under this key into the provided storage instance. fn put>(val: Arg); + /// Mutate the value + fn mutate(f: F); + /// Clear the storage value. fn kill(); @@ -205,6 +208,9 @@ impl StorageValue for U where U: generator::StorageValue { fn put>(val: Arg) { U::put(val.borrow(), &RuntimeStorage) } + fn mutate(f: F) { + U::mutate(f, &RuntimeStorage) + } fn kill() { U::kill(&RuntimeStorage) } @@ -304,6 +310,9 @@ pub trait StorageMap { /// Remove the value under a key. fn remove>(key: KeyArg); + /// Mutate the value under a key. + fn mutate, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F); + /// Take the value under a key. fn take>(key: KeyArg) -> Self::Query; } @@ -335,6 +344,10 @@ impl StorageMap for U where U: generator::StorageMa U::remove(key.borrow(), &RuntimeStorage) } + fn mutate, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F) { + U::mutate(key.borrow(), f, &RuntimeStorage) + } + fn take>(key: KeyArg) -> Self::Query { U::take(key.borrow(), &RuntimeStorage) } diff --git a/substrate/runtime/example/src/lib.rs b/substrate/runtime/example/src/lib.rs index a7953074c1048..a195f8e2eadb3 100644 --- a/substrate/runtime/example/src/lib.rs +++ b/substrate/runtime/example/src/lib.rs @@ -28,7 +28,7 @@ extern crate substrate_runtime_std; #[cfg(test)] extern crate substrate_runtime_io as runtime_io; -// Needed for the set of mock primatives used in our tests. +// Needed for the set of mock primitives used in our tests. #[cfg(test)] extern crate substrate_primitives; @@ -110,7 +110,9 @@ decl_module! { /// world. fn accumulate_dummy(origin, increase_by: T::Balance) -> Result; - /// A priviledged call; in this case it resets our dummy value to something new. + fn accumulate_foo(origin, increase_by: T::Balance) -> Result; + + /// A privileged call; in this case it resets our dummy value to something new. fn set_dummy(origin, new_dummy: T::Balance) -> Result; } } @@ -133,7 +135,7 @@ pub enum RawEvent { Dummy(B), } -// By convention we implement any trait for which a "null implemntation" makes sense +// By convention we implement any trait for which a "null implementation" makes sense // for `()`. This is the case for conversion of module `Event` types and hook traits. It // is helpful for test code and production configurations where no eventing is necessary // or the hook is unused. @@ -170,9 +172,12 @@ decl_storage! { // implements `runtime_support::StorageMap`. // // If they have a getter (`get(getter_name)`), then your module will come - // equiped with `fn getter_name() -> Type` for basic value items or + // equipped with `fn getter_name() -> Type` for basic value items or // `fn getter_name(key: KeyType) -> ValueType` for map items. Dummy get(dummy): T::Balance; + + // this one uses the default, we'll demonstrate the usage of 'mutate' API. + Foo get(foo): default T::Balance; } } @@ -232,18 +237,24 @@ impl Module { let _sender = ensure_signed(origin)?; // Read the value of dummy from storage. - let dummy = Self::dummy(); - // Will also work using the `::get` on the storage item type iself: + // let dummy = Self::dummy(); + // Will also work using the `::get` on the storage item type itself: // let dummy = >::get(); // Calculate the new value. - let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); + // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); // Put the new value into storage. - >::put(new_dummy); + // >::put(new_dummy); // Will also work with a reference: // >::put(&new_dummy); + // Here's the new one of read and then modify the value. + >::mutate(|dummy| { + let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); + *dummy = Some(new_dummy); + }); + // Let's deposit an event to let the outside world know this happened. Self::deposit_event(RawEvent::Dummy(increase_by)); @@ -251,10 +262,19 @@ impl Module { Ok(()) } - // Implementation of a priviledged call. This doesn't have an `origin` parameter because + fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> Result { + let _sender = ensure_signed(origin)?; + + // Because Foo has 'default', the type of 'foo' in closure is the raw type instead of an Option<> type. + >::mutate(|foo| *foo = *foo + increase_by); + + Ok(()) + } + + // Implementation of a privileged call. This doesn't have an `origin` parameter because // it's not (directly) from an extrinsic, but rather the system as a whole has decided - // to execute it. Different runtimes have different reasons for allow priviledged - // calls to be executed - we don't need to care why. Because it's priviledged, we can + // to execute it. Different runtimes have different reasons for allow privileged + // calls to be executed - we don't need to care why. Because it's privileged, we can // assume it's a one-off operation and substantial processing/storage/memory can be used // without worrying about gameability or attack scenarios. fn set_dummy(origin: T::Origin, new_value: T::Balance) -> Result { @@ -287,6 +307,7 @@ impl OnFinalise for Module { pub struct GenesisConfig { /// A value with which to initialise the Dummy storage item. pub dummy: T::Balance, + pub foo: T::Balance, } #[cfg(feature = "std")] @@ -294,6 +315,7 @@ impl Default for GenesisConfig { fn default() -> Self { GenesisConfig { dummy: Default::default(), + foo: Default::default(), } } } @@ -311,7 +333,8 @@ impl runtime_primitives::BuildStorage for GenesisConfig fn build_storage(self) -> ::std::result::Result { use codec::Encode; Ok(map![ - Self::hash(>::key()).to_vec() => self.dummy.encode() + Self::hash(>::key()).to_vec() => self.dummy.encode(), + Self::hash(>::key()).to_vec() => self.foo.encode() ]) } } @@ -369,12 +392,13 @@ mod tests { t.extend(balances::GenesisConfig::::default().build_storage().unwrap()); t.extend(GenesisConfig::{ dummy: 42, + foo: 24, }.build_storage().unwrap()); t.into() } #[test] - fn it_works() { + fn it_works_for_optional_value() { with_externalities(&mut new_test_ext(), || { // Check that GenesisBuilder works properly. assert_eq!(Example::dummy(), Some(42)); @@ -382,7 +406,7 @@ mod tests { // Check that accumulate works when we have Some value in Dummy already. assert_ok!(Example::accumulate_dummy(Origin::signed(1), 27)); assert_eq!(Example::dummy(), Some(69)); - + // Check that finalising the block removes Dummy from storage. >::on_finalise(1); assert_eq!(Example::dummy(), None); @@ -392,4 +416,13 @@ mod tests { assert_eq!(Example::dummy(), Some(42)); }); } + + #[test] + fn it_works_for_default_value() { + with_externalities(&mut new_test_ext(), || { + assert_eq!(Example::foo(), 24); + assert_ok!(Example::accumulate_foo(Origin::signed(1), 1)); + assert_eq!(Example::foo(), 25); + }); + } } diff --git a/substrate/runtime/treasury/src/lib.rs b/substrate/runtime/treasury/src/lib.rs index b0b962a7d58d5..01d4142dd9aab 100644 --- a/substrate/runtime/treasury/src/lib.rs +++ b/substrate/runtime/treasury/src/lib.rs @@ -205,13 +205,7 @@ impl Module { ensure_root(origin)?; ensure!(>::exists(proposal_id), "No proposal at that index"); - { - let mut v = >::get(); - v.push(proposal_id); - >::put(v); - } - //TODO gav: make work: - //>::mutate(|a| a.push(proposal_id)); + >::mutate(|v| v.push(proposal_id)); Ok(()) }