EnumerableStorageMap (#1763)

* Refactor decl_storage a bit to allow easier impl of linked map.

* A bunch of refactorings for storage generation.

- Rename StorageMap and ChildrenStorageMap to avoid confusion with generator::StorageMap.
- Separate implementation from the procedural macro code to clean it up.
- Make sure that genesis is initialised using the `StorageValue/StorageMap`
  generated implementations instead of going RAW.

* WiP: Writing test.

* Basic implementation.

* Implement enumeration.

* Fix non-std issues.

* fix warning

* Fix test-client.

* Address review grumbles - part 1

* Avoid cloning the key, relax Storage requirements.

* Rebuild runtime.

* Remove dangling todo.
This commit is contained in:
Tomasz Drwięga
2019-02-13 08:52:52 +01:00
committed by Bastian Köcher
parent 6e26c52191
commit 9e2710246f
20 changed files with 803 additions and 243 deletions
+1 -1
View File
@@ -51,7 +51,7 @@ use proc_macro::TokenStream;
/// }
/// add_extra_genesis {
/// config(genesis_field): GenesisFieldType;
/// build(|_: &mut StorageMap, _: &mut ChildrenStorageMap, _: &GenesisConfig<T>| {
/// build(|_: &mut StorageOverlay, _: &mut ChildrenStorageOverlay, _: &GenesisConfig<T>| {
/// })
/// }
/// }
@@ -0,0 +1,428 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use proc_macro2::TokenStream as TokenStream2;
use syn;
use quote::quote;
use crate::storage::transformation::DeclStorageTypeInfos;
pub fn option_unwrap(is_option: bool) -> TokenStream2 {
if !is_option {
// raw type case
quote!( unwrap_or_else )
} else {
// Option<> type case
quote!( or_else )
}
}
pub(crate) struct Impls<'a> {
pub scrate: &'a TokenStream2,
pub visibility: &'a syn::Visibility,
pub traitinstance: &'a syn::Ident,
pub traittype: &'a syn::TypeParamBound,
pub type_infos: DeclStorageTypeInfos<'a>,
pub fielddefault: TokenStream2,
pub prefix: String,
pub name: &'a syn::Ident,
}
impl<'a> Impls<'a> {
pub fn simple_value(self) -> TokenStream2 {
let Self {
scrate,
visibility,
traitinstance,
traittype,
type_infos,
fielddefault,
prefix,
name,
} = self;
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
let option_simple_1 = option_unwrap(is_option);
let mutate_impl = if !is_option {
quote!{
<Self as #scrate::storage::generator::StorageValue<#typ>>::put(&val, storage)
}
} else {
quote!{
match val {
Some(ref val) => <Self as #scrate::storage::generator::StorageValue<#typ>>::put(&val, storage),
None => <Self as #scrate::storage::generator::StorageValue<#typ>>::kill(storage),
}
}
};
// generator for value
quote!{
#visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>);
impl<#traitinstance: #traittype> #scrate::storage::generator::StorageValue<#typ> for #name<#traitinstance> {
type Query = #value_type;
/// Get the storage key.
fn key() -> &'static [u8] {
#prefix.as_bytes()
}
/// Load the value from the provided storage instance.
fn get<S: #scrate::GenericStorage>(storage: &S) -> Self::Query {
storage.get(<Self as #scrate::storage::generator::StorageValue<#typ>>::key())
.#option_simple_1(|| #fielddefault)
}
/// Take a value from storage, removing it afterwards.
fn take<S: #scrate::GenericStorage>(storage: &S) -> Self::Query {
storage.take(<Self as #scrate::storage::generator::StorageValue<#typ>>::key())
.#option_simple_1(|| #fielddefault)
}
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(f: F, storage: &S) -> R {
let mut val = <Self as #scrate::storage::generator::StorageValue<#typ>>::get(storage);
let ret = f(&mut val);
#mutate_impl ;
ret
}
}
}
}
pub fn map(self, kty: &syn::Type) -> TokenStream2 {
let Self {
scrate,
visibility,
traitinstance,
traittype,
type_infos,
fielddefault,
prefix,
name,
} = self;
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
let option_simple_1 = option_unwrap(is_option);
let mutate_impl = if !is_option {
quote!{
<Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage)
}
} else {
quote!{
match val {
Some(ref val) => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage),
None => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::remove(key, storage),
}
}
};
// generator for map
quote!{
#visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>);
impl<#traitinstance: #traittype> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance> {
type Query = #value_type;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8] {
#prefix.as_bytes()
}
/// Get the storage key used to fetch a value corresponding to a specific key.
fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec<u8> {
let mut key = #prefix.as_bytes().to_vec();
#scrate::codec::Encode::encode_to(x, &mut key);
key
}
/// Load the value associated with the given key from the map.
fn get<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query {
let key = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(key);
storage.get(&key[..]).#option_simple_1(|| #fielddefault)
}
/// Take the value, reading and removing it.
fn take<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query {
let key = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(key);
storage.take(&key[..]).#option_simple_1(|| #fielddefault)
}
/// Mutate the value under a key
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(key: &#kty, f: F, storage: &S) -> R {
let mut val = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::get(key, storage);
let ret = f(&mut val);
#mutate_impl ;
ret
}
}
}
}
pub fn linked_map(self, kty: &syn::Type) -> TokenStream2 {
let Self {
scrate,
visibility,
traitinstance,
traittype,
type_infos,
fielddefault,
prefix,
name,
} = self;
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
let option_simple_1 = option_unwrap(is_option);
// make sure to use different prefix for head and elements.
let head_key = format!("head of {}", prefix);
let prefix = format!("{}", prefix);
let name_lowercase = name.to_string().to_lowercase();
let key_for = syn::Ident::new(&format!("key_for_{}", name_lowercase), name.span());
let internal_module = syn::Ident::new(&format!("__internal_do_not_use_{}", name_lowercase), name.span());
let linkage = syn::Ident::new(&format!("Linkage{}", name), name.span());
let borrowing_linkage = syn::Ident::new(&format!("Borrowing{}", linkage), name.span());
let enumerator = syn::Ident::new(&format!("Enumerator{}", name), name.span());
let put_or_insert = quote! {
match linkage {
Some(linkage) => storage.put(key_for, &(val, linkage)),
None => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage),
}
};
let mutate_impl = if !type_infos.is_option {
put_or_insert
} else {
quote! {
match val {
Some(ref val) => #put_or_insert,
None => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::remove(key, storage),
}
}
};
// generator for linked map
quote! {
mod #internal_module {
use super::*;
#[derive(Default, parity_codec_derive::Encode, parity_codec_derive::Decode)]
pub struct #linkage {
/// Previous element key in storage (None for the first element)
previous: Option<#kty>,
/// Next element key in storage (None for the last element)
next: Option<#kty>,
}
/// A helper struct to avoid unnecessary key cloning.
///
/// NOTE It has to have exact same parity-codec encoding as #linkage!
#[derive(parity_codec_derive::Encode)]
struct #borrowing_linkage<'a> {
previous: Option<&'a #kty>,
next: Option<&'a #kty>,
}
impl #linkage {
/// Update linkage when this element is removed.
///
/// Takes care of updating previous and next elements points
/// as well as updates head if the element is first or last.
pub fn remove<S: #scrate::GenericStorage>(
self,
storage: &S,
) {
let next_key = self.next.as_ref().map(|x| #key_for(x));
let prev_key = self.previous.as_ref().map(|x| #key_for(x));
if let Some(prev_key) = prev_key {
// Retrieve previous element and update `next`
let mut res = Self::read(storage, &*prev_key)
.expect("Linkage is updated in case entry is removed; it always points to existing keys; qed");
res.1.next = self.next;
storage.put(&*prev_key, &res);
} else {
// we were first so let's update the head
Self::write_head(storage, self.next.as_ref());
}
if let Some(next_key) = next_key {
// Update previous of next element
let mut res = Self::read(storage, &*next_key)
.expect("Linkage is updated in case entry is removed; it always points to existing keys; qed");
res.1.previous = self.previous;
storage.put(&*next_key, &res);
}
}
/// Read the contained data and it's linkage.
pub fn read<S: #scrate::GenericStorage>(storage: &S, key: &[u8]) -> Option<(#value_type, #linkage)> {
storage.get(key)
}
/// Generate linkage for newly inserted element.
///
/// Takes care of updating head and previous head's pointer.
pub fn insert_new_head<S: #scrate::GenericStorage>(
storage: &S,
key: &#kty,
) -> Self {
if let Some(head) = Self::read_head(storage) {
// update previous head predecessor
{
let head_key = #key_for(&head);
let (data, linkage) = Self::read(storage, &*head_key).expect(r#"
head is set when first element is inserted and unset when last element is removed;
if head is Some then it points to existing key; qed
"#);
storage.put(&*head_key, &(data, #borrowing_linkage {
next: linkage.next.as_ref(),
previous: Some(key),
}));
}
// update to current head
Self::write_head(storage, Some(key));
// return linkage with pointer to previous head
let mut linkage = Self::default();
linkage.next = Some(head);
linkage
} else {
// we are first - update the head and produce empty linkage
Self::write_head(storage, Some(key));
Self::default()
}
}
/// Read current head pointer.
pub fn read_head<S: #scrate::GenericStorage>(storage: &S) -> Option<#kty> {
storage.get(#head_key.as_bytes())
}
/// Overwrite current head pointer.
///
/// If `None` is given head is removed from storage.
fn write_head<S: #scrate::GenericStorage>(storage: &S, head: Option<&#kty>) {
match head {
Some(head) => storage.put(#head_key.as_bytes(), head),
None => storage.kill(#head_key.as_bytes()),
}
}
}
pub struct #enumerator<'a, S> {
pub storage: &'a S,
pub next: Option<#kty>,
}
impl<'a, S: #scrate::GenericStorage> Iterator for #enumerator<'a, S> {
type Item = (#kty, #typ);
fn next(&mut self) -> Option<Self::Item> {
let next = self.next.take()?;
let key_for = #key_for(&next);
let (val, linkage) = #linkage::read(self.storage, &*key_for)
.expect("previous/next only contain existing entires; we enumerate using next; entry exists; qed");
self.next = linkage.next;
Some((next, val))
}
}
}
fn #key_for(key: &#kty) -> #scrate::rstd::vec::Vec<u8> {
let mut key_for = #prefix.as_bytes().to_vec();
#scrate::codec::Encode::encode_to(&key, &mut key_for);
key_for
}
#visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>);
impl<#traitinstance: #traittype> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance> {
type Query = #value_type;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8] {
#prefix.as_bytes()
}
/// Get the storage key used to fetch a value corresponding to a specific key.
fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec<u8> {
#key_for(x)
}
/// Load the value associated with the given key from the map.
fn get<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query {
storage.get(&*#key_for(key)).#option_simple_1(|| #fielddefault)
}
/// Take the value, reading and removing it.
fn take<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query {
let res: Option<(#value_type, self::#internal_module::#linkage)> = storage.take(&*#key_for(key));
match res {
Some((data, linkage)) => {
linkage.remove(storage);
data
},
None => #fielddefault
}
}
/// Remove the value under a key.
fn remove<S: #scrate::GenericStorage>(key: &#kty, storage: &S) {
<Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::take(key, storage);
}
/// Store a value to be associated with the given key from the map.
fn insert<S: #scrate::GenericStorage>(key: &#kty, val: &#typ, storage: &S) {
let key_for = &*#key_for(key);
let linkage = match self::#internal_module::#linkage::read(storage, key_for) {
// overwrite but reuse existing linkage
Some((_data, linkage)) => linkage,
// create new linkage
None => self::#internal_module::#linkage::insert_new_head(storage, key),
};
storage.put(key_for, &(*val, linkage))
}
/// Mutate the value under a key
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(key: &#kty, f: F, storage: &S) -> R {
let key_for = &*#key_for(key);
let (mut val, linkage) = self::#internal_module::#linkage::read(storage, key_for)
.map(|(data, linkage)| (data, Some(linkage)))
.#option_simple_1(|| (#fielddefault, None));
let ret = f(&mut val);
#mutate_impl ;
ret
}
}
impl<#traitinstance: #traittype> #scrate::storage::generator::EnumerableStorageMap<#kty, #typ> for #name<#traitinstance> {
fn head<S: #scrate::GenericStorage>(storage: &S) -> Option<#kty> {
self::#internal_module::#linkage::read_head(storage)
}
fn enumerate<'a, S: #scrate::GenericStorage>(storage: &'a S) -> #scrate::storage::generator::Box<dyn Iterator<Item = (#kty, #typ)> + 'a> {
#scrate::storage::generator::Box::new(self::#internal_module::#enumerator {
next: self::#internal_module::#linkage::read_head(storage),
storage,
})
}
}
}
}
}
@@ -24,6 +24,8 @@ use srml_support_procedural_tools::{ToTokens, Parse, custom_keyword, custom_keyw
use syn::{Ident, Token};
use syn::token::CustomKeyword;
mod impls;
pub mod transformation;
/// Parsing usage only
@@ -116,6 +118,7 @@ struct DeclStorageBuild {
#[derive(Parse, ToTokens, Debug)]
enum DeclStorageType {
Map(DeclStorageMap),
LinkedMap(DeclStorageLinkedMap),
Simple(syn::Type),
}
@@ -127,6 +130,14 @@ struct DeclStorageMap {
pub value: syn::Type,
}
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageLinkedMap {
pub map_keyword: ext::CustomToken<LinkedMapKeyword>,
pub key: syn::Type,
pub ass_keyword: Token![=>],
pub value: syn::Type,
}
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageDefault {
pub equal_token: Token![=],
@@ -141,3 +152,4 @@ custom_keyword_impl!(DeclStorageBuild, "build", "storage build config");
custom_keyword_impl!(AddExtraGenesis, "add_extra_genesis", "storage extra genesis");
custom_keyword_impl!(DeclStorageGetter, "get", "storage getter");
custom_keyword!(MapKeyword, "map", "map as keyword");
custom_keyword!(LinkedMapKeyword, "linked_map", "linked_map as keyword");
@@ -188,15 +188,15 @@ fn decl_store_extra_genesis(
let ident = &getter.getfn.content;
quote!( #ident )
};
if type_infos.is_simple && ext::has_parametric_type(type_infos.full_type, traitinstance) {
if type_infos.kind.is_simple() && ext::has_parametric_type(type_infos.value_type, traitinstance) {
is_trait_needed = true;
has_trait_field = true;
}
for t in ext::get_non_bound_serde_derive_types(type_infos.full_type, &traitinstance).into_iter() {
for t in ext::get_non_bound_serde_derive_types(type_infos.value_type, &traitinstance).into_iter() {
serde_complete_bound.insert(t);
}
if let Some(kt) = type_infos.map_key {
for t in ext::get_non_bound_serde_derive_types(kt, &traitinstance).into_iter() {
if let DeclStorageTypeInfosKind::Map { key_type, .. } = type_infos.kind {
for t in ext::get_non_bound_serde_derive_types(key_type, &traitinstance).into_iter() {
serde_complete_bound.insert(t);
}
}
@@ -210,8 +210,7 @@ fn decl_store_extra_genesis(
} else {
quote!( #d )
}).unwrap_or_else(|| quote!( Default::default() ));
config_field_default.extend(quote!( #ident: #fielddefault, ));
config_field_default.extend(quote!( #ident: #fielddefault, ));
} else {
opt_build = build.as_ref().map(|b| &b.expr.content).map(|b| quote!( #b ));
}
@@ -219,25 +218,39 @@ fn decl_store_extra_genesis(
let typ = type_infos.typ;
if let Some(builder) = opt_build {
is_trait_needed = true;
if type_infos.is_simple {
builders.extend(quote!{{
use #scrate::codec::Encode;
let v = (#builder)(&self);
r.insert(Self::hash(
<#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>>::key()
).to_vec(), v.encode());
}});
} else {
let kty = type_infos.map_key.clone().expect("is not simple; qed");
builders.extend(quote!{{
use #scrate::codec::Encode;
let data = (#builder)(&self);
for (k, v) in data.into_iter() {
let key = <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(&k);
r.insert(Self::hash(&key[..]).to_vec(), v.encode());
}
}});
}
let error_message = format!(
"Genesis parameters encoding of {} does not match the expected type ({:?}).",
name,
type_infos.value_type,
);
builders.extend(match type_infos.kind {
DeclStorageTypeInfosKind::Simple => {
quote!{{
use #scrate::rstd::{cell::RefCell, marker::PhantomData};
use #scrate::codec::{Encode, Decode};
let storage = (RefCell::new(&mut r), PhantomData::<Self>::default());
let v = (#builder)(&self);
let v = Encode::using_encoded(&v, |mut v| Decode::decode(&mut v))
.expect(#error_message);
<#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>>::put(&v, &storage);
}}
},
DeclStorageTypeInfosKind::Map { key_type, .. } => {
quote!{{
use #scrate::rstd::{cell::RefCell, marker::PhantomData};
use #scrate::codec::{Encode, Decode};
let storage = (RefCell::new(&mut r), PhantomData::<Self>::default());
let data = (#builder)(&self);
for (k, v) in data.into_iter() {
let v = Encode::using_encoded(&v, |mut v| Decode::decode(&mut v))
.expect(#error_message);
<#name<#traitinstance> as #scrate::storage::generator::StorageMap<#key_type, #typ>>::insert(&k, &v, &storage);
}
}}
},
});
}
}
@@ -367,9 +380,9 @@ fn decl_store_extra_genesis(
#[cfg(feature = "std")]
impl#fparam #scrate::runtime_primitives::BuildStorage for GenesisConfig#sparam {
fn build_storage(self) -> ::std::result::Result<(#scrate::runtime_primitives::StorageMap, #scrate::runtime_primitives::ChildrenStorageMap), String> {
let mut r: #scrate::runtime_primitives::StorageMap = Default::default();
let mut c: #scrate::runtime_primitives::ChildrenStorageMap = Default::default();
fn build_storage(self) -> ::std::result::Result<(#scrate::runtime_primitives::StorageOverlay, #scrate::runtime_primitives::ChildrenStorageOverlay), String> {
let mut r: #scrate::runtime_primitives::StorageOverlay = Default::default();
let mut c: #scrate::runtime_primitives::ChildrenStorageOverlay = Default::default();
#builders
@@ -403,128 +416,29 @@ fn decl_storage_items(
} = sline;
let type_infos = get_type_infos(storage_type);
let gettype = type_infos.full_type;
let fielddefault = default_value.inner.as_ref().map(|d| &d.expr).map(|d| quote!( #d ))
.unwrap_or_else(|| quote!{ Default::default() });
let typ = type_infos.typ;
let option_simple_1 = if !type_infos.is_option {
// raw type case
quote!( unwrap_or_else )
} else {
// Option<> type case
quote!( or_else )
let kind = type_infos.kind.clone();
let i = impls::Impls {
scrate,
visibility,
traitinstance,
traittype,
type_infos,
fielddefault: default_value.inner.as_ref().map(|d| &d.expr).map(|d| quote!( #d ))
.unwrap_or_else(|| quote!{ Default::default() }),
prefix: format!("{} {}", cratename, name),
name,
};
let implementation = if type_infos.is_simple {
let mutate_impl = if !type_infos.is_option {
quote!{
<Self as #scrate::storage::generator::StorageValue<#typ>>::put(&val, storage)
}
} else {
quote!{
match val {
Some(ref val) => <Self as #scrate::storage::generator::StorageValue<#typ>>::put(&val, storage),
None => <Self as #scrate::storage::generator::StorageValue<#typ>>::kill(storage),
}
}
};
let key_string = cratename.to_string() + " " + &name.to_string();
// generator for value
quote!{
#visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>);
impl<#traitinstance: #traittype> #scrate::storage::generator::StorageValue<#typ> for #name<#traitinstance> {
type Query = #gettype;
/// Get the storage key.
fn key() -> &'static [u8] {
#key_string.as_bytes()
}
/// Load the value from the provided storage instance.
fn get<S: #scrate::GenericStorage>(storage: &S) -> Self::Query {
storage.get(<#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>>::key())
.#option_simple_1(|| #fielddefault)
}
/// Take a value from storage, removing it afterwards.
fn take<S: #scrate::GenericStorage>(storage: &S) -> Self::Query {
storage.take(<#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>>::key())
.#option_simple_1(|| #fielddefault)
}
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(f: F, storage: &S) -> R {
let mut val = <Self as #scrate::storage::generator::StorageValue<#typ>>::get(storage);
let ret = f(&mut val);
#mutate_impl ;
ret
}
}
}
} else {
let kty = type_infos.map_key.expect("is not simple; qed");
let mutate_impl = if !type_infos.is_option {
quote!{
<Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage)
}
} else {
quote!{
match val {
Some(ref val) => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage),
None => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::remove(key, storage),
}
}
};
let prefix_string = cratename.to_string() + " " + &name.to_string();
// generator for map
quote!{
#visibility struct #name<#traitinstance: #traittype>(#scrate::storage::generator::PhantomData<#traitinstance>);
impl<#traitinstance: #traittype> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance> {
type Query = #gettype;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8] {
#prefix_string.as_bytes()
}
/// Get the storage key used to fetch a value corresponding to a specific key.
fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec<u8> {
let mut key = <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#kty, #typ>>::prefix().to_vec();
#scrate::codec::Encode::encode_to(x, &mut key);
key
}
/// Load the value associated with the given key from the map.
fn get<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query {
let key = <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(key);
storage.get(&key[..]).#option_simple_1(|| #fielddefault)
}
/// Take the value, reading and removing it.
fn take<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query {
let key = <#name<#traitinstance> as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(key);
storage.take(&key[..]).#option_simple_1(|| #fielddefault)
}
/// Mutate the value under a key
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(key: &#kty, f: F, storage: &S) -> R {
let mut val = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::take(key, storage);
let ret = f(&mut val);
#mutate_impl ;
ret
}
}
}
let implementation = match kind {
DeclStorageTypeInfosKind::Simple => {
i.simple_value()
},
DeclStorageTypeInfosKind::Map { key_type, is_linked: false } => {
i.map(key_type)
},
DeclStorageTypeInfosKind::Map { key_type, is_linked: true } => {
i.linked_map(key_type)
},
};
impls.extend(implementation)
}
@@ -571,21 +485,22 @@ fn impl_store_fns(
let get_fn = &getter.getfn.content;
let type_infos = get_type_infos(storage_type);
let gettype = type_infos.full_type;
let value_type = type_infos.value_type;
let typ = type_infos.typ;
let item = if type_infos.is_simple {
quote!{
pub fn #get_fn() -> #gettype {
<#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage)
let item = match type_infos.kind {
DeclStorageTypeInfosKind::Simple => {
quote!{
pub fn #get_fn() -> #value_type {
<#name<#traitinstance> as #scrate::storage::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage)
}
}
}
} else {
let kty = type_infos.map_key.expect("is not simple; qed");
// map
quote!{
pub fn #get_fn<K: #scrate::storage::generator::Borrow<#kty>>(key: K) -> #gettype {
<#name<#traitinstance> as #scrate::storage::generator::StorageMap<#kty, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage)
},
DeclStorageTypeInfosKind::Map { key_type, .. } => {
quote!{
pub fn #get_fn<K: #scrate::storage::generator::Borrow<#key_type>>(key: K) -> #value_type {
<#name<#traitinstance> as #scrate::storage::generator::StorageMap<#key_type, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage)
}
}
}
};
@@ -614,26 +529,27 @@ fn store_functions_to_metadata (
} = sline;
let type_infos = get_type_infos(storage_type);
let gettype = type_infos.full_type;
let value_type = type_infos.value_type;
let typ = type_infos.typ;
let stype = if type_infos.is_simple {
let styp = clean_type_string(&typ.to_string());
quote!{
#scrate::storage::generator::StorageFunctionType::Plain(
#scrate::storage::generator::DecodeDifferent::Encode(#styp),
)
}
} else {
let kty = type_infos.map_key.expect("is not simple; qed");
let kty = clean_type_string(&quote!(#kty).to_string());
let styp = clean_type_string(&typ.to_string());
quote!{
#scrate::storage::generator::StorageFunctionType::Map {
key: #scrate::storage::generator::DecodeDifferent::Encode(#kty),
value: #scrate::storage::generator::DecodeDifferent::Encode(#styp),
let styp = clean_type_string(&typ.to_string());
let stype = match type_infos.kind {
DeclStorageTypeInfosKind::Simple => {
quote!{
#scrate::storage::generator::StorageFunctionType::Plain(
#scrate::storage::generator::DecodeDifferent::Encode(#styp),
)
}
}
},
DeclStorageTypeInfosKind::Map { key_type, .. } => {
let kty = clean_type_string(&quote!(#key_type).to_string());
quote!{
#scrate::storage::generator::StorageFunctionType::Map {
key: #scrate::storage::generator::DecodeDifferent::Encode(#kty),
value: #scrate::storage::generator::DecodeDifferent::Encode(#styp),
}
}
},
};
let modifier = if type_infos.is_option {
quote!{
@@ -688,8 +604,8 @@ fn store_functions_to_metadata (
fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> {
use #scrate::codec::Encode;
#cache_name.get_or_init(|| {
let def_val: #gettype = #default;
<#gettype as Encode>::encode(&def_val)
let def_val: #value_type = #default;
<#value_type as Encode>::encode(&def_val)
}).clone()
}
}
@@ -697,8 +613,8 @@ fn store_functions_to_metadata (
impl<#traitinstance: #traittype> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance> {
fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> {
use #scrate::codec::Encode;
let def_val: #gettype = #default;
<#gettype as Encode>::encode(&def_val)
let def_val: #value_type = #default;
<#value_type as Encode>::encode(&def_val)
}
}
};
@@ -714,26 +630,54 @@ fn store_functions_to_metadata (
}
struct DeclStorageTypeInfos<'a> {
pub is_simple: bool,
pub full_type: &'a syn::Type,
#[derive(Debug, Clone)]
pub(crate) struct DeclStorageTypeInfos<'a> {
pub is_option: bool,
pub typ: TokenStream2,
pub map_key: Option<&'a syn::Type>,
pub value_type: &'a syn::Type,
kind: DeclStorageTypeInfosKind<'a>,
}
#[derive(Debug, Clone)]
enum DeclStorageTypeInfosKind<'a> {
Simple,
Map {
key_type: &'a syn::Type,
is_linked: bool,
},
}
impl<'a> DeclStorageTypeInfosKind<'a> {
fn is_simple(&self) -> bool {
match *self {
DeclStorageTypeInfosKind::Simple => true,
_ => false,
}
}
}
fn get_type_infos(storage_type: &DeclStorageType) -> DeclStorageTypeInfos {
let (is_simple, extracted_type, map_key, full_type) = match storage_type {
DeclStorageType::Simple(ref st) => (true, ext::extract_type_option(st), None, st),
DeclStorageType::Map(ref map) => (false, ext::extract_type_option(&map.value), Some(&map.key), &map.value),
let (value_type, kind) = match storage_type {
DeclStorageType::Simple(ref st) => (st, DeclStorageTypeInfosKind::Simple),
DeclStorageType::Map(ref map) => (&map.value, DeclStorageTypeInfosKind::Map {
key_type: &map.key,
is_linked: false,
}),
DeclStorageType::LinkedMap(ref map) => (&map.value, DeclStorageTypeInfosKind::Map {
key_type: &map.key,
is_linked: true,
}),
};
let extracted_type = ext::extract_type_option(value_type);
let is_option = extracted_type.is_some();
let typ = extracted_type.unwrap_or(quote!( #full_type ));
let typ = extracted_type.unwrap_or(quote!( #value_type ));
DeclStorageTypeInfos {
is_simple,
full_type,
is_option,
typ,
map_key,
value_type,
kind,
}
}