Skip to content

Commit

Permalink
Include default values in storage metadata (paritytech#1264)
Browse files Browse the repository at this point in the history
* Add a 'default' field to metadata. It contains code to generate the
default value.

* wasm update

* Make 'default' field an `Option`

* Boxed fn is not static, that won't be fine

* static fn won't do it to as it cannot get T param, will try fat trait

* Fat pointer over phantom data compatible with static instantiation

* DecodeDifferent is cool, using it for decoding.

* using once cell to do what would require copying lazy_static internals.

* Remove cache when no_std (non compatible deps)

* wasm bins update

* Fuse tooling struct and enum derive.
  • Loading branch information
cheme authored and gavofyork committed Dec 20, 2018
1 parent 2939dc8 commit fe193bd
Show file tree
Hide file tree
Showing 15 changed files with 300 additions and 85 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions core/test-runtime/wasm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
7 changes: 7 additions & 0 deletions node/runtime/wasm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
54 changes: 50 additions & 4 deletions srml/metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ impl<B, O> serde::Serialize for DecodeDifferent<B, O>
O: serde::Serialize + 'static,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
where
S: serde::Serializer,
{
match self {
DecodeDifferent::Encode(b) => b.serialize(serializer),
Expand Down Expand Up @@ -187,8 +187,8 @@ impl<E: Encode + ::std::fmt::Debug> std::fmt::Debug for FnEncode<E> {
#[cfg(feature = "std")]
impl<E: Encode + serde::Serialize> serde::Serialize for FnEncode<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
where
S: serde::Serializer,
{
self.0().serialize(serializer)
}
Expand Down Expand Up @@ -229,9 +229,55 @@ pub struct StorageFunctionMetadata {
pub name: DecodeDifferentStr,
pub modifier: StorageFunctionModifier,
pub ty: StorageFunctionType,
pub default: ByteGetter,
pub documentation: DecodeDifferentArray<&'static str, StringBuf>,
}

/// A technical trait to store lazy initiated vec value as static dyn pointer.
pub trait DefaultByte {
fn default_byte(&self) -> Vec<u8>;
}

/// Wrapper over dyn pointer for accessing a cached once byet value.
#[derive(Clone)]
pub struct DefaultByteGetter(pub &'static dyn DefaultByte);

/// Decode different for static lazy initiated byte value.
pub type ByteGetter = DecodeDifferent<DefaultByteGetter, Vec<u8>>;

impl Encode for DefaultByteGetter {
fn encode_to<W: Output>(&self, dest: &mut W) {
self.0.default_byte().encode_to(dest)
}
}

impl PartialEq<DefaultByteGetter> for DefaultByteGetter {
fn eq(&self, other: &DefaultByteGetter) -> bool {
let left = self.0.default_byte();
let right = other.0.default_byte();
left.eq(&right)
}
}

impl Eq for DefaultByteGetter { }

#[cfg(feature = "std")]
impl serde::Serialize for DefaultByteGetter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.default_byte().serialize(serializer)
}
}

#[cfg(feature = "std")]
impl std::fmt::Debug for DefaultByteGetter {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.0.default_byte().fmt(f)
}
}

/// A storage function type.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
Expand Down
2 changes: 2 additions & 0 deletions srml/support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ sr-io = { path = "../../core/sr-io", default-features = false }
sr-primitives = { path = "../../core/sr-primitives", default-features = false }
srml-support-procedural = { path = "./procedural" }
mashup = "0.1.7"
once_cell = { version = "0.1.6", default-features = false, optional = true }

[dev-dependencies]
pretty_assertions = "0.5.1"
Expand All @@ -23,6 +24,7 @@ parity-codec-derive = { version = "2.1" }
default = ["std"]
std = [
"hex-literal",
"once_cell",
"serde/std",
"serde_derive",
"sr-io/std",
Expand Down
26 changes: 13 additions & 13 deletions srml/support/procedural/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use syn::token::CustomKeyword;
pub mod transformation;

/// Parsing usage only
#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct StorageDefinition {
pub hidden_crate: Option<SpecificHiddenCrate>,
pub visibility: syn::Visibility,
Expand All @@ -44,30 +44,30 @@ struct StorageDefinition {
}


#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct SpecificHiddenCrate {
pub keyword: ext::CustomToken<SpecificHiddenCrate>,
pub ident: ext::Parens<Ident>,
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct AddExtraGenesis {
pub extragenesis_keyword: ext::CustomToken<AddExtraGenesis>,
pub content: ext::Braces<AddExtraGenesisContent>,
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct AddExtraGenesisContent {
pub lines: ext::Punctuated<AddExtraGenesisLineEnum, Token![;]>,
}

#[derive(ParseEnum, ToTokensEnum, Debug)]
#[derive(Parse, ToTokens, Debug)]
enum AddExtraGenesisLineEnum {
AddExtraGenesisLine(AddExtraGenesisLine),
AddExtraGenesisBuild(DeclStorageBuild),
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct AddExtraGenesisLine {
pub attrs: ext::OuterAttributes,
pub config_keyword: ext::CustomToken<ConfigKeyword>,
Expand All @@ -78,7 +78,7 @@ struct AddExtraGenesisLine {
pub default_value: ext::Seq<DeclStorageDefault>,
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageLine {
// attrs (main use case is doc)
pub attrs: ext::OuterAttributes,
Expand All @@ -96,39 +96,39 @@ struct DeclStorageLine {
}


#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageGetter {
pub getter_keyword: ext::CustomToken<DeclStorageGetter>,
pub getfn: ext::Parens<Ident>,
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageConfig {
pub config_keyword: ext::CustomToken<DeclStorageConfig>,
pub expr: ext::Parens<Option<syn::Ident>>,
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageBuild {
pub build_keyword: ext::CustomToken<DeclStorageBuild>,
pub expr: ext::Parens<syn::Expr>,
}

#[derive(ParseEnum, ToTokensEnum, Debug)]
#[derive(Parse, ToTokens, Debug)]
enum DeclStorageType {
Map(DeclStorageMap),
Simple(syn::Type),
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageMap {
pub map_keyword: ext::CustomToken<MapKeyword>,
pub key: syn::Type,
pub ass_keyword: Token![=>],
pub value: syn::Type,
}

#[derive(ParseStruct, ToTokensStruct, Debug)]
#[derive(Parse, ToTokens, Debug)]
struct DeclStorageDefault {
pub equal_token: Token![=],
pub expr: syn::Expr,
Expand Down
64 changes: 54 additions & 10 deletions srml/support/procedural/src/storage/transformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,21 +110,24 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
&traitinstance,
&storage_lines,
);
let store_functions_to_metadata = store_functions_to_metadata(
let (store_default_struct, store_functions_to_metadata) = store_functions_to_metadata(
&scrate,
&traitinstance,
&traittype,
&storage_lines,
);
let cratename_string = cratename.to_string();
let expanded = quote! {
#scrate_decl
#decl_storage_items
#visibility trait #storetype {
#decl_store_items
#decl_store_items
}
#store_default_struct
impl<#traitinstance: #traittype> #storetype for #module_ident<#traitinstance> {
#impl_store_items
}
impl<#traitinstance: #traittype> #module_ident<#traitinstance> {
impl<#traitinstance: 'static + #traittype> #module_ident<#traitinstance> {
#impl_store_fns
pub fn store_metadata() -> #scrate::storage::generator::StorageMetadata {
#scrate::storage::generator::StorageMetadata {
Expand Down Expand Up @@ -557,15 +560,19 @@ fn impl_store_fns(

fn store_functions_to_metadata (
scrate: &TokenStream2,
traitinstance: &Ident,
traittype: &syn::TypeParamBound,
storage_lines: &ext::Punctuated<DeclStorageLine, Token![;]>,
) -> TokenStream2 {
) -> (TokenStream2, TokenStream2) {

let mut items = TokenStream2::new();
let mut default_getter_struct_def = TokenStream2::new();
for sline in storage_lines.inner.iter() {
let DeclStorageLine {
attrs,
name,
storage_type,
default_value,
..
} = sline;

Expand Down Expand Up @@ -603,6 +610,11 @@ fn store_functions_to_metadata (
#scrate::storage::generator::StorageFunctionModifier::Optional
}
};
let default = default_value.inner.get(0).as_ref().map(|d| &d.expr)
.map(|d| {
quote!( #d )
})
.unwrap_or_else(|| quote!( Default::default() ));
let mut docs = TokenStream2::new();
for attr in attrs.inner.iter().filter_map(|v| v.interpret_meta()) {
if let syn::Meta::NameValue(syn::MetaNameValue{
Expand All @@ -616,20 +628,52 @@ fn store_functions_to_metadata (
}
}
let str_name = name.to_string();
let struct_name = proc_macro2::Ident::new(&("__GetByteStruct".to_string() + &str_name), name.span());
let cache_name = proc_macro2::Ident::new(&("__CacheGetByteStruct".to_string() + &str_name), name.span());
let item = quote! {
#scrate::storage::generator::StorageFunctionMetadata {
name: #scrate::storage::generator::DecodeDifferent::Encode(#str_name),
modifier: #modifier,
ty: #stype,
default: #scrate::storage::generator::DecodeDifferent::Encode(
#scrate::storage::generator::DefaultByteGetter(
&#struct_name::<#traitinstance>(#scrate::rstd::marker::PhantomData)
)
),
documentation: #scrate::storage::generator::DecodeDifferent::Encode(&[ #docs ]),
},
};
items.extend(item);
let def_get = quote! {
pub struct #struct_name<#traitinstance>(pub #scrate::rstd::marker::PhantomData<#traitinstance>);
#[cfg(feature = "std")]
static #cache_name: #scrate::once_cell::sync::OnceCell<Vec<u8>> = #scrate::once_cell::sync::OnceCell::INIT;
#[cfg(feature = "std")]
impl<#traitinstance: #traittype> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance> {
fn default_byte(&self) -> Vec<u8> {
use #scrate::codec::Encode;
#cache_name.get_or_init(|| {
let def_val: #gettype = #default;
<#gettype as Encode>::encode(&def_val)
}).clone()
}
}
#[cfg(not(feature = "std"))]
impl<#traitinstance: #traittype> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance> {
fn default_byte(&self) -> Vec<u8> {
use #scrate::codec::Encode;
let def_val: #gettype = #default;
<#gettype as Encode>::encode(&def_val)
}
}
};
default_getter_struct_def.extend(def_get);
}

quote!{
#scrate::storage::generator::DecodeDifferent::Encode(&[
#items
])
}
(default_getter_struct_def, quote!{
{
#scrate::storage::generator::DecodeDifferent::Encode(&[
#items
])
}
})
}
Loading

0 comments on commit fe193bd

Please sign in to comment.