Fix lazy initialisation bug for parametizability (#2046)

remove lazy and compute prefix at compile time
This commit is contained in:
thiolliere
2019-03-19 18:05:07 +01:00
committed by GitHub
parent fc16677e4d
commit 3501746fa9
11 changed files with 156 additions and 68 deletions
@@ -29,6 +29,10 @@ pub fn option_unwrap(is_option: bool) -> TokenStream2 {
}
}
// prefix for consts in trait Instance
pub(crate) const PREFIX_FOR: &str = "PREFIX_FOR_";
pub(crate) const HEAD_KEY_FOR: &str = "HEAD_KEY_FOR_";
pub(crate) struct Impls<'a, I: Iterator<Item=syn::Meta>> {
pub scrate: &'a TokenStream2,
pub visibility: &'a syn::Visibility,
@@ -83,8 +87,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} = instance_opts;
let final_prefix = if let Some(instance) = instance {
let method_name = syn::Ident::new(&format!("build_prefix_once_for_{}", name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#method_name(#prefix.as_bytes()) }
let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#const_name.as_bytes() }
} else {
quote!{ #prefix.as_bytes() }
};
@@ -165,8 +169,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} = instance_opts;
let final_prefix = if let Some(instance) = instance {
let method_name = syn::Ident::new(&format!("build_prefix_once_for_{}", name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#method_name(#prefix.as_bytes()) }
let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#const_name.as_bytes() }
} else {
quote!{ #prefix.as_bytes() }
};
@@ -240,16 +244,16 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} = instance_opts;
let final_prefix = if let Some(instance) = instance {
let method_name = syn::Ident::new(&format!("build_prefix_once_for_{}", name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#method_name(#prefix.as_bytes()) }
let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#const_name.as_bytes() }
} else {
quote!{ #prefix.as_bytes() }
};
// make sure to use different prefix for head and elements.
let final_head_key = if let Some(instance) = instance {
let method_name = syn::Ident::new(&format!("build_head_key_once_for_{}", name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#method_name(#prefix.as_bytes()) }
let const_name = syn::Ident::new(&format!("{}{}", HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site());
quote!{ #instance::#const_name.as_bytes() }
} else {
let final_head_key = format!("head of {}", prefix);
quote!{ #final_head_key.as_bytes() }
@@ -462,10 +462,12 @@ fn decl_storage_items(
..
} = instance_opts;
let build_prefix = |cratename, name| format!("{} {}", cratename, name);
// Build Instantiable trait
if instance.is_some() {
let mut method_defs = TokenStream2::new();
let mut method_impls = TokenStream2::new();
let mut const_names = vec![];
for sline in storage_lines.inner.iter() {
let DeclStorageLine {
storage_type,
@@ -473,48 +475,36 @@ fn decl_storage_items(
..
} = sline;
let prefix = build_prefix(cratename, name);
let type_infos = get_type_infos(storage_type);
let method_name = syn::Ident::new(&format!("build_prefix_once_for_{}", name.to_string()), proc_macro2::Span::call_site());
method_defs.extend(quote!{ fn #method_name(prefix: &'static [u8]) -> &'static [u8]; });
method_impls.extend(quote!{
fn #method_name(prefix: &'static [u8]) -> &'static [u8] {
static LAZY: #scrate::lazy::Lazy<#scrate::rstd::vec::Vec<u8>> = #scrate::lazy::Lazy::INIT;
LAZY.get(|| {
let mut final_prefix = #scrate::rstd::vec::Vec::new();
final_prefix.extend_from_slice(prefix);
final_prefix.extend_from_slice(Self::INSTANCE_PREFIX.as_bytes());
final_prefix
})
}
});
let const_name = syn::Ident::new(&format!("{}{}", impls::PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site());
let partial_const_value = prefix.clone();
const_names.push((const_name, partial_const_value));
if let DeclStorageTypeInfosKind::Map { is_linked: true, .. } = type_infos.kind {
let method_name = syn::Ident::new(&format!("build_head_key_once_for_{}", name.to_string()), proc_macro2::Span::call_site());
method_defs.extend(quote!{ fn #method_name(prefix: &'static [u8]) -> &'static [u8]; });
method_impls.extend(quote!{
fn #method_name(prefix: &'static [u8]) -> &'static [u8] {
static LAZY: #scrate::lazy::Lazy<#scrate::rstd::vec::Vec<u8>> = #scrate::lazy::Lazy::INIT;
LAZY.get(|| {
let mut final_prefix = #scrate::rstd::vec::Vec::new();
final_prefix.extend_from_slice("head of ".as_bytes());
final_prefix.extend_from_slice(prefix);
final_prefix.extend_from_slice(Self::INSTANCE_PREFIX.as_bytes());
final_prefix
})
}
});
let const_name = syn::Ident::new(&format!("{}{}", impls::HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site());
let partial_const_value = format!("head of {}", prefix);
const_names.push((const_name, partial_const_value));
}
}
impls.extend(quote! {
pub trait #instantiable: 'static {
const INSTANCE_PREFIX: &'static str;
#method_defs
// Declare Instance trait
{
let mut const_impls = TokenStream2::new();
for (const_name, _) in &const_names {
const_impls.extend(quote! {
const #const_name: &'static str;
});
}
});
impls.extend(quote! {
pub trait #instantiable: 'static {
#const_impls
}
});
}
let instances = (0..NUMBER_OF_INSTANCE)
.map(|i| {
@@ -524,15 +514,24 @@ fn decl_storage_items(
})
.chain(default_instance.clone().map(|ident| (String::new(), ident)));
// Impl Instance trait for instances
for (prefix, ident) in instances {
let mut const_impls = TokenStream2::new();
for (const_name, partial_const_value) in &const_names {
let const_value = format!("{}{}", partial_const_value, prefix);
const_impls.extend(quote! {
const #const_name: &'static str = #const_value;
});
}
impls.extend(quote! {
// Those trait are derived because of wrong bounds for generics
#[cfg_attr(feature = "std", derive(Debug))]
#[derive(Clone, Eq, PartialEq, #scrate::codec::Encode, #scrate::codec::Decode)]
pub struct #ident;
impl #instantiable for #ident {
const INSTANCE_PREFIX: &'static str = #prefix;
#method_impls
#const_impls
}
});
}
@@ -563,7 +562,7 @@ fn decl_storage_items(
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),
prefix: build_prefix(cratename, name),
name,
attrs,
};