add mutate api (#695)

* runtime-storage: add 'mutate' api

* support mutate for StorageValue

* try adding 'mutate' for map

* dispatch on Option<> type

* add check for prev_some

* consolidate the wrap type

* unify wrap type handling

* add sample for StorageValue
This commit is contained in:
Guanqun Lu
2018-09-09 19:32:15 +08:00
committed by Gav Wood
parent 6fb9b5a0ba
commit ea7aeb8409
4 changed files with 210 additions and 83 deletions
@@ -108,11 +108,14 @@ pub trait StorageValue<T: codec::Codec> {
/// Take a value from storage, removing it afterwards.
fn take<S: Storage>(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<S: Storage>(val: &T, storage: &S) {
storage.put(Self::key(), val)
}
/// Mutate this value
fn mutate<F: FnOnce(&mut Self::Query), S: Storage>(f: F, storage: &S);
/// Clear the storage value.
fn kill<S: Storage>(storage: &S) {
storage.kill(Self::key())
@@ -180,6 +183,9 @@ pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
fn remove<S: Storage>(key: &K, storage: &S) {
storage.kill(&Self::key_for(key)[..]);
}
/// Mutate the value under a key.
fn mutate<F: FnOnce(&mut Self::Query), S: Storage>(key: &K, f: F, storage: &S);
}
// TODO: Remove this in favour of `decl_storage` macro.
@@ -188,103 +194,103 @@ pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
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<S: $crate::GenericStorage>(storage: &S) -> Self::Query {
storage.$taker($key)
}
/// Mutate this value.
fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(f: F, storage: &S) {
let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage);
f(&mut val);
__handle_wrap_internal!($wraptype {
// raw type case
<Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage)
} {
// Option<> type case
match val {
Some(val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage),
None => <Self as $crate::storage::generator::StorageValue<$ty>>::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<K: $crate::storage::generator::Borrow<$kty>>(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<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) {
let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage);
f(&mut val);
__handle_wrap_internal!($wraptype {
// raw type case
<Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage)
} {
// Option<> type case
match val {
Some(val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage),
None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::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<S: $crate::GenericStorage>(storage: &S) -> Self::Query {
storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key())
}
/// Mutate the value under a key.
fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(f: F, storage: &S) {
let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage);
f(&mut val);
__handle_wrap_internal!($wraptype {
// raw type case
<Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage)
} {
// Option<> type case
match val {
Some(val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage),
None => <Self as $crate::storage::generator::StorageValue<$ty>>::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<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) {
let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage);
f(&mut val);
__handle_wrap_internal!($wraptype {
<Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage);
} {
match val {
Some(val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage),
None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage),
}
});
}
}
};
}
@@ -180,9 +180,12 @@ pub trait StorageValue<T: Codec> {
/// 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<Arg: Borrow<T>>(val: Arg);
/// Mutate the value
fn mutate<F: FnOnce(&mut Self::Query)>(f: F);
/// Clear the storage value.
fn kill();
@@ -205,6 +208,9 @@ impl<T: Codec, U> StorageValue<T> for U where U: generator::StorageValue<T> {
fn put<Arg: Borrow<T>>(val: Arg) {
U::put(val.borrow(), &RuntimeStorage)
}
fn mutate<F: FnOnce(&mut Self::Query)>(f: F) {
U::mutate(f, &RuntimeStorage)
}
fn kill() {
U::kill(&RuntimeStorage)
}
@@ -304,6 +310,9 @@ pub trait StorageMap<K: Codec, V: Codec> {
/// Remove the value under a key.
fn remove<KeyArg: Borrow<K>>(key: KeyArg);
/// Mutate the value under a key.
fn mutate<KeyArg: Borrow<K>, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F);
/// Take the value under a key.
fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query;
}
@@ -335,6 +344,10 @@ impl<K: Codec, V: Codec, U> StorageMap<K, V> for U where U: generator::StorageMa
U::remove(key.borrow(), &RuntimeStorage)
}
fn mutate<KeyArg: Borrow<K>, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F) {
U::mutate(key.borrow(), f, &RuntimeStorage)
}
fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query {
U::take(key.borrow(), &RuntimeStorage)
}
+47 -14
View File
@@ -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<B> {
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<T: Trait> Module<T> {
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 = <Dummy<T>>::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.
<Dummy<T>>::put(new_dummy);
// <Dummy<T>>::put(new_dummy);
// Will also work with a reference:
// <Dummy<T>>::put(&new_dummy);
// Here's the new one of read and then modify the value.
<Dummy<T>>::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<T: Trait> Module<T> {
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.
<Foo<T>>::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<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
pub struct GenesisConfig<T: Trait> {
/// 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<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
dummy: Default::default(),
foo: Default::default(),
}
}
}
@@ -311,7 +333,8 @@ impl<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T>
fn build_storage(self) -> ::std::result::Result<runtime_primitives::StorageMap, String> {
use codec::Encode;
Ok(map![
Self::hash(<Dummy<T>>::key()).to_vec() => self.dummy.encode()
Self::hash(<Dummy<T>>::key()).to_vec() => self.dummy.encode(),
Self::hash(<Foo<T>>::key()).to_vec() => self.foo.encode()
])
}
}
@@ -369,12 +392,13 @@ mod tests {
t.extend(balances::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(GenesisConfig::<Test>{
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.
<Example as OnFinalise<u64>>::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);
});
}
}
@@ -205,13 +205,7 @@ impl<T: Trait> Module<T> {
ensure_root(origin)?;
ensure!(<Proposals<T>>::exists(proposal_id), "No proposal at that index");
{
let mut v = <Approvals<T>>::get();
v.push(proposal_id);
<Approvals<T>>::put(v);
}
//TODO gav: make work:
//<Approvals<T>>::mutate(|a| a.push(proposal_id));
<Approvals<T>>::mutate(|v| v.push(proposal_id));
Ok(())
}