diff --git a/substrate/srml/support/procedural/src/storage/transformation.rs b/substrate/srml/support/procedural/src/storage/transformation.rs index 104c5c830c..41a24ccfef 100644 --- a/substrate/srml/support/procedural/src/storage/transformation.rs +++ b/substrate/srml/support/procedural/src/storage/transformation.rs @@ -154,6 +154,7 @@ fn decl_store_extra_genesis( let mut is_trait_needed = false; let mut has_trait_field = false; + let mut serde_complete_bound = std::collections::HashSet::new(); let mut config_field = TokenStream2::new(); let mut config_field_default = TokenStream2::new(); let mut builders = TokenStream2::new(); @@ -184,6 +185,14 @@ fn decl_store_extra_genesis( 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() { + 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() { + serde_complete_bound.insert(t); + } + } let storage_type = type_infos.typ.clone(); config_field.extend(quote!( pub #ident: #storage_type, )); opt_build = Some(build.as_ref().map(|b| &b.expr.content).map(|b|quote!( #b )) @@ -246,6 +255,11 @@ fn decl_store_extra_genesis( is_trait_needed = true; has_trait_field = true; } + + for t in ext::get_non_bound_serde_derive_types(extra_type, &traitinstance).into_iter() { + serde_complete_bound.insert(t); + } + let extrafield = &extra_field.content; genesis_extrafields.extend(quote!{ #attrs pub #extrafield: #extra_type, @@ -268,6 +282,25 @@ fn decl_store_extra_genesis( } } + + let serde_bug_bound = if serde_complete_bound.len() > 0 { + + let mut b_ser = String::new(); + let mut b_dser = String::new(); + for bound in serde_complete_bound { + let stype = quote!(#bound); + b_ser += &(stype.to_string() + " : " + &scrate.to_string() + "::serde::Serialize, "); + b_dser += &(stype.to_string() + " : " + &scrate.to_string() + "::serde::de::DeserializeOwned, "); + } + + quote! { + #[serde(bound(serialize = #b_ser))] + #[serde(bound(deserialize = #b_dser))] + } + } else { + quote!() + }; + let is_extra_genesis_needed = has_scall || !config_field.is_empty() || !genesis_extrafields.is_empty() @@ -307,6 +340,7 @@ fn decl_store_extra_genesis( #[cfg(feature = "std")] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] + #serde_bug_bound pub struct GenesisConfig#fparam { #ph_field #config_field diff --git a/substrate/srml/support/procedural/tools/src/syn_ext.rs b/substrate/srml/support/procedural/tools/src/syn_ext.rs index 75118c053d..3a93a5c533 100644 --- a/substrate/srml/support/procedural/tools/src/syn_ext.rs +++ b/substrate/srml/support/procedural/tools/src/syn_ext.rs @@ -334,3 +334,57 @@ pub fn has_parametric_type_def(typ: &syn::Type, ident: &Ident, default: bool) -> pub fn has_parametric_type(typ: &syn::Type, ident: &Ident) -> bool { has_parametric_type_def(typ, ident, true) } + +/// Get case where serde does not include bound with serde_derive macros: +/// see https://github.com/serde-rs/serde/issues/1454 +pub fn get_non_bound_serde_derive_types(typ: &syn::Type, t: &syn::Ident) -> Vec { + let mut result = Vec::new(); + get_non_bound_serde_derive_types_inner(typ, t, &mut result); + result +} + +fn get_non_bound_serde_derive_types_inner(typ: &syn::Type, t: &syn::Ident, result: &mut Vec) { + match *typ { + syn::Type::Path(ref path) => { + if heuristic_is_associated_path(&path.path,t) { + result.push(typ.clone()); + } + for p in path.path.segments.iter() { + if let syn::PathArguments::AngleBracketed(ref args) = p.arguments { + for a in args.args.iter() { + if let syn::GenericArgument::Type(ref ty) = a { + get_non_bound_serde_derive_types_inner(ty, t, result) + } + } + } + } + }, + syn::Type::Slice(ref inner) => get_non_bound_serde_derive_types_inner(&inner.elem, t, result), + syn::Type::Array(ref inner) => get_non_bound_serde_derive_types_inner(&inner.elem, t, result), + syn::Type::Ptr(ref inner) => get_non_bound_serde_derive_types_inner(&inner.elem, t, result), + syn::Type::Reference(ref inner) => get_non_bound_serde_derive_types_inner(&inner.elem, t, result), + syn::Type::BareFn(..) => (), + syn::Type::Never(..) => (), + syn::Type::Tuple(ref inner) => for e in inner.elems.iter() { + get_non_bound_serde_derive_types_inner(e, t, result) + }, + syn::Type::TraitObject(..) => (), + syn::Type::ImplTrait(..) => (), + syn::Type::Paren(ref inner) => get_non_bound_serde_derive_types_inner(&inner.elem, t, result), + syn::Type::Group(ref inner) => get_non_bound_serde_derive_types_inner(&inner.elem, t, result), + syn::Type::Infer(..) => (), + syn::Type::Macro(..) => (), + syn::Type::Verbatim(..) => (), + } + +} + +fn heuristic_is_associated_path(path: &syn::Path,t: &syn::Ident) -> bool { + + if let Some(syn::punctuated::Pair::Punctuated(s,_)) = path.segments.first() { + &s.ident == t + } else { + false + } + +} diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index 3708129b2c..ec285590d2 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -20,7 +20,7 @@ #![cfg_attr(not(feature = "std"), feature(alloc))] #[cfg(feature = "std")] -extern crate serde; +pub extern crate serde; #[doc(hidden)] pub extern crate sr_std as rstd;