fix: Complete snowbridge pezpallet rebrand and critical bug fixes
- snowbridge-pezpallet-* → pezsnowbridge-pezpallet-* (201 refs) - pallet/ directories → pezpallet/ (4 locations) - Fixed pezpallet.rs self-include recursion bug - Fixed sc-chain-spec hardcoded crate name in derive macro - Reverted .pezpallet_by_name() to .pallet_by_name() (subxt API) - Added BizinikiwiConfig type alias for zombienet tests - Deleted obsolete session state files Verified: pezsnowbridge-pezpallet-*, pezpallet-staking, pezpallet-staking-async, pezframe-benchmarking-cli all pass cargo check
This commit is contained in:
@@ -0,0 +1,614 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{
|
||||
deprecation::extract_or_return_allow_attrs,
|
||||
pezpallet::{
|
||||
expand::warnings::{weight_constant_warning, weight_witness_warning},
|
||||
parse::{
|
||||
call::{CallVariantDef, CallWeightDef},
|
||||
helper::CallReturnType,
|
||||
},
|
||||
Def,
|
||||
},
|
||||
COUNTER,
|
||||
};
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use proc_macro_warning::Warning;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Expand the weight to final token stream and accumulate warnings.
|
||||
fn expand_weight(
|
||||
prefix: &str,
|
||||
pezframe_support: &syn::Path,
|
||||
dev_mode: bool,
|
||||
weight_warnings: &mut Vec<Warning>,
|
||||
method: &CallVariantDef,
|
||||
weight: &CallWeightDef,
|
||||
) -> TokenStream2 {
|
||||
match weight {
|
||||
CallWeightDef::DevModeDefault => quote::quote!(
|
||||
#pezframe_support::pezpallet_prelude::Weight::zero()
|
||||
),
|
||||
CallWeightDef::Immediate(e) => {
|
||||
weight_constant_warning(e, dev_mode, weight_warnings);
|
||||
weight_witness_warning(method, dev_mode, weight_warnings);
|
||||
|
||||
e.into_token_stream()
|
||||
},
|
||||
CallWeightDef::Inherited(t) => {
|
||||
// Expand `<<T as Config>::WeightInfo>::$prefix$call_name()`.
|
||||
let n = &syn::Ident::new(&format!("{}{}", prefix, method.name), method.name.span());
|
||||
quote!({ < #t > :: #n () })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// * Generate enum call and implement various trait on it.
|
||||
/// * Implement Callable and call_function on `Pezpallet`
|
||||
pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let (span, where_clause, methods, docs) = match def.call.as_ref() {
|
||||
Some(call) => {
|
||||
let span = call.attr_span;
|
||||
let where_clause = call.where_clause.clone();
|
||||
let methods = call.methods.clone();
|
||||
let docs = call.docs.clone();
|
||||
|
||||
(span, where_clause, methods, docs)
|
||||
},
|
||||
None => (def.item.span(), def.config.where_clause.clone(), Vec::new(), Vec::new()),
|
||||
};
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let type_impl_gen = &def.type_impl_generics(span);
|
||||
let type_decl_bounded_gen = &def.type_decl_bounded_generics(span);
|
||||
let type_use_gen = &def.type_use_generics(span);
|
||||
let call_ident = syn::Ident::new("Call", span);
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
|
||||
let fn_name = methods.iter().map(|method| &method.name).collect::<Vec<_>>();
|
||||
let call_index = methods.iter().map(|method| method.call_index).collect::<Vec<_>>();
|
||||
let new_call_variant_fn_name = fn_name
|
||||
.iter()
|
||||
.map(|fn_name| quote::format_ident!("new_call_variant_{}", fn_name))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let new_call_variant_doc = fn_name
|
||||
.iter()
|
||||
.map(|fn_name| format!("Create a call with the variant `{}`.", fn_name))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut call_index_warnings = Vec::new();
|
||||
// Emit a warning for each call that is missing `call_index` when not in dev-mode.
|
||||
for method in &methods {
|
||||
if method.explicit_call_index || def.dev_mode {
|
||||
continue;
|
||||
}
|
||||
|
||||
let warning = Warning::new_deprecated("ImplicitCallIndex")
|
||||
.index(call_index_warnings.len())
|
||||
.old("use implicit call indices")
|
||||
.new("ensure that all calls have a `pezpallet::call_index` attribute or put the pezpallet into `dev` mode")
|
||||
.help_links(&[
|
||||
"https://github.com/pezkuwichain/kurdistan-sdk/issues/39",
|
||||
"https://github.com/pezkuwichain/kurdistan-sdk/issues/36"
|
||||
])
|
||||
.span(method.name.span())
|
||||
.build_or_panic();
|
||||
call_index_warnings.push(warning);
|
||||
}
|
||||
|
||||
let mut fn_weight = Vec::<TokenStream2>::new();
|
||||
let mut weight_warnings = Vec::new();
|
||||
for method in &methods {
|
||||
let w = expand_weight(
|
||||
"",
|
||||
pezframe_support,
|
||||
def.dev_mode,
|
||||
&mut weight_warnings,
|
||||
method,
|
||||
&method.weight,
|
||||
);
|
||||
fn_weight.push(w);
|
||||
}
|
||||
debug_assert_eq!(fn_weight.len(), methods.len());
|
||||
|
||||
let fn_doc = methods.iter().map(|method| &method.docs).collect::<Vec<_>>();
|
||||
|
||||
let args_name = methods
|
||||
.iter()
|
||||
.map(|method| method.args.iter().map(|(_, name, _)| name.clone()).collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let args_name_stripped = methods
|
||||
.iter()
|
||||
.map(|method| {
|
||||
method
|
||||
.args
|
||||
.iter()
|
||||
.map(|(_, name, _)| {
|
||||
syn::Ident::new(name.to_string().trim_start_matches('_'), name.span())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let make_args_name_pattern = |ref_tok| {
|
||||
args_name
|
||||
.iter()
|
||||
.zip(args_name_stripped.iter())
|
||||
.map(|(args_name, args_name_stripped)| {
|
||||
args_name
|
||||
.iter()
|
||||
.zip(args_name_stripped)
|
||||
.map(|(args_name, args_name_stripped)| {
|
||||
if args_name == args_name_stripped {
|
||||
quote::quote!( #ref_tok #args_name )
|
||||
} else {
|
||||
quote::quote!( #args_name_stripped: #ref_tok #args_name )
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
|
||||
let args_name_pattern = make_args_name_pattern(None);
|
||||
let args_name_pattern_ref = make_args_name_pattern(Some(quote::quote!(ref)));
|
||||
|
||||
let args_type = methods
|
||||
.iter()
|
||||
.map(|method| method.args.iter().map(|(_, _, type_)| type_.clone()).collect::<Vec<_>>())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let args_compact_attr = methods.iter().map(|method| {
|
||||
method
|
||||
.args
|
||||
.iter()
|
||||
.map(|(is_compact, _, type_)| {
|
||||
if *is_compact {
|
||||
quote::quote_spanned!(type_.span() => #[codec(compact)] )
|
||||
} else {
|
||||
quote::quote!()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let default_docs =
|
||||
[syn::parse_quote!(r"Contains a variant per dispatchable extrinsic that this pezpallet has.")];
|
||||
let docs = if docs.is_empty() { &default_docs[..] } else { &docs[..] };
|
||||
|
||||
let maybe_compile_error = if def.call.is_none() {
|
||||
quote::quote! {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have #[pezpallet::call] defined, perhaps you should remove `Call` from \
|
||||
construct_runtime?",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
proc_macro2::TokenStream::new()
|
||||
};
|
||||
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
let macro_ident = syn::Ident::new(&format!("__is_call_part_defined_{}", count), span);
|
||||
|
||||
let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" };
|
||||
|
||||
// Wrap all calls inside of storage layers
|
||||
if let Some(call) = def.call.as_ref() {
|
||||
let item_impl =
|
||||
&mut def.item.content.as_mut().expect("Checked by def parser").1[call.index];
|
||||
let syn::Item::Impl(item_impl) = item_impl else {
|
||||
unreachable!("Checked by def parser");
|
||||
};
|
||||
|
||||
item_impl.items.iter_mut().enumerate().for_each(|(i, item)| {
|
||||
if let syn::ImplItem::Fn(method) = item {
|
||||
let return_type =
|
||||
&call.methods.get(i).expect("def should be consistent with item").return_type;
|
||||
|
||||
let (ok_type, err_type) = match return_type {
|
||||
CallReturnType::DispatchResult => (
|
||||
quote::quote!(()),
|
||||
quote::quote!(#pezframe_support::pezpallet_prelude::DispatchError),
|
||||
),
|
||||
CallReturnType::DispatchResultWithPostInfo => (
|
||||
quote::quote!(#pezframe_support::dispatch::PostDispatchInfo),
|
||||
quote::quote!(#pezframe_support::dispatch::DispatchErrorWithPostInfo),
|
||||
),
|
||||
};
|
||||
|
||||
let block = &method.block;
|
||||
method.block = syn::parse_quote! {{
|
||||
// We execute all dispatchable in a new storage layer, allowing them
|
||||
// to return an error at any point, and undoing any storage changes.
|
||||
#pezframe_support::storage::with_storage_layer::<#ok_type, #err_type, _>(
|
||||
|| #block
|
||||
)
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs = methods
|
||||
.iter()
|
||||
.map(|method| {
|
||||
let attrs = extract_or_return_allow_attrs(&method.attrs);
|
||||
quote::quote! {
|
||||
#(#attrs)*
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let cfg_attrs = methods
|
||||
.iter()
|
||||
.map(|method| {
|
||||
let attrs =
|
||||
method.cfg_attrs.iter().map(|attr| attr.to_token_stream()).collect::<Vec<_>>();
|
||||
quote::quote!( #( #attrs )* )
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let feeless_checks = methods.iter().map(|method| &method.feeless_check).collect::<Vec<_>>();
|
||||
let feeless_check =
|
||||
feeless_checks.iter().zip(args_name.iter()).map(|(feeless_check, arg_name)| {
|
||||
if let Some(check) = feeless_check {
|
||||
quote::quote_spanned!(span => #check)
|
||||
} else {
|
||||
quote::quote_spanned!(span => |_origin, #( #arg_name, )*| { false })
|
||||
}
|
||||
});
|
||||
|
||||
let deprecation = match crate::deprecation::get_deprecation_enum(
|
||||
"e::quote! {#pezframe_support},
|
||||
methods.iter().map(|item| (item.call_index as u8, item.attrs.as_ref())),
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
// Implementation of the authorize function for each call
|
||||
// `authorize_fn_pallet_impl` writes the user-defined authorize function as a function
|
||||
// implementation for the pezpallet.
|
||||
// `authorize_impl` is the call to this former function to implement `Authorize` trait.
|
||||
let (authorize_fn_pallet_impl, authorize_impl) = methods
|
||||
.iter()
|
||||
.zip(args_name.iter())
|
||||
.zip(args_type.iter())
|
||||
.zip(cfg_attrs.iter())
|
||||
.map(|(((method, arg_name), arg_type), cfg_attr)| {
|
||||
if let Some(authorize_def) = &method.authorize {
|
||||
let authorize_fn = &authorize_def.expr;
|
||||
let attr_fn_getter = syn::Ident::new(
|
||||
&format!("__macro_inner_authorize_call_for_{}", method.name),
|
||||
authorize_fn.span(),
|
||||
);
|
||||
let source = syn::Ident::new("source", span);
|
||||
|
||||
let authorize_fn_pallet_impl = quote::quote_spanned!(authorize_fn.span() =>
|
||||
// Closure don't have a writable type. So we fix the authorize token stream to
|
||||
// be any implementation of a specific function.
|
||||
// This allows to have good type inference on the closure.
|
||||
//
|
||||
// Then we wrap this into an implementation for `Pezpallet` in order to get access
|
||||
// to `Self` as `Pezpallet` instead of `Call`.
|
||||
#cfg_attr
|
||||
impl<#type_impl_gen> Pezpallet<#type_use_gen> #where_clause {
|
||||
#[doc(hidden)]
|
||||
fn #attr_fn_getter() -> impl Fn(
|
||||
#pezframe_support::pezpallet_prelude::TransactionSource,
|
||||
#( &#arg_type ),*
|
||||
) -> #pezframe_support::pezpallet_prelude::TransactionValidityWithRefund {
|
||||
#authorize_fn
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// `source` is from outside this block, so we can't use the authorize_fn span.
|
||||
let authorize_impl = quote::quote!(
|
||||
{
|
||||
let authorize_fn = Pezpallet::<#type_use_gen>::#attr_fn_getter();
|
||||
let res = authorize_fn(#source, #( #arg_name, )*);
|
||||
|
||||
Some(res)
|
||||
}
|
||||
);
|
||||
|
||||
(authorize_fn_pallet_impl, authorize_impl)
|
||||
} else {
|
||||
(Default::default(), quote::quote!(None))
|
||||
}
|
||||
})
|
||||
.unzip::<_, _, Vec<TokenStream2>, Vec<TokenStream2>>();
|
||||
|
||||
// Implementation of the authorize function weight for each call
|
||||
let mut authorize_fn_weight = Vec::<TokenStream2>::new();
|
||||
for method in &methods {
|
||||
let w = match &method.authorize {
|
||||
Some(authorize_def) => expand_weight(
|
||||
"authorize_",
|
||||
pezframe_support,
|
||||
def.dev_mode,
|
||||
&mut weight_warnings,
|
||||
method,
|
||||
&authorize_def.weight,
|
||||
),
|
||||
// No authorize logic, weight is negligible
|
||||
None => quote::quote!(#pezframe_support::pezpallet_prelude::Weight::zero()),
|
||||
};
|
||||
authorize_fn_weight.push(w);
|
||||
}
|
||||
assert_eq!(authorize_fn_weight.len(), methods.len());
|
||||
|
||||
quote::quote_spanned!(span =>
|
||||
#[doc(hidden)]
|
||||
mod warnings {
|
||||
#(
|
||||
#call_index_warnings
|
||||
)*
|
||||
#(
|
||||
#weight_warnings
|
||||
)*
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_call_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #macro_ident {
|
||||
($pezpallet_name:ident) => {
|
||||
#maybe_compile_error
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #macro_ident as is_call_part_defined;
|
||||
}
|
||||
|
||||
#( #[doc = #docs] )*
|
||||
#[derive(
|
||||
#pezframe_support::RuntimeDebugNoBound,
|
||||
#pezframe_support::CloneNoBound,
|
||||
#pezframe_support::EqNoBound,
|
||||
#pezframe_support::PartialEqNoBound,
|
||||
#pezframe_support::__private::codec::Encode,
|
||||
#pezframe_support::__private::codec::Decode,
|
||||
#pezframe_support::__private::codec::DecodeWithMemTracking,
|
||||
#pezframe_support::__private::scale_info::TypeInfo,
|
||||
)]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum #call_ident<#type_decl_bounded_gen> #where_clause {
|
||||
#[doc(hidden)]
|
||||
#[codec(skip)]
|
||||
__Ignore(
|
||||
::core::marker::PhantomData<(#type_use_gen,)>,
|
||||
#pezframe_support::Never,
|
||||
),
|
||||
#(
|
||||
#cfg_attrs
|
||||
#( #[doc = #fn_doc] )*
|
||||
#[codec(index = #call_index)]
|
||||
#fn_name {
|
||||
#(
|
||||
#[allow(missing_docs)]
|
||||
#args_compact_attr #args_name_stripped: #args_type
|
||||
),*
|
||||
},
|
||||
)*
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #call_ident<#type_use_gen> #where_clause {
|
||||
#(
|
||||
#cfg_attrs
|
||||
#[doc = #new_call_variant_doc]
|
||||
pub fn #new_call_variant_fn_name(
|
||||
#( #args_name_stripped: #args_type ),*
|
||||
) -> Self {
|
||||
Self::#fn_name {
|
||||
#( #args_name_stripped ),*
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::dispatch::GetDispatchInfo
|
||||
for #call_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
fn get_dispatch_info(&self) -> #pezframe_support::dispatch::DispatchInfo {
|
||||
match *self {
|
||||
#(
|
||||
#cfg_attrs
|
||||
Self::#fn_name { #( #args_name_pattern_ref, )* } => {
|
||||
let __pallet_base_weight = #fn_weight;
|
||||
|
||||
let __pallet_weight = <
|
||||
dyn #pezframe_support::dispatch::WeighData<( #( & #args_type, )* )>
|
||||
>::weigh_data(&__pallet_base_weight, ( #( #args_name, )* ));
|
||||
|
||||
let __pallet_class = <
|
||||
dyn #pezframe_support::dispatch::ClassifyDispatch<
|
||||
( #( & #args_type, )* )
|
||||
>
|
||||
>::classify_dispatch(&__pallet_base_weight, ( #( #args_name, )* ));
|
||||
|
||||
let __pallet_pays_fee = <
|
||||
dyn #pezframe_support::dispatch::PaysFee<( #( & #args_type, )* )>
|
||||
>::pays_fee(&__pallet_base_weight, ( #( #args_name, )* ));
|
||||
|
||||
#pezframe_support::dispatch::DispatchInfo {
|
||||
call_weight: __pallet_weight,
|
||||
extension_weight: Default::default(),
|
||||
class: __pallet_class,
|
||||
pays_fee: __pallet_pays_fee,
|
||||
}
|
||||
},
|
||||
)*
|
||||
Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::dispatch::CheckIfFeeless for #call_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
type Origin = #pezframe_system::pezpallet_prelude::OriginFor<T>;
|
||||
#[allow(unused_variables)]
|
||||
fn is_feeless(&self, origin: &Self::Origin) -> bool {
|
||||
match *self {
|
||||
#(
|
||||
#cfg_attrs
|
||||
Self::#fn_name { #( #args_name_pattern_ref, )* } => {
|
||||
let feeless_check = #feeless_check;
|
||||
feeless_check(origin, #( #args_name, )*)
|
||||
},
|
||||
)*
|
||||
Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::traits::GetCallName for #call_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
fn get_call_name(&self) -> &'static str {
|
||||
match *self {
|
||||
#( #cfg_attrs Self::#fn_name { .. } => stringify!(#fn_name), )*
|
||||
Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_call_names() -> &'static [&'static str] {
|
||||
&[ #( #cfg_attrs stringify!(#fn_name), )* ]
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::traits::GetCallIndex for #call_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
fn get_call_index(&self) -> u8 {
|
||||
match *self {
|
||||
#( #cfg_attrs Self::#fn_name { .. } => #call_index, )*
|
||||
Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_call_indices() -> &'static [u8] {
|
||||
&[ #( #cfg_attrs #call_index, )* ]
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::traits::UnfilteredDispatchable
|
||||
for #call_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
type RuntimeOrigin = #pezframe_system::pezpallet_prelude::OriginFor<T>;
|
||||
fn dispatch_bypass_filter(
|
||||
self,
|
||||
origin: Self::RuntimeOrigin
|
||||
) -> #pezframe_support::dispatch::DispatchResultWithPostInfo {
|
||||
#pezframe_support::dispatch_context::run_in_context(|| {
|
||||
match self {
|
||||
#(
|
||||
#cfg_attrs
|
||||
Self::#fn_name { #( #args_name_pattern, )* } => {
|
||||
#pezframe_support::__private::pezsp_tracing::enter_span!(
|
||||
#pezframe_support::__private::pezsp_tracing::trace_span!(stringify!(#fn_name))
|
||||
);
|
||||
#maybe_allow_attrs
|
||||
#[allow(clippy::useless_conversion)]
|
||||
<#pezpallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* )
|
||||
.map(Into::into).map_err(Into::into)
|
||||
},
|
||||
)*
|
||||
Self::__Ignore(_, _) => {
|
||||
let _ = origin; // Use origin for empty Call enum
|
||||
unreachable!("__PhantomItem cannot be used.");
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::dispatch::Callable<T> for #pezpallet_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
type RuntimeCall = #call_ident<#type_use_gen>;
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #where_clause {
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
pub fn call_functions() -> #pezframe_support::__private::metadata_ir::PalletCallMetadataIR {
|
||||
#pezframe_support::__private::metadata_ir::PalletCallMetadataIR {
|
||||
ty: #pezframe_support::__private::scale_info::meta_type::<#call_ident<#type_use_gen>>(),
|
||||
deprecation_info: #deprecation,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#( #authorize_fn_pallet_impl )*
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::traits::Authorize for #call_ident<#type_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
fn authorize(&self, source: #pezframe_support::pezpallet_prelude::TransactionSource) -> ::core::option::Option<::core::result::Result<
|
||||
(
|
||||
#pezframe_support::pezpallet_prelude::ValidTransaction,
|
||||
#pezframe_support::pezpallet_prelude::Weight,
|
||||
),
|
||||
#pezframe_support::pezpallet_prelude::TransactionValidityError
|
||||
>>
|
||||
{
|
||||
match *self {
|
||||
#(
|
||||
#cfg_attrs
|
||||
Self::#fn_name { #( #args_name_pattern_ref, )* } => {
|
||||
#authorize_impl
|
||||
},
|
||||
)*
|
||||
Self::__Ignore(_, _) => {
|
||||
let _ = source;
|
||||
unreachable!("__Ignore cannot be used")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn weight_of_authorize(&self) -> #pezframe_support::pezpallet_prelude::Weight {
|
||||
match *self {
|
||||
#(
|
||||
#cfg_attrs
|
||||
Self::#fn_name { #( #args_name_pattern_ref, )* } => {
|
||||
#authorize_fn_weight
|
||||
},
|
||||
)*
|
||||
Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
/// Expands `composite_enum` and adds the `VariantCount` implementation for it.
|
||||
pub fn expand_composites(def: &mut Def) -> TokenStream {
|
||||
let mut expand = quote::quote!();
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
|
||||
for composite in &def.composites {
|
||||
let name = &composite.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = composite.generics.split_for_impl();
|
||||
let variants_count = composite.variant_count;
|
||||
|
||||
// add `VariantCount` implementation for `composite_enum`
|
||||
expand.extend(quote::quote_spanned!(composite.attr_span =>
|
||||
impl #impl_generics #pezframe_support::traits::VariantCount for #name #ty_generics #where_clause {
|
||||
const VARIANT_COUNT: u32 = #variants_count;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
expand
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::{parse::GenericKind, Def};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_quote, Item};
|
||||
|
||||
///
|
||||
/// * Generate default rust doc
|
||||
pub fn expand_config(def: &mut Def) -> TokenStream {
|
||||
let config = &def.config;
|
||||
let config_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[config.index];
|
||||
if let Item::Trait(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by config parser")
|
||||
}
|
||||
};
|
||||
|
||||
config_item.attrs.insert(
|
||||
0,
|
||||
parse_quote!(
|
||||
#[doc = r"
|
||||
Configuration trait of this pezpallet.
|
||||
|
||||
The main purpose of this trait is to act as an interface between this pezpallet and the runtime in
|
||||
which it is embedded in. A type, function, or constant in this trait is essentially left to be
|
||||
configured by the runtime that includes this pezpallet.
|
||||
|
||||
Consequently, a runtime that wants to include this pezpallet must implement this trait."
|
||||
]
|
||||
),
|
||||
);
|
||||
config_item.attrs.retain(|attr| !attr.path().is_ident("deprecated"));
|
||||
|
||||
// insert `pezframe_system::Config` supertrait with `RuntimeEvent: From<Event<Self>>` if neither
|
||||
// associated type nor type bound is defined.
|
||||
if let Some(event) = &def.event {
|
||||
if !def.is_pezframe_system {
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
|
||||
// can't use `type_use_gen()` since it returns `T`, not `Self`
|
||||
let event_use_gen = match event.gen_kind {
|
||||
GenericKind::None => quote!(),
|
||||
GenericKind::Config => quote::quote_spanned! {event.attr_span => Self},
|
||||
GenericKind::ConfigAndInstance => {
|
||||
quote::quote_spanned! {event.attr_span => Self, I}
|
||||
},
|
||||
};
|
||||
|
||||
let supertrait_with_event_bound = syn::parse2::<syn::TypeParamBound>(
|
||||
quote! { #pezframe_system::Config<RuntimeEvent: From<Event<#event_use_gen>>> },
|
||||
)
|
||||
.expect("Parsing super trait doesn't fail; qed");
|
||||
|
||||
config_item.supertraits.push(supertrait_with_event_bound.into());
|
||||
}
|
||||
}
|
||||
|
||||
// we only emit `DefaultConfig` if there are trait items, so an empty `DefaultConfig` is
|
||||
// impossible consequently.
|
||||
match &config.default_sub_trait {
|
||||
Some(default_sub_trait) if default_sub_trait.items.len() > 0 => {
|
||||
let trait_items = &default_sub_trait
|
||||
.items
|
||||
.iter()
|
||||
.map(|item| {
|
||||
if item.1 {
|
||||
if let syn::TraitItem::Type(item) = item.0.clone() {
|
||||
let mut item = item.clone();
|
||||
item.bounds.clear();
|
||||
syn::TraitItem::Type(item)
|
||||
} else {
|
||||
item.0.clone()
|
||||
}
|
||||
} else {
|
||||
item.0.clone()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let type_param_bounds = if default_sub_trait.has_system {
|
||||
let system = &def.pezframe_system;
|
||||
quote::quote!(: #system::DefaultConfig)
|
||||
} else {
|
||||
quote::quote!()
|
||||
};
|
||||
|
||||
quote!(
|
||||
/// Based on [`Config`]. Auto-generated by
|
||||
/// [`#[pezpallet::config(with_default)]`](`pezframe_support::pezpallet_macros::config`).
|
||||
/// Can be used in tandem with
|
||||
/// [`#[register_default_config]`](`pezframe_support::register_default_config`) and
|
||||
/// [`#[derive_impl]`](`pezframe_support::derive_impl`) to derive test config traits
|
||||
/// based on existing pezpallet config traits in a safe and developer-friendly way.
|
||||
///
|
||||
/// See [here](`pezframe_support::pezpallet_macros::config`) for more information and caveats about
|
||||
/// the auto-generated `DefaultConfig` trait and how it is generated.
|
||||
pub trait DefaultConfig #type_param_bounds {
|
||||
#(#trait_items)*
|
||||
}
|
||||
)
|
||||
},
|
||||
_ => quote!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the metadata for the associated types of the config trait.
|
||||
///
|
||||
/// Implements the `pezpallet_associated_types_metadata` function for the pezpallet.
|
||||
pub fn expand_config_metadata(def: &Def) -> proc_macro2::TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
|
||||
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let trait_use_gen = &def.trait_use_generics(proc_macro2::Span::call_site());
|
||||
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause));
|
||||
let completed_where_clause = super::merge_where_clauses(&where_clauses);
|
||||
|
||||
let types = def.config.associated_types_metadata.iter().map(|metadata| {
|
||||
let ident = &metadata.ident;
|
||||
let span = ident.span();
|
||||
let ident_str = ident.to_string();
|
||||
let cfgs = &metadata.cfg;
|
||||
|
||||
let no_docs = vec![];
|
||||
let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &metadata.doc };
|
||||
|
||||
quote::quote_spanned!(span => {
|
||||
#( #cfgs ) *
|
||||
#pezframe_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR {
|
||||
name: #ident_str,
|
||||
ty: #pezframe_support::__private::scale_info::meta_type::<
|
||||
<T as Config #trait_use_gen>::#ident
|
||||
>(),
|
||||
docs: #pezframe_support::__private::vec![ #( #doc ),* ],
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
quote::quote!(
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn pezpallet_associated_types_metadata()
|
||||
-> #pezframe_support::__private::vec::Vec<#pezframe_support::__private::metadata_ir::PalletAssociatedTypeMetadataIR>
|
||||
{
|
||||
#pezframe_support::__private::vec![ #( #types ),* ]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{deprecation::extract_or_return_allow_attrs, pezpallet::Def};
|
||||
|
||||
struct ConstDef {
|
||||
/// Name of the associated type.
|
||||
pub ident: syn::Ident,
|
||||
/// The type in Get, e.g. `u32` in `type Foo: Get<u32>;`, but `Self` is replaced by `T`
|
||||
pub type_: syn::Type,
|
||||
/// The doc associated
|
||||
pub doc: Vec<syn::Expr>,
|
||||
/// default_byte implementation
|
||||
pub default_byte_impl: proc_macro2::TokenStream,
|
||||
/// Constant name for Metadata (optional)
|
||||
pub metadata_name: Option<syn::Ident>,
|
||||
/// Deprecation_info:
|
||||
pub deprecation_info: proc_macro2::TokenStream,
|
||||
}
|
||||
|
||||
/// Implement the `pezpallet_constants_metadata` function for the pezpallet.
|
||||
pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
|
||||
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let trait_use_gen = &def.trait_use_generics(proc_macro2::Span::call_site());
|
||||
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause));
|
||||
let completed_where_clause = super::merge_where_clauses(&where_clauses);
|
||||
|
||||
let mut config_consts = vec![];
|
||||
for const_ in def.config.consts_metadata.iter() {
|
||||
let ident = &const_.ident;
|
||||
let const_type = &const_.type_;
|
||||
let deprecation_info = match crate::deprecation::get_deprecation(
|
||||
"e::quote! { #pezframe_support },
|
||||
&const_.attrs,
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs = extract_or_return_allow_attrs(&const_.attrs);
|
||||
|
||||
config_consts.push(ConstDef {
|
||||
ident: const_.ident.clone(),
|
||||
type_: const_.type_.clone(),
|
||||
doc: const_.doc.clone(),
|
||||
default_byte_impl: quote::quote!(
|
||||
#(#maybe_allow_attrs)*
|
||||
let value = <<T as Config #trait_use_gen>::#ident as
|
||||
#pezframe_support::traits::Get<#const_type>>::get();
|
||||
#pezframe_support::__private::codec::Encode::encode(&value)
|
||||
),
|
||||
metadata_name: None,
|
||||
deprecation_info,
|
||||
})
|
||||
}
|
||||
|
||||
let mut extra_consts = vec![];
|
||||
for const_ in def.extra_constants.iter().flat_map(|d| &d.extra_constants) {
|
||||
let ident = &const_.ident;
|
||||
let deprecation_info = match crate::deprecation::get_deprecation(
|
||||
"e::quote! { #pezframe_support },
|
||||
&const_.attrs,
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs = extract_or_return_allow_attrs(&const_.attrs);
|
||||
|
||||
extra_consts.push(ConstDef {
|
||||
ident: const_.ident.clone(),
|
||||
type_: const_.type_.clone(),
|
||||
doc: const_.doc.clone(),
|
||||
default_byte_impl: quote::quote!(
|
||||
#(#maybe_allow_attrs)*
|
||||
let value = <Pezpallet<#type_use_gen>>::#ident();
|
||||
#pezframe_support::__private::codec::Encode::encode(&value)
|
||||
),
|
||||
metadata_name: const_.metadata_name.clone(),
|
||||
deprecation_info,
|
||||
})
|
||||
}
|
||||
|
||||
let consts = config_consts.into_iter().chain(extra_consts.into_iter()).map(|const_| {
|
||||
let const_type = &const_.type_;
|
||||
let ident_str = format!("{}", const_.metadata_name.unwrap_or(const_.ident));
|
||||
|
||||
let no_docs = vec![];
|
||||
let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &const_.doc };
|
||||
|
||||
let default_byte_impl = &const_.default_byte_impl;
|
||||
let deprecation_info = &const_.deprecation_info;
|
||||
quote::quote!({
|
||||
#pezframe_support::__private::metadata_ir::PalletConstantMetadataIR {
|
||||
name: #ident_str,
|
||||
ty: #pezframe_support::__private::scale_info::meta_type::<#const_type>(),
|
||||
value: { #default_byte_impl },
|
||||
docs: #pezframe_support::__private::vec![ #( #doc ),* ],
|
||||
deprecation_info: #deprecation_info
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
quote::quote!(
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause{
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn pezpallet_constants_metadata()
|
||||
-> #pezframe_support::__private::Vec<#pezframe_support::__private::metadata_ir::PalletConstantMetadataIR>
|
||||
{
|
||||
#pezframe_support::__private::vec![ #( #consts ),* ]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use proc_macro2::Span;
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
|
||||
pub fn expand_doc_only(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let dispatchables = if let Some(call_def) = &def.call {
|
||||
let type_impl_generics = def.type_impl_generics(Span::call_site());
|
||||
call_def
|
||||
.methods
|
||||
.iter()
|
||||
.map(|method| {
|
||||
let name = &method.name;
|
||||
let args = &method
|
||||
.args
|
||||
.iter()
|
||||
.map(|(_, arg_name, arg_type)| quote::quote!( #arg_name: #arg_type, ))
|
||||
.collect::<proc_macro2::TokenStream>();
|
||||
let docs = &method.docs;
|
||||
|
||||
let real = format!(" [`Pezpallet::{}`].", name);
|
||||
quote::quote!(
|
||||
#( #[doc = #docs] )*
|
||||
///
|
||||
/// # Warning: Doc-Only
|
||||
///
|
||||
/// This function is an automatically generated, and is doc-only, uncallable
|
||||
/// stub. See the real version in
|
||||
#[ doc = #real ]
|
||||
pub fn #name<#type_impl_generics>(#args) { unreachable!(); }
|
||||
)
|
||||
})
|
||||
.collect::<proc_macro2::TokenStream>()
|
||||
} else {
|
||||
quote::quote!()
|
||||
};
|
||||
|
||||
let storage_types = def
|
||||
.storages
|
||||
.iter()
|
||||
.map(|storage| {
|
||||
let storage_name = &storage.ident;
|
||||
let storage_type_docs = &storage.docs;
|
||||
let real = format!("[`pezpallet::{}`].", storage_name);
|
||||
quote::quote!(
|
||||
#( #[doc = #storage_type_docs] )*
|
||||
///
|
||||
/// # Warning: Doc-Only
|
||||
///
|
||||
/// This type is automatically generated, and is doc-only. See the real version in
|
||||
#[ doc = #real ]
|
||||
pub struct #storage_name();
|
||||
)
|
||||
})
|
||||
.collect::<proc_macro2::TokenStream>();
|
||||
|
||||
quote::quote!(
|
||||
/// Auto-generated docs-only module listing all (public and private) defined storage types
|
||||
/// for this pezpallet.
|
||||
///
|
||||
/// # Warning: Doc-Only
|
||||
///
|
||||
/// Members of this module cannot be used directly and are only provided for documentation
|
||||
/// purposes.
|
||||
///
|
||||
/// To see the actual storage type, find a struct with the same name at the root of the
|
||||
/// pezpallet, in the list of [*Type Definitions*](../index.html#types).
|
||||
#[cfg(doc)]
|
||||
pub mod storage_types {
|
||||
use super::*;
|
||||
#storage_types
|
||||
}
|
||||
|
||||
/// Auto-generated docs-only module listing all defined dispatchables for this pezpallet.
|
||||
///
|
||||
/// # Warning: Doc-Only
|
||||
///
|
||||
/// Members of this module cannot be used directly and are only provided for documentation
|
||||
/// purposes. To see the real version of each dispatchable, look for them in [`Pezpallet`] or
|
||||
/// [`Call`].
|
||||
#[cfg(doc)]
|
||||
pub mod dispatchables {
|
||||
use super::*;
|
||||
#dispatchables
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::{spanned::Spanned, Attribute, Lit, LitStr};
|
||||
|
||||
const DOC: &'static str = "doc";
|
||||
const PALLET_DOC: &'static str = "pezpallet_doc";
|
||||
|
||||
/// Get the documentation file path from the `pezpallet_doc` attribute.
|
||||
///
|
||||
/// Supported format:
|
||||
/// `#[pezpallet_doc(PATH)]`: The path of the file from which the documentation is loaded
|
||||
fn parse_pallet_doc_value(attr: &Attribute) -> syn::Result<DocMetaValue> {
|
||||
let lit: syn::LitStr = attr.parse_args().map_err(|_| {
|
||||
let msg = "The `pezpallet_doc` received an unsupported argument. Supported format: `pezpallet_doc(\"PATH\")`";
|
||||
syn::Error::new(attr.span(), msg)
|
||||
})?;
|
||||
|
||||
Ok(DocMetaValue::Path(lit))
|
||||
}
|
||||
|
||||
/// Get the value from the `doc` comment attribute:
|
||||
///
|
||||
/// Supported formats:
|
||||
/// - `#[doc = "A doc string"]`: Documentation as a string literal
|
||||
/// - `#[doc = include_str!(PATH)]`: Documentation obtained from a path
|
||||
fn parse_doc_value(attr: &Attribute) -> syn::Result<Option<DocMetaValue>> {
|
||||
if !attr.path().is_ident(DOC) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let meta = attr.meta.require_name_value()?;
|
||||
|
||||
match &meta.value {
|
||||
syn::Expr::Lit(lit) => Ok(Some(DocMetaValue::Lit(lit.lit.clone()))),
|
||||
syn::Expr::Macro(mac) if mac.mac.path.is_ident("include_str") =>
|
||||
Ok(Some(DocMetaValue::Path(mac.mac.parse_body()?))),
|
||||
_ =>
|
||||
Err(syn::Error::new(attr.span(), "Expected `= \"docs\"` or `= include_str!(\"PATH\")`")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Supported documentation tokens.
|
||||
#[derive(Debug)]
|
||||
enum DocMetaValue {
|
||||
/// Documentation with string literals.
|
||||
///
|
||||
/// `#[doc = "Lit"]`
|
||||
Lit(Lit),
|
||||
/// Documentation with `include_str!` macro.
|
||||
///
|
||||
/// The string literal represents the file `PATH`.
|
||||
///
|
||||
/// `#[doc = include_str!(PATH)]`
|
||||
Path(LitStr),
|
||||
}
|
||||
|
||||
impl ToTokens for DocMetaValue {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
DocMetaValue::Lit(lit) => lit.to_tokens(tokens),
|
||||
DocMetaValue::Path(path_lit) => {
|
||||
let decl = quote::quote!(include_str!(#path_lit));
|
||||
tokens.extend(decl)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the documentation from the given pezpallet definition
|
||||
/// to include in the runtime metadata.
|
||||
///
|
||||
/// Implement a `pezpallet_documentation_metadata` function to fetch the
|
||||
/// documentation that is included in the metadata.
|
||||
///
|
||||
/// The documentation is placed on the pezpallet similar to:
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[pezpallet]
|
||||
/// /// Documentation for pezpallet
|
||||
/// #[doc = "Documentation for pezpallet"]
|
||||
/// #[doc = include_str!("../README.md")]
|
||||
/// #[pezpallet_doc("../documentation1.md")]
|
||||
/// #[pezpallet_doc("../documentation2.md")]
|
||||
/// pub mod pezpallet {}
|
||||
/// ```
|
||||
///
|
||||
/// # pezpallet_doc
|
||||
///
|
||||
/// The `pezpallet_doc` attribute can only be provided with one argument,
|
||||
/// which is the file path that holds the documentation to be added to the metadata.
|
||||
///
|
||||
/// Unlike the `doc` attribute, the documentation provided to the `proc_macro` attribute is
|
||||
/// not added to the pezpallet.
|
||||
pub fn expand_documentation(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
|
||||
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let where_clauses = &def.config.where_clause;
|
||||
|
||||
// TODO: Use [drain_filter](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter) when it is stable.
|
||||
|
||||
// The `pezpallet_doc` attributes are excluded from the generation of the pezpallet,
|
||||
// but they are included in the runtime metadata.
|
||||
let mut pezpallet_docs = Vec::with_capacity(def.item.attrs.len());
|
||||
let mut index = 0;
|
||||
while index < def.item.attrs.len() {
|
||||
let attr = &def.item.attrs[index];
|
||||
if attr.path().get_ident().map_or(false, |i| *i == PALLET_DOC) {
|
||||
pezpallet_docs.push(def.item.attrs.remove(index));
|
||||
// Do not increment the index, we have just removed the
|
||||
// element from the attributes.
|
||||
continue;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Capture the `#[doc = include_str!("../README.md")]` and `#[doc = "Documentation"]`.
|
||||
let docs = match def
|
||||
.item
|
||||
.attrs
|
||||
.iter()
|
||||
.filter_map(|v| parse_doc_value(v).transpose())
|
||||
.collect::<syn::Result<Vec<_>>>()
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(err) => return err.into_compile_error(),
|
||||
};
|
||||
|
||||
// Capture the `#[pezpallet_doc("../README.md")]`.
|
||||
let pezpallet_docs = match pezpallet_docs
|
||||
.into_iter()
|
||||
.map(|attr| parse_pallet_doc_value(&attr))
|
||||
.collect::<syn::Result<Vec<_>>>()
|
||||
{
|
||||
Ok(docs) => docs,
|
||||
Err(err) => return err.into_compile_error(),
|
||||
};
|
||||
|
||||
let docs = docs.iter().chain(pezpallet_docs.iter());
|
||||
|
||||
quote::quote!(
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #where_clauses{
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn pezpallet_documentation_metadata()
|
||||
-> #pezframe_support::__private::Vec<&'static str>
|
||||
{
|
||||
#pezframe_support::__private::vec![ #( #docs ),* ]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{
|
||||
deprecation::extract_or_return_allow_attrs,
|
||||
pezpallet::{
|
||||
parse::error::{VariantDef, VariantField},
|
||||
Def,
|
||||
},
|
||||
COUNTER,
|
||||
};
|
||||
use pezframe_support_procedural_tools::get_doc_literals;
|
||||
use quote::ToTokens;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
///
|
||||
/// * impl various trait on Error
|
||||
pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
let error_token_unique_id =
|
||||
syn::Ident::new(&format!("__tt_error_token_{}", count), def.item.span());
|
||||
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
let error = if let Some(error) = &def.error {
|
||||
error
|
||||
} else {
|
||||
return quote::quote! {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #error_token_unique_id {
|
||||
{
|
||||
$caller:tt
|
||||
your_tt_return = [{ $my_tt_return:path }]
|
||||
} => {
|
||||
$my_tt_return! {
|
||||
$caller
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use #error_token_unique_id as tt_error_token;
|
||||
};
|
||||
};
|
||||
|
||||
let error_ident = &error.error;
|
||||
let type_impl_gen = &def.type_impl_generics(error.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(error.attr_span);
|
||||
|
||||
let phantom_variant: syn::Variant = syn::parse_quote!(
|
||||
#[doc(hidden)]
|
||||
#[codec(skip)]
|
||||
__Ignore(
|
||||
core::marker::PhantomData<(#type_use_gen)>,
|
||||
#pezframe_support::Never,
|
||||
)
|
||||
);
|
||||
|
||||
let as_str_matches =
|
||||
error
|
||||
.variants
|
||||
.iter()
|
||||
.map(|VariantDef { ident: variant, field: field_ty, cfg_attrs, maybe_allow_attrs }| {
|
||||
let variant_str = variant.to_string();
|
||||
let cfg_attrs = cfg_attrs.iter().map(|attr| attr.to_token_stream());
|
||||
match field_ty {
|
||||
Some(VariantField { is_named: true }) => {
|
||||
quote::quote_spanned!(error.attr_span => #( #cfg_attrs )* #(#maybe_allow_attrs)* Self::#variant { .. } => #variant_str,)
|
||||
},
|
||||
Some(VariantField { is_named: false }) => {
|
||||
quote::quote_spanned!(error.attr_span => #( #cfg_attrs )* #(#maybe_allow_attrs)* Self::#variant(..) => #variant_str,)
|
||||
},
|
||||
None => {
|
||||
quote::quote_spanned!(error.attr_span => #( #cfg_attrs )* #(#maybe_allow_attrs)* Self::#variant => #variant_str,)
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
let error_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[error.index];
|
||||
if let syn::Item::Enum(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by error parser")
|
||||
}
|
||||
};
|
||||
error_item.variants.insert(0, phantom_variant);
|
||||
|
||||
let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" };
|
||||
|
||||
let deprecation = match crate::deprecation::get_deprecation_enum(
|
||||
"e::quote! {#pezframe_support},
|
||||
error_item.variants.iter().enumerate().map(|(index, item)| {
|
||||
let index = crate::deprecation::variant_index_for_deprecation(index as u8, item);
|
||||
|
||||
(index, item.attrs.as_ref())
|
||||
}),
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
// derive TypeInfo for error metadata
|
||||
error_item.attrs.push(syn::parse_quote! {
|
||||
#[derive(
|
||||
#pezframe_support::__private::codec::Encode,
|
||||
#pezframe_support::__private::codec::Decode,
|
||||
#pezframe_support::__private::codec::DecodeWithMemTracking,
|
||||
#pezframe_support::__private::scale_info::TypeInfo,
|
||||
#pezframe_support::PalletError,
|
||||
)]
|
||||
});
|
||||
error_item.attrs.push(syn::parse_quote!(
|
||||
#[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)]
|
||||
));
|
||||
|
||||
if get_doc_literals(&error_item.attrs).is_empty() {
|
||||
error_item.attrs.push(syn::parse_quote!(
|
||||
#[doc = "The `Error` enum of this pezpallet."]
|
||||
));
|
||||
}
|
||||
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs: Vec<syn::Attribute> =
|
||||
extract_or_return_allow_attrs(&error_item.attrs).collect();
|
||||
|
||||
quote::quote_spanned!(error.attr_span =>
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#type_impl_gen> core::fmt::Debug for #error_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>)
|
||||
-> core::fmt::Result
|
||||
{
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#type_impl_gen> #error_ident<#type_use_gen> #config_where_clause {
|
||||
#[doc(hidden)]
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match &self {
|
||||
#(#maybe_allow_attrs)* Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"),
|
||||
#( #as_str_matches )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#type_impl_gen> From<#error_ident<#type_use_gen>> for &'static str
|
||||
#config_where_clause
|
||||
{
|
||||
fn from(err: #error_ident<#type_use_gen>) -> &'static str {
|
||||
err.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#type_impl_gen> From<#error_ident<#type_use_gen>>
|
||||
for #pezframe_support::pezsp_runtime::DispatchError
|
||||
#config_where_clause
|
||||
{
|
||||
fn from(err: #error_ident<#type_use_gen>) -> Self {
|
||||
use #pezframe_support::__private::codec::Encode;
|
||||
let index = <
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::index::<Pezpallet<#type_use_gen>>()
|
||||
.expect("Every active module has an index in the runtime; qed") as u8;
|
||||
let mut encoded = err.encode();
|
||||
encoded.resize(#pezframe_support::MAX_MODULE_ERROR_ENCODED_SIZE, 0);
|
||||
|
||||
#pezframe_support::pezsp_runtime::DispatchError::Module(#pezframe_support::pezsp_runtime::ModuleError {
|
||||
index,
|
||||
error: TryInto::try_into(encoded).expect("encoded error is resized to be equal to the maximum encoded error size; qed"),
|
||||
message: Some(err.as_str()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #error_token_unique_id {
|
||||
{
|
||||
$caller:tt
|
||||
your_tt_return = [{ $my_tt_return:path }]
|
||||
} => {
|
||||
$my_tt_return! {
|
||||
$caller
|
||||
error = [{ #error_ident }]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use #error_token_unique_id as tt_error_token;
|
||||
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#type_impl_gen> #error_ident<#type_use_gen> #config_where_clause {
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
pub fn error_metadata() -> #pezframe_support::__private::metadata_ir::PalletErrorMetadataIR {
|
||||
#(#maybe_allow_attrs)*
|
||||
#pezframe_support::__private::metadata_ir::PalletErrorMetadataIR {
|
||||
ty: #pezframe_support::__private::scale_info::meta_type::<#error_ident<#type_use_gen>>(),
|
||||
deprecation_info: #deprecation,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{
|
||||
deprecation::extract_or_return_allow_attrs,
|
||||
pezpallet::{parse::event::PalletEventDepositAttr, Def},
|
||||
COUNTER,
|
||||
};
|
||||
use pezframe_support_procedural_tools::get_doc_literals;
|
||||
use syn::{spanned::Spanned, Ident};
|
||||
|
||||
///
|
||||
/// * Add __Ignore variant on Event
|
||||
/// * Impl various trait on Event including metadata
|
||||
/// * if deposit_event is defined, implement deposit_event on module.
|
||||
pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
|
||||
let (event, macro_ident) = if let Some(event) = &def.event {
|
||||
let ident = Ident::new(&format!("__is_event_part_defined_{}", count), event.attr_span);
|
||||
(event, ident)
|
||||
} else {
|
||||
let macro_ident =
|
||||
Ident::new(&format!("__is_event_part_defined_{}", count), def.item.span());
|
||||
|
||||
return quote::quote! {
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_event_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #macro_ident {
|
||||
($pezpallet_name:ident) => {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have #[pezpallet::event] defined, perhaps you should \
|
||||
remove `Event` from construct_runtime?",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #macro_ident as is_event_part_defined;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let event_where_clause = &event.where_clause;
|
||||
|
||||
// NOTE: actually event where clause must be a subset of config where clause because of
|
||||
// `type RuntimeEvent: From<Event<Self>>`. But we merge either way for potential better error
|
||||
// message
|
||||
let completed_where_clause =
|
||||
super::merge_where_clauses(&[&event.where_clause, &def.config.where_clause]);
|
||||
|
||||
let event_ident = &event.event;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
|
||||
let event_impl_gen = &event.gen_kind.type_impl_gen(event.attr_span);
|
||||
let event_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[event.index];
|
||||
if let syn::Item::Enum(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by event parser")
|
||||
}
|
||||
};
|
||||
|
||||
// Phantom data is added for generic event.
|
||||
if event.gen_kind.is_generic() {
|
||||
let variant = syn::parse_quote!(
|
||||
#[doc(hidden)]
|
||||
#[codec(skip)]
|
||||
__Ignore(
|
||||
::core::marker::PhantomData<(#event_use_gen)>,
|
||||
#pezframe_support::Never,
|
||||
)
|
||||
);
|
||||
|
||||
// Push ignore variant at the end.
|
||||
event_item.variants.push(variant);
|
||||
}
|
||||
|
||||
let deprecation = match crate::deprecation::get_deprecation_enum(
|
||||
"e::quote! {#pezframe_support},
|
||||
event_item.variants.iter().enumerate().map(|(index, item)| {
|
||||
let index = crate::deprecation::variant_index_for_deprecation(index as u8, item);
|
||||
|
||||
(index, item.attrs.as_ref())
|
||||
}),
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
if get_doc_literals(&event_item.attrs).is_empty() {
|
||||
event_item
|
||||
.attrs
|
||||
.push(syn::parse_quote!(#[doc = "The `Event` enum of this pezpallet"]));
|
||||
}
|
||||
|
||||
// derive some traits because system event require Clone, FullCodec, Eq, PartialEq and Debug
|
||||
event_item.attrs.push(syn::parse_quote!(
|
||||
#[derive(
|
||||
#pezframe_support::CloneNoBound,
|
||||
#pezframe_support::EqNoBound,
|
||||
#pezframe_support::PartialEqNoBound,
|
||||
#pezframe_support::DebugNoBound,
|
||||
#pezframe_support::__private::codec::Encode,
|
||||
#pezframe_support::__private::codec::Decode,
|
||||
#pezframe_support::__private::codec::DecodeWithMemTracking,
|
||||
#pezframe_support::__private::scale_info::TypeInfo,
|
||||
)]
|
||||
));
|
||||
|
||||
let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" };
|
||||
|
||||
// skip requirement for type params to implement `TypeInfo`, and set docs capture
|
||||
event_item.attrs.push(syn::parse_quote!(
|
||||
#[scale_info(skip_type_params(#event_use_gen), capture_docs = #capture_docs)]
|
||||
));
|
||||
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs: Vec<syn::Attribute> =
|
||||
extract_or_return_allow_attrs(&event_item.attrs).collect();
|
||||
|
||||
let deposit_event = if let Some(deposit_event) = &event.deposit_event {
|
||||
let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
|
||||
let type_impl_gen = &def.type_impl_generics(event.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(event.attr_span);
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
|
||||
let PalletEventDepositAttr { fn_vis, fn_span, .. } = deposit_event;
|
||||
|
||||
quote::quote_spanned!(*fn_span =>
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#(#maybe_allow_attrs)*
|
||||
#fn_vis fn deposit_event(event: Event<#event_use_gen>) {
|
||||
let event = <
|
||||
<T as #pezframe_system::Config>::RuntimeEvent as
|
||||
From<Event<#event_use_gen>>
|
||||
>::from(event);
|
||||
|
||||
let event = <
|
||||
<T as #pezframe_system::Config>::RuntimeEvent as
|
||||
Into<<T as #pezframe_system::Config>::RuntimeEvent>
|
||||
>::into(event);
|
||||
|
||||
<#pezframe_system::Pezpallet<T>>::deposit_event(event)
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
quote::quote_spanned!(event.attr_span =>
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_event_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #macro_ident {
|
||||
($pezpallet_name:ident) => {};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #macro_ident as is_event_part_defined;
|
||||
}
|
||||
|
||||
#deposit_event
|
||||
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#event_impl_gen> From<#event_ident<#event_use_gen>> for () #event_where_clause {
|
||||
fn from(_: #event_ident<#event_use_gen>) {}
|
||||
}
|
||||
|
||||
#(#maybe_allow_attrs)*
|
||||
impl<#event_impl_gen> #event_ident<#event_use_gen> #event_where_clause {
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
pub fn event_metadata<W: #pezframe_support::__private::scale_info::TypeInfo + 'static>() -> #pezframe_support::__private::metadata_ir::PalletEventMetadataIR {
|
||||
#pezframe_support::__private::metadata_ir::PalletEventMetadataIR {
|
||||
ty: #pezframe_support::__private::scale_info::meta_type::<W>(),
|
||||
deprecation_info: #deprecation,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
|
||||
///
|
||||
/// * implement the trait `pezsp_runtime::BuildStorage`
|
||||
pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let genesis_config = if let Some(genesis_config) = &def.genesis_config {
|
||||
genesis_config
|
||||
} else {
|
||||
return Default::default();
|
||||
};
|
||||
let genesis_build = def.genesis_build.as_ref().expect("Checked by def parser");
|
||||
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let type_impl_gen = &genesis_config.gen_kind.type_impl_gen(genesis_build.attr_span);
|
||||
let gen_cfg_ident = &genesis_config.genesis_config;
|
||||
let gen_cfg_use_gen = &genesis_config.gen_kind.type_use_gen(genesis_build.attr_span);
|
||||
|
||||
let where_clause = &genesis_build.where_clause;
|
||||
|
||||
quote::quote_spanned!(genesis_build.attr_span =>
|
||||
#pezframe_support::std_enabled! {
|
||||
impl<#type_impl_gen> #pezframe_support::pezsp_runtime::BuildStorage for #gen_cfg_ident<#gen_cfg_use_gen> #where_clause
|
||||
{
|
||||
fn assimilate_storage(&self, storage: &mut #pezframe_support::pezsp_runtime::Storage) -> std::result::Result<(), std::string::String> {
|
||||
#pezframe_support::__private::BasicExternalities::execute_with_storage(storage, || {
|
||||
self.build();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{pezpallet::Def, COUNTER};
|
||||
use pezframe_support_procedural_tools::get_doc_literals;
|
||||
use quote::ToTokens;
|
||||
use syn::{spanned::Spanned, Ident};
|
||||
|
||||
///
|
||||
/// * add various derive trait on GenesisConfig struct.
|
||||
pub fn expand_genesis_config(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
|
||||
let (genesis_config, def_macro_ident, std_macro_ident) =
|
||||
if let Some(genesis_config) = &def.genesis_config {
|
||||
let def_macro_ident = Ident::new(
|
||||
&format!("__is_genesis_config_defined_{}", count),
|
||||
genesis_config.genesis_config.span(),
|
||||
);
|
||||
|
||||
let std_macro_ident = Ident::new(
|
||||
&format!("__is_std_macro_defined_for_genesis_{}", count),
|
||||
genesis_config.genesis_config.span(),
|
||||
);
|
||||
|
||||
(genesis_config, def_macro_ident, std_macro_ident)
|
||||
} else {
|
||||
let def_macro_ident =
|
||||
Ident::new(&format!("__is_genesis_config_defined_{}", count), def.item.span());
|
||||
|
||||
let std_macro_ident =
|
||||
Ident::new(&format!("__is_std_enabled_for_genesis_{}", count), def.item.span());
|
||||
|
||||
return quote::quote! {
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_genesis_config_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #def_macro_ident {
|
||||
($pezpallet_name:ident) => {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have #[pezpallet::genesis_config] defined, perhaps you should \
|
||||
remove `Config` from construct_runtime?",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #std_macro_ident {
|
||||
($pezpallet_name:ident, $pezpallet_path:expr) => {};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #def_macro_ident as is_genesis_config_defined;
|
||||
#[doc(hidden)]
|
||||
pub use #std_macro_ident as is_std_enabled_for_genesis;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
|
||||
let genesis_config_item =
|
||||
&mut def.item.content.as_mut().expect("Checked by def parser").1[genesis_config.index];
|
||||
|
||||
let serde_crate = format!("{}::__private::serde", pezframe_support.to_token_stream());
|
||||
|
||||
match genesis_config_item {
|
||||
syn::Item::Enum(syn::ItemEnum { attrs, .. }) |
|
||||
syn::Item::Struct(syn::ItemStruct { attrs, .. }) |
|
||||
syn::Item::Type(syn::ItemType { attrs, .. }) => {
|
||||
if get_doc_literals(attrs).is_empty() {
|
||||
attrs.push(syn::parse_quote!(
|
||||
#[doc = r"
|
||||
Can be used to configure the
|
||||
[genesis state](https://docs.pezkuwichain.io/build/genesis-configuration/)
|
||||
of this pezpallet.
|
||||
"]
|
||||
));
|
||||
}
|
||||
attrs.push(syn::parse_quote!(
|
||||
#[derive(#pezframe_support::Serialize, #pezframe_support::Deserialize)]
|
||||
));
|
||||
attrs.push(syn::parse_quote!( #[serde(rename_all = "camelCase")] ));
|
||||
attrs.push(syn::parse_quote!( #[serde(deny_unknown_fields)] ));
|
||||
attrs.push(syn::parse_quote!( #[serde(bound(serialize = ""))] ));
|
||||
attrs.push(syn::parse_quote!( #[serde(bound(deserialize = ""))] ));
|
||||
attrs.push(syn::parse_quote!( #[serde(crate = #serde_crate)] ));
|
||||
},
|
||||
_ => unreachable!("Checked by genesis_config parser"),
|
||||
}
|
||||
|
||||
quote::quote! {
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_genesis_config_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #def_macro_ident {
|
||||
($pezpallet_name:ident) => {};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #std_macro_ident {
|
||||
($pezpallet_name:ident, $pezpallet_path:expr) => {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have the std feature enabled, this will cause the `",
|
||||
$pezpallet_path,
|
||||
"::GenesisConfig` type to not implement serde traits."
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #std_macro_ident {
|
||||
($pezpallet_name:ident, $pezpallet_path:expr) => {};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #def_macro_ident as is_genesis_config_defined;
|
||||
#[doc(hidden)]
|
||||
pub use #std_macro_ident as is_std_enabled_for_genesis;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
|
||||
/// * implement the individual traits using the Hooks trait
|
||||
pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let (where_clause, span, has_runtime_upgrade) = match def.hooks.as_ref() {
|
||||
Some(hooks) => {
|
||||
let where_clause = hooks.where_clause.clone();
|
||||
let span = hooks.attr_span;
|
||||
let has_runtime_upgrade = hooks.has_runtime_upgrade;
|
||||
(where_clause, span, has_runtime_upgrade)
|
||||
},
|
||||
None => (def.config.where_clause.clone(), def.pezpallet_struct.attr_span, false),
|
||||
};
|
||||
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let type_impl_gen = &def.type_impl_generics(span);
|
||||
let type_use_gen = &def.type_use_generics(span);
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let pezpallet_name = quote::quote! {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as
|
||||
#pezframe_support::traits::PalletInfo
|
||||
>::name::<Self>().unwrap_or("<unknown pezpallet name>")
|
||||
};
|
||||
|
||||
let initialize_on_chain_storage_version = if let Some(in_code_version) =
|
||||
&def.pezpallet_struct.storage_version
|
||||
{
|
||||
quote::quote! {
|
||||
#pezframe_support::__private::log::info!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"🐥 New pezpallet {:?} detected in the runtime. Initializing the on-chain storage version to match the storage version defined in the pezpallet: {:?}",
|
||||
#pezpallet_name,
|
||||
#in_code_version
|
||||
);
|
||||
#in_code_version.put::<Self>();
|
||||
}
|
||||
} else {
|
||||
quote::quote! {
|
||||
let default_version = #pezframe_support::traits::StorageVersion::new(0);
|
||||
#pezframe_support::__private::log::info!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"🐥 New pezpallet {:?} detected in the runtime. The pezpallet has no defined storage version, so the on-chain version is being initialized to {:?}.",
|
||||
#pezpallet_name,
|
||||
default_version
|
||||
);
|
||||
default_version.put::<Self>();
|
||||
}
|
||||
};
|
||||
|
||||
let log_runtime_upgrade = if has_runtime_upgrade {
|
||||
// a migration is defined here.
|
||||
quote::quote! {
|
||||
#pezframe_support::__private::log::info!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"⚠️ {} declares internal migrations (which *might* execute). \
|
||||
On-chain `{:?}` vs in-code storage version `{:?}`",
|
||||
#pezpallet_name,
|
||||
<Self as #pezframe_support::traits::GetStorageVersion>::on_chain_storage_version(),
|
||||
<Self as #pezframe_support::traits::GetStorageVersion>::in_code_storage_version(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// default.
|
||||
quote::quote! {
|
||||
#pezframe_support::__private::log::debug!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"✅ no migration for {}",
|
||||
#pezpallet_name,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let hooks_impl = if def.hooks.is_none() {
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
quote::quote! {
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::Hooks<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause {}
|
||||
}
|
||||
} else {
|
||||
proc_macro2::TokenStream::new()
|
||||
};
|
||||
|
||||
// If a storage version is set, we should ensure that the storage version on chain matches the
|
||||
// in-code storage version. This assumes that `Executive` is running custom migrations before
|
||||
// the pallets are called.
|
||||
let post_storage_version_check = if def.pezpallet_struct.storage_version.is_some() {
|
||||
quote::quote! {
|
||||
let on_chain_version = <Self as #pezframe_support::traits::GetStorageVersion>::on_chain_storage_version();
|
||||
let in_code_version = <Self as #pezframe_support::traits::GetStorageVersion>::in_code_storage_version();
|
||||
|
||||
if on_chain_version != in_code_version {
|
||||
#pezframe_support::__private::log::error!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"{}: On chain storage version {:?} doesn't match in-code storage version {:?}.",
|
||||
#pezpallet_name,
|
||||
on_chain_version,
|
||||
in_code_version,
|
||||
);
|
||||
|
||||
return Err("On chain and in-code storage version do not match. Missing runtime upgrade?".into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote::quote! {
|
||||
let on_chain_version = <Self as #pezframe_support::traits::GetStorageVersion>::on_chain_storage_version();
|
||||
|
||||
if on_chain_version != #pezframe_support::traits::StorageVersion::new(0) {
|
||||
#pezframe_support::__private::log::error!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"{}: On chain storage version {:?} is set to non zero, \
|
||||
while the pezpallet is missing the `#[pezpallet::storage_version(VERSION)]` attribute.",
|
||||
#pezpallet_name,
|
||||
on_chain_version,
|
||||
);
|
||||
|
||||
return Err("On chain storage version set, while the pezpallet doesn't \
|
||||
have the `#[pezpallet::storage_version(VERSION)]` attribute.".into());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
quote::quote_spanned!(span =>
|
||||
#hooks_impl
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::OnFinalize<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn on_finalize(n: #pezframe_system::pezpallet_prelude::BlockNumberFor::<T>) {
|
||||
#pezframe_support::__private::pezsp_tracing::enter_span!(
|
||||
#pezframe_support::__private::pezsp_tracing::trace_span!("on_finalize")
|
||||
);
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::on_finalize(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::OnIdle<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn on_idle(
|
||||
n: #pezframe_system::pezpallet_prelude::BlockNumberFor::<T>,
|
||||
remaining_weight: #pezframe_support::weights::Weight
|
||||
) -> #pezframe_support::weights::Weight {
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::on_idle(n, remaining_weight)
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::OnPoll<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn on_poll(
|
||||
n: #pezframe_system::pezpallet_prelude::BlockNumberFor::<T>,
|
||||
weight: &mut #pezframe_support::weights::WeightMeter
|
||||
) {
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::on_poll(n, weight);
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::OnInitialize<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn on_initialize(
|
||||
n: #pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
) -> #pezframe_support::weights::Weight {
|
||||
#pezframe_support::__private::pezsp_tracing::enter_span!(
|
||||
#pezframe_support::__private::pezsp_tracing::trace_span!("on_initialize")
|
||||
);
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::on_initialize(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::BeforeAllRuntimeMigrations
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn before_all_runtime_migrations() -> #pezframe_support::weights::Weight {
|
||||
use #pezframe_support::traits::{Get, PalletInfoAccess};
|
||||
use #pezframe_support::__private::hashing::twox_128;
|
||||
use #pezframe_support::storage::unhashed::contains_prefixed_key;
|
||||
#pezframe_support::__private::pezsp_tracing::enter_span!(
|
||||
#pezframe_support::__private::pezsp_tracing::trace_span!("before_all")
|
||||
);
|
||||
|
||||
// Check if the pezpallet has any keys set, including the storage version. If there are
|
||||
// no keys set, the pezpallet was just added to the runtime and needs to have its
|
||||
// version initialized.
|
||||
let pezpallet_hashed_prefix = <Self as PalletInfoAccess>::name_hash();
|
||||
let exists = contains_prefixed_key(&pezpallet_hashed_prefix);
|
||||
if !exists {
|
||||
#initialize_on_chain_storage_version
|
||||
<T as #pezframe_system::Config>::DbWeight::get().reads_writes(1, 1)
|
||||
} else {
|
||||
<T as #pezframe_system::Config>::DbWeight::get().reads(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::OnRuntimeUpgrade
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn on_runtime_upgrade() -> #pezframe_support::weights::Weight {
|
||||
#pezframe_support::__private::pezsp_tracing::enter_span!(
|
||||
#pezframe_support::__private::pezsp_tracing::trace_span!("on_runtime_update")
|
||||
);
|
||||
|
||||
// log info about the upgrade.
|
||||
#log_runtime_upgrade
|
||||
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::on_runtime_upgrade()
|
||||
}
|
||||
|
||||
#pezframe_support::try_runtime_enabled! {
|
||||
fn pre_upgrade() -> Result<#pezframe_support::__private::Vec<u8>, #pezframe_support::pezsp_runtime::TryRuntimeError> {
|
||||
<
|
||||
Self
|
||||
as
|
||||
#pezframe_support::traits::Hooks<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
>::pre_upgrade()
|
||||
}
|
||||
|
||||
fn post_upgrade(state: #pezframe_support::__private::Vec<u8>) -> Result<(), #pezframe_support::pezsp_runtime::TryRuntimeError> {
|
||||
#post_storage_version_check
|
||||
|
||||
<
|
||||
Self
|
||||
as
|
||||
#pezframe_support::traits::Hooks<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
>::post_upgrade(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::OffchainWorker<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn offchain_worker(n: #pezframe_system::pezpallet_prelude::BlockNumberFor::<T>) {
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::offchain_worker(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Integrity tests are only required for when `std` is enabled.
|
||||
#pezframe_support::std_enabled! {
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::IntegrityTest
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn integrity_test() {
|
||||
#pezframe_support::__private::pezsp_io::TestExternalities::default().execute_with(|| {
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::integrity_test()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pezframe_support::try_runtime_enabled! {
|
||||
impl<#type_impl_gen>
|
||||
#pezframe_support::traits::TryState<#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>>
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
fn try_state(
|
||||
n: #pezframe_system::pezpallet_prelude::BlockNumberFor::<T>,
|
||||
_s: #pezframe_support::traits::TryStateSelect
|
||||
) -> Result<(), #pezframe_support::pezsp_runtime::TryRuntimeError> {
|
||||
#pezframe_support::__private::log::info!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"🩺 Running {:?} try-state checks",
|
||||
#pezpallet_name,
|
||||
);
|
||||
<
|
||||
Self as #pezframe_support::traits::Hooks<
|
||||
#pezframe_system::pezpallet_prelude::BlockNumberFor::<T>
|
||||
>
|
||||
>::try_state(n).inspect_err(|err| {
|
||||
#pezframe_support::__private::log::error!(
|
||||
target: #pezframe_support::LOG_TARGET,
|
||||
"❌ {:?} try_state checks failed: {:?}",
|
||||
#pezpallet_name,
|
||||
err
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{pezpallet::Def, COUNTER};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{spanned::Spanned, Ident};
|
||||
|
||||
pub fn expand_inherents(def: &mut Def) -> TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
let macro_ident = Ident::new(&format!("__is_inherent_part_defined_{}", count), def.item.span());
|
||||
|
||||
let maybe_compile_error = if def.inherent.is_none() {
|
||||
quote! {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have #[pezpallet::inherent] defined, perhaps you should \
|
||||
remove `Inherent` from construct_runtime?",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_inherent_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #macro_ident {
|
||||
($pezpallet_name:ident) => {
|
||||
#maybe_compile_error
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #macro_ident as is_inherent_part_defined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{pezpallet::Def, NUMBER_OF_INSTANCE};
|
||||
use proc_macro2::Span;
|
||||
|
||||
///
|
||||
/// * Provide inherent instance to be used by construct_runtime
|
||||
/// * Provide Instance1 ..= Instance16 for instantiable pezpallet
|
||||
pub fn expand_instances(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let inherent_ident = syn::Ident::new(crate::INHERENT_INSTANCE_NAME, Span::call_site());
|
||||
let instances = if def.config.has_instance {
|
||||
(1..=NUMBER_OF_INSTANCE)
|
||||
.map(|i| syn::Ident::new(&format!("Instance{}", i), Span::call_site()))
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
quote::quote!(
|
||||
/// Hidden instance generated to be internally used when module is used without
|
||||
/// instance.
|
||||
#[doc(hidden)]
|
||||
pub type #inherent_ident = ();
|
||||
|
||||
#( pub use #pezframe_support::instances::#instances; )*
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod call;
|
||||
mod composite;
|
||||
mod config;
|
||||
mod constants;
|
||||
mod doc_only;
|
||||
mod documentation;
|
||||
mod error;
|
||||
mod event;
|
||||
mod genesis_build;
|
||||
mod genesis_config;
|
||||
mod hooks;
|
||||
mod inherent;
|
||||
mod instances;
|
||||
mod origin;
|
||||
mod pezpallet_struct;
|
||||
mod storage;
|
||||
mod tasks;
|
||||
mod tt_default_parts;
|
||||
mod type_value;
|
||||
mod validate_unsigned;
|
||||
mod view_functions;
|
||||
mod warnings;
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
use quote::ToTokens;
|
||||
|
||||
/// Merge where clause together, `where` token span is taken from the first not none one.
|
||||
pub fn merge_where_clauses(clauses: &[&Option<syn::WhereClause>]) -> Option<syn::WhereClause> {
|
||||
let mut clauses = clauses.iter().filter_map(|f| f.as_ref());
|
||||
let mut res = clauses.next()?.clone();
|
||||
for other in clauses {
|
||||
res.predicates.extend(other.predicates.iter().cloned())
|
||||
}
|
||||
Some(res)
|
||||
}
|
||||
|
||||
/// Expand definition, in particular:
|
||||
/// * add some bounds and variants to type defined,
|
||||
/// * create some new types,
|
||||
/// * impl stuff on them.
|
||||
pub fn expand(mut def: Def) -> proc_macro2::TokenStream {
|
||||
// Remove the `pezpallet_doc` attribute first.
|
||||
let metadata_docs = documentation::expand_documentation(&mut def);
|
||||
let constants = constants::expand_constants(&mut def);
|
||||
let pezpallet_struct = pezpallet_struct::expand_pallet_struct(&mut def);
|
||||
let config = config::expand_config(&mut def);
|
||||
let associated_types = config::expand_config_metadata(&def);
|
||||
let call = call::expand_call(&mut def);
|
||||
let tasks = tasks::expand_tasks(&mut def);
|
||||
let error = error::expand_error(&mut def);
|
||||
let event = event::expand_event(&mut def);
|
||||
let storages = storage::expand_storages(&mut def);
|
||||
let view_functions = view_functions::expand_view_functions(&def);
|
||||
let inherents = inherent::expand_inherents(&mut def);
|
||||
let instances = instances::expand_instances(&mut def);
|
||||
let hooks = hooks::expand_hooks(&mut def);
|
||||
let genesis_build = genesis_build::expand_genesis_build(&mut def);
|
||||
let genesis_config = genesis_config::expand_genesis_config(&mut def);
|
||||
let type_values = type_value::expand_type_values(&mut def);
|
||||
let origin = origin::expand_origin(&mut def);
|
||||
let validate_unsigned = validate_unsigned::expand_validate_unsigned(&mut def);
|
||||
let tt_default_parts = tt_default_parts::expand_tt_default_parts(&mut def);
|
||||
let doc_only = doc_only::expand_doc_only(&mut def);
|
||||
let composites = composite::expand_composites(&mut def);
|
||||
|
||||
let warnings = def.config.warnings;
|
||||
|
||||
def.item.attrs.insert(
|
||||
0,
|
||||
syn::parse_quote!(
|
||||
#[doc = r"The `pezpallet` module in each FRAME pezpallet hosts the most important items needed
|
||||
to construct this pezpallet.
|
||||
|
||||
The main components of this pezpallet are:
|
||||
- [`Pezpallet`], which implements all of the dispatchable extrinsics of the pezpallet, among
|
||||
other public functions.
|
||||
- The subset of the functions that are dispatchable can be identified either in the
|
||||
[`dispatchables`] module or in the [`Call`] enum.
|
||||
- [`storage_types`], which contains the list of all types that are representing a
|
||||
storage item. Otherwise, all storage items are listed among [*Type Definitions*](#types).
|
||||
- [`Config`], which contains the configuration trait of this pezpallet.
|
||||
- [`Event`] and [`Error`], which are listed among the [*Enums*](#enums).
|
||||
"]
|
||||
),
|
||||
);
|
||||
|
||||
let new_items = quote::quote!(
|
||||
#(
|
||||
#warnings
|
||||
)*
|
||||
#metadata_docs
|
||||
#constants
|
||||
#pezpallet_struct
|
||||
#config
|
||||
#associated_types
|
||||
#call
|
||||
#tasks
|
||||
#error
|
||||
#event
|
||||
#storages
|
||||
#view_functions
|
||||
#inherents
|
||||
#instances
|
||||
#hooks
|
||||
#genesis_build
|
||||
#genesis_config
|
||||
#type_values
|
||||
#origin
|
||||
#validate_unsigned
|
||||
#tt_default_parts
|
||||
#doc_only
|
||||
#composites
|
||||
);
|
||||
|
||||
let item = &mut def.item.content.as_mut().expect("This is checked by parsing").1;
|
||||
item.push(syn::Item::Verbatim(new_items));
|
||||
|
||||
def.item.into_token_stream()
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{pezpallet::Def, COUNTER};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{spanned::Spanned, Ident};
|
||||
|
||||
/// expand the `is_origin_part_defined` macro.
|
||||
pub fn expand_origin(def: &mut Def) -> TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
let macro_ident = Ident::new(&format!("__is_origin_part_defined_{}", count), def.item.span());
|
||||
|
||||
let maybe_compile_error = if def.origin.is_none() {
|
||||
quote! {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have #[pezpallet::origin] defined, perhaps you should \
|
||||
remove `Origin` from construct_runtime?",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_origin_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #macro_ident {
|
||||
($pezpallet_name:ident) => {
|
||||
#maybe_compile_error
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #macro_ident as is_origin_part_defined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::{expand::merge_where_clauses, Def};
|
||||
use pezframe_support_procedural_tools::get_doc_literals;
|
||||
|
||||
///
|
||||
/// * Add derive trait on Pezpallet
|
||||
/// * Implement GetStorageVersion on Pezpallet
|
||||
/// * Implement OnGenesis on Pezpallet
|
||||
/// * Implement `fn error_metadata` on Pezpallet
|
||||
/// * declare Module type alias for construct_runtime
|
||||
/// * replace the first field type of `struct Pezpallet` with `PhantomData` if it is `_`
|
||||
/// * implementation of `PalletInfoAccess` information
|
||||
/// * implementation of `StorageInfoTrait` on Pezpallet
|
||||
pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let type_impl_gen = &def.type_impl_generics(def.pezpallet_struct.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(def.pezpallet_struct.attr_span);
|
||||
let type_decl_gen = &def.type_decl_generics(def.pezpallet_struct.attr_span);
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
let deprecation_status =
|
||||
match crate::deprecation::get_deprecation("e::quote! {#pezframe_support}, &def.item.attrs)
|
||||
{
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
let mut storages_where_clauses = vec![&def.config.where_clause];
|
||||
storages_where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
|
||||
let storages_where_clauses = merge_where_clauses(&storages_where_clauses);
|
||||
|
||||
let pezpallet_item = {
|
||||
let pezpallet_module_items = &mut def.item.content.as_mut().expect("Checked by def").1;
|
||||
let item = &mut pezpallet_module_items[def.pezpallet_struct.index];
|
||||
if let syn::Item::Struct(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by pezpallet struct parser")
|
||||
}
|
||||
};
|
||||
|
||||
// If the first field type is `_` then we replace with `PhantomData`
|
||||
if let Some(field) = pezpallet_item.fields.iter_mut().next() {
|
||||
if field.ty == syn::parse_quote!(_) {
|
||||
field.ty = syn::parse_quote!(
|
||||
core::marker::PhantomData<(#type_use_gen)>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if get_doc_literals(&pezpallet_item.attrs).is_empty() {
|
||||
pezpallet_item.attrs.push(syn::parse_quote!(
|
||||
#[doc = r"
|
||||
The `Pezpallet` struct, the main type that implements traits and standalone
|
||||
functions within the pezpallet.
|
||||
"]
|
||||
));
|
||||
}
|
||||
|
||||
pezpallet_item.attrs.push(syn::parse_quote!(
|
||||
#[derive(
|
||||
#pezframe_support::CloneNoBound,
|
||||
#pezframe_support::EqNoBound,
|
||||
#pezframe_support::PartialEqNoBound,
|
||||
#pezframe_support::RuntimeDebugNoBound,
|
||||
)]
|
||||
));
|
||||
|
||||
let pezpallet_error_metadata = if let Some(error_def) = &def.error {
|
||||
let error_ident = &error_def.error;
|
||||
quote::quote_spanned!(def.pezpallet_struct.attr_span =>
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #config_where_clause {
|
||||
#[doc(hidden)]
|
||||
#[allow(deprecated)]
|
||||
pub fn error_metadata() -> Option<#pezframe_support::__private::metadata_ir::PalletErrorMetadataIR> {
|
||||
Some(<#error_ident<#type_use_gen>>::error_metadata())
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
quote::quote_spanned!(def.pezpallet_struct.attr_span =>
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #config_where_clause {
|
||||
#[doc(hidden)]
|
||||
pub fn error_metadata() -> Option<#pezframe_support::__private::metadata_ir::PalletErrorMetadataIR> {
|
||||
None
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
let storage_info_span =
|
||||
def.pezpallet_struct.without_storage_info.unwrap_or(def.pezpallet_struct.attr_span);
|
||||
|
||||
let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::<Vec<_>>();
|
||||
let storage_cfg_attrs =
|
||||
&def.storages.iter().map(|storage| &storage.cfg_attrs).collect::<Vec<_>>();
|
||||
let storage_maybe_allow_attrs = &def
|
||||
.storages
|
||||
.iter()
|
||||
.map(|storage| crate::deprecation::extract_or_return_allow_attrs(&storage.attrs).collect())
|
||||
.collect::<Vec<Vec<_>>>();
|
||||
// Depending on the flag `without_storage_info` and the storage attribute `unbounded`, we use
|
||||
// partial or full storage info from storage.
|
||||
let storage_info_traits = &def
|
||||
.storages
|
||||
.iter()
|
||||
.map(|storage| {
|
||||
if storage.unbounded || def.pezpallet_struct.without_storage_info.is_some() {
|
||||
quote::quote_spanned!(storage_info_span => PartialStorageInfoTrait)
|
||||
} else {
|
||||
quote::quote_spanned!(storage_info_span => StorageInfoTrait)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let storage_info_methods = &def
|
||||
.storages
|
||||
.iter()
|
||||
.map(|storage| {
|
||||
if storage.unbounded || def.pezpallet_struct.without_storage_info.is_some() {
|
||||
quote::quote_spanned!(storage_info_span => partial_storage_info)
|
||||
} else {
|
||||
quote::quote_spanned!(storage_info_span => storage_info)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let storage_info = quote::quote_spanned!(storage_info_span =>
|
||||
impl<#type_impl_gen> #pezframe_support::traits::StorageInfoTrait
|
||||
for #pezpallet_ident<#type_use_gen>
|
||||
#storages_where_clauses
|
||||
{
|
||||
fn storage_info()
|
||||
-> #pezframe_support::__private::Vec<#pezframe_support::traits::StorageInfo>
|
||||
{
|
||||
#[allow(unused_mut)]
|
||||
let mut res = #pezframe_support::__private::vec![];
|
||||
|
||||
#(
|
||||
#(#storage_cfg_attrs)*
|
||||
#(#storage_maybe_allow_attrs)*
|
||||
{
|
||||
let mut storage_info = <
|
||||
#storage_names<#type_use_gen>
|
||||
as #pezframe_support::traits::#storage_info_traits
|
||||
>::#storage_info_methods();
|
||||
res.append(&mut storage_info);
|
||||
}
|
||||
)*
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let (storage_version, in_code_storage_version_ty) =
|
||||
if let Some(v) = def.pezpallet_struct.storage_version.as_ref() {
|
||||
(quote::quote! { #v }, quote::quote! { #pezframe_support::traits::StorageVersion })
|
||||
} else {
|
||||
(
|
||||
quote::quote! { core::default::Default::default() },
|
||||
quote::quote! { #pezframe_support::traits::NoStorageVersionSet },
|
||||
)
|
||||
};
|
||||
|
||||
let whitelisted_storage_idents: Vec<syn::Ident> = def
|
||||
.storages
|
||||
.iter()
|
||||
.filter_map(|s| s.whitelisted.then(|| s.ident.clone()))
|
||||
.collect();
|
||||
|
||||
let whitelisted_storage_keys_impl = quote::quote![
|
||||
use #pezframe_support::traits::{StorageInfoTrait, TrackedStorageKey, WhitelistedStorageKeys};
|
||||
impl<#type_impl_gen> WhitelistedStorageKeys for #pezpallet_ident<#type_use_gen> #storages_where_clauses {
|
||||
fn whitelisted_storage_keys() -> #pezframe_support::__private::Vec<TrackedStorageKey> {
|
||||
use #pezframe_support::__private::vec;
|
||||
vec![#(
|
||||
TrackedStorageKey::new(#whitelisted_storage_idents::<#type_use_gen>::hashed_key().to_vec())
|
||||
),*]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
quote::quote_spanned!(def.pezpallet_struct.attr_span =>
|
||||
#pezpallet_error_metadata
|
||||
|
||||
/// Type alias to `Pezpallet`, to be used by `construct_runtime`.
|
||||
///
|
||||
/// Generated by `pezpallet` attribute macro.
|
||||
#[deprecated(note = "use `Pezpallet` instead")]
|
||||
#[allow(dead_code)]
|
||||
pub type Module<#type_decl_gen> = #pezpallet_ident<#type_use_gen>;
|
||||
|
||||
// Implement `GetStorageVersion` for `Pezpallet`
|
||||
impl<#type_impl_gen> #pezframe_support::traits::GetStorageVersion
|
||||
for #pezpallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
type InCodeStorageVersion = #in_code_storage_version_ty;
|
||||
|
||||
fn in_code_storage_version() -> Self::InCodeStorageVersion {
|
||||
#storage_version
|
||||
}
|
||||
|
||||
fn on_chain_storage_version() -> #pezframe_support::traits::StorageVersion {
|
||||
#pezframe_support::traits::StorageVersion::get::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `OnGenesis` for `Pezpallet`
|
||||
impl<#type_impl_gen> #pezframe_support::traits::OnGenesis
|
||||
for #pezpallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn on_genesis() {
|
||||
let storage_version: #pezframe_support::traits::StorageVersion = #storage_version;
|
||||
storage_version.put::<Self>();
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `PalletInfoAccess` for `Pezpallet`
|
||||
impl<#type_impl_gen> #pezframe_support::traits::PalletInfoAccess
|
||||
for #pezpallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn index() -> usize {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo as #pezframe_support::traits::PalletInfo
|
||||
>::index::<Self>()
|
||||
.expect("Pezpallet is part of the runtime because pezpallet `Config` trait is \
|
||||
implemented by the runtime")
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo as #pezframe_support::traits::PalletInfo
|
||||
>::name::<Self>()
|
||||
.expect("Pezpallet is part of the runtime because pezpallet `Config` trait is \
|
||||
implemented by the runtime")
|
||||
}
|
||||
|
||||
fn name_hash() -> [u8; 16] {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo as #pezframe_support::traits::PalletInfo
|
||||
>::name_hash::<Self>()
|
||||
.expect("Pezpallet is part of the runtime because pezpallet `Config` trait is \
|
||||
implemented by the runtime")
|
||||
}
|
||||
|
||||
fn module_name() -> &'static str {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo as #pezframe_support::traits::PalletInfo
|
||||
>::module_name::<Self>()
|
||||
.expect("Pezpallet is part of the runtime because pezpallet `Config` trait is \
|
||||
implemented by the runtime")
|
||||
}
|
||||
|
||||
fn crate_version() -> #pezframe_support::traits::CrateVersion {
|
||||
#pezframe_support::crate_to_crate_version!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::traits::PalletsInfoAccess
|
||||
for #pezpallet_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn count() -> usize { 1 }
|
||||
fn infos() -> #pezframe_support::__private::Vec<#pezframe_support::traits::PalletInfoData> {
|
||||
use #pezframe_support::traits::PalletInfoAccess;
|
||||
let item = #pezframe_support::traits::PalletInfoData {
|
||||
index: Self::index(),
|
||||
name: Self::name(),
|
||||
module_name: Self::module_name(),
|
||||
crate_version: Self::crate_version(),
|
||||
};
|
||||
#pezframe_support::__private::vec![item]
|
||||
}
|
||||
}
|
||||
|
||||
#storage_info
|
||||
#whitelisted_storage_keys_impl
|
||||
|
||||
impl<#type_use_gen> #pezpallet_ident<#type_use_gen> {
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
pub fn deprecation_info() -> #pezframe_support::__private::metadata_ir::ItemDeprecationInfoIR {
|
||||
#deprecation_status
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,946 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{
|
||||
counter_prefix,
|
||||
deprecation::extract_or_return_allow_attrs,
|
||||
pezpallet::{
|
||||
parse::{
|
||||
helper::two128_str,
|
||||
storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
|
||||
},
|
||||
Def,
|
||||
},
|
||||
};
|
||||
use quote::ToTokens;
|
||||
use std::{collections::HashMap, ops::IndexMut};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generate the prefix_ident related to the storage.
|
||||
/// prefix_ident is used for the prefix struct to be given to storage as first generic param.
|
||||
fn prefix_ident(storage: &StorageDef) -> syn::Ident {
|
||||
let storage_ident = &storage.ident;
|
||||
syn::Ident::new(&format!("_GeneratedPrefixForStorage{}", storage_ident), storage_ident.span())
|
||||
}
|
||||
|
||||
/// Generate the counter_prefix_ident related to the storage.
|
||||
/// counter_prefix_ident is used for the prefix struct to be given to counted storage map.
|
||||
fn counter_prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
|
||||
syn::Ident::new(
|
||||
&format!("_GeneratedCounterPrefixForStorage{}", storage_ident),
|
||||
storage_ident.span(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Check for duplicated storage prefixes. This step is necessary since users can specify an
|
||||
/// alternative storage prefix using the #[pezpallet::storage_prefix] syntax, and we need to ensure
|
||||
/// that the prefix specified by the user is not a duplicate of an existing one.
|
||||
fn check_prefix_duplicates(
|
||||
storage_def: &StorageDef,
|
||||
// A hashmap of all already used prefix and their associated error if duplication
|
||||
used_prefixes: &mut HashMap<String, syn::Error>,
|
||||
) -> syn::Result<()> {
|
||||
let prefix = storage_def.prefix();
|
||||
let dup_err = syn::Error::new(
|
||||
storage_def.prefix_span(),
|
||||
format!("Duplicate storage prefixes found for `{}`", prefix),
|
||||
);
|
||||
|
||||
if let Some(other_dup_err) = used_prefixes.insert(prefix.clone(), dup_err.clone()) {
|
||||
let mut err = dup_err;
|
||||
err.combine(other_dup_err);
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
if let Metadata::CountedMap { .. } = storage_def.metadata {
|
||||
let counter_prefix = counter_prefix(&prefix);
|
||||
let counter_dup_err = syn::Error::new(
|
||||
storage_def.prefix_span(),
|
||||
format!(
|
||||
"Duplicate storage prefixes found for `{}`, used for counter associated to \
|
||||
counted storage map",
|
||||
counter_prefix,
|
||||
),
|
||||
);
|
||||
|
||||
if let Some(other_dup_err) = used_prefixes.insert(counter_prefix, counter_dup_err.clone()) {
|
||||
let mut err = counter_dup_err;
|
||||
err.combine(other_dup_err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ResultOnEmptyStructMetadata {
|
||||
/// The Rust ident that is going to be used as the name of the OnEmpty struct.
|
||||
pub name: syn::Ident,
|
||||
/// The path to the error type being returned by the ResultQuery.
|
||||
pub error_path: syn::Path,
|
||||
/// The visibility of the OnEmpty struct.
|
||||
pub visibility: syn::Visibility,
|
||||
/// The type of the storage item.
|
||||
pub value_ty: syn::Type,
|
||||
/// The name of the pezpallet error enum variant that is going to be returned.
|
||||
pub variant_name: syn::Ident,
|
||||
/// The span used to report compilation errors about the OnEmpty struct.
|
||||
pub span: proc_macro2::Span,
|
||||
}
|
||||
|
||||
///
|
||||
/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
|
||||
/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
|
||||
/// * Add `#[allow(type_alias_bounds)]`
|
||||
pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMetadata>> {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let mut on_empty_struct_metadata = Vec::new();
|
||||
|
||||
for storage_def in def.storages.iter_mut() {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage_def.index];
|
||||
|
||||
let typ_item = match item {
|
||||
syn::Item::Type(t) => t,
|
||||
_ => unreachable!("Checked by def"),
|
||||
};
|
||||
|
||||
typ_item.attrs.push(syn::parse_quote!(#[allow(type_alias_bounds)]));
|
||||
|
||||
let typ_path = match &mut *typ_item.ty {
|
||||
syn::Type::Path(p) => p,
|
||||
_ => unreachable!("Checked by def"),
|
||||
};
|
||||
|
||||
let args = match &mut typ_path.path.segments[0].arguments {
|
||||
syn::PathArguments::AngleBracketed(args) => args,
|
||||
_ => unreachable!("Checked by def"),
|
||||
};
|
||||
|
||||
let prefix_ident = prefix_ident(storage_def);
|
||||
let type_use_gen = if def.config.has_instance {
|
||||
quote::quote_spanned!(storage_def.attr_span => T, I)
|
||||
} else {
|
||||
quote::quote_spanned!(storage_def.attr_span => T)
|
||||
};
|
||||
|
||||
let default_query_kind: syn::Type =
|
||||
syn::parse_quote!(#pezframe_support::storage::types::OptionQuery);
|
||||
let mut default_on_empty = |value_ty: syn::Type| -> syn::Type {
|
||||
if let Some(QueryKind::ResultQuery(error_path, variant_name)) =
|
||||
storage_def.query_kind.as_ref()
|
||||
{
|
||||
let on_empty_ident =
|
||||
quote::format_ident!("__Frame_Internal_Get{}Result", storage_def.ident);
|
||||
on_empty_struct_metadata.push(ResultOnEmptyStructMetadata {
|
||||
name: on_empty_ident.clone(),
|
||||
visibility: storage_def.vis.clone(),
|
||||
value_ty,
|
||||
error_path: error_path.clone(),
|
||||
variant_name: variant_name.clone(),
|
||||
span: storage_def.attr_span,
|
||||
});
|
||||
return syn::parse_quote!(#on_empty_ident);
|
||||
}
|
||||
syn::parse_quote!(#pezframe_support::traits::GetDefault)
|
||||
};
|
||||
let default_max_values: syn::Type = syn::parse_quote!(#pezframe_support::traits::GetDefault);
|
||||
|
||||
let set_result_query_type_parameter = |query_type: &mut syn::Type| -> syn::Result<()> {
|
||||
if let Some(QueryKind::ResultQuery(error_path, _)) = storage_def.query_kind.as_ref() {
|
||||
if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) =
|
||||
query_type
|
||||
{
|
||||
if let Some(seg) = segments.last_mut() {
|
||||
if let syn::PathArguments::AngleBracketed(
|
||||
syn::AngleBracketedGenericArguments { args, .. },
|
||||
) = &mut seg.arguments
|
||||
{
|
||||
args.clear();
|
||||
args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let msg = format!(
|
||||
"Invalid pezpallet::storage, unexpected type for query, expected ResultQuery \
|
||||
with 1 type parameter, found `{}`",
|
||||
query_type.to_token_stream().to_string()
|
||||
);
|
||||
return Err(syn::Error::new(query_type.span(), msg));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if let Some(named_generics) = storage_def.named_generics.clone() {
|
||||
args.args.clear();
|
||||
args.args.push(syn::parse_quote!( #prefix_ident<#type_use_gen> ));
|
||||
match named_generics {
|
||||
StorageGenerics::Value { value, query_kind, on_empty } => {
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
},
|
||||
StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } |
|
||||
StorageGenerics::CountedMap {
|
||||
hasher,
|
||||
key,
|
||||
value,
|
||||
query_kind,
|
||||
on_empty,
|
||||
max_values,
|
||||
} => {
|
||||
args.args.push(syn::GenericArgument::Type(hasher));
|
||||
args.args.push(syn::GenericArgument::Type(key));
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
},
|
||||
StorageGenerics::DoubleMap {
|
||||
hasher1,
|
||||
key1,
|
||||
hasher2,
|
||||
key2,
|
||||
value,
|
||||
query_kind,
|
||||
on_empty,
|
||||
max_values,
|
||||
} => {
|
||||
args.args.push(syn::GenericArgument::Type(hasher1));
|
||||
args.args.push(syn::GenericArgument::Type(key1));
|
||||
args.args.push(syn::GenericArgument::Type(hasher2));
|
||||
args.args.push(syn::GenericArgument::Type(key2));
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
},
|
||||
StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } |
|
||||
StorageGenerics::CountedNMap {
|
||||
keygen,
|
||||
value,
|
||||
query_kind,
|
||||
on_empty,
|
||||
max_values,
|
||||
} => {
|
||||
args.args.push(syn::GenericArgument::Type(keygen));
|
||||
args.args.push(syn::GenericArgument::Type(value.clone()));
|
||||
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
|
||||
set_result_query_type_parameter(&mut query_kind)?;
|
||||
args.args.push(syn::GenericArgument::Type(query_kind));
|
||||
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
|
||||
args.args.push(syn::GenericArgument::Type(max_values));
|
||||
},
|
||||
}
|
||||
} else {
|
||||
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
|
||||
|
||||
let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata {
|
||||
Metadata::Value { .. } => (1, 2, 3),
|
||||
Metadata::NMap { .. } | Metadata::CountedNMap { .. } => (2, 3, 4),
|
||||
Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5),
|
||||
Metadata::DoubleMap { .. } => (5, 6, 7),
|
||||
};
|
||||
|
||||
if storage_def.use_default_hasher {
|
||||
let hasher_indices: Vec<usize> = match storage_def.metadata {
|
||||
Metadata::Map { .. } | Metadata::CountedMap { .. } => vec![1],
|
||||
Metadata::DoubleMap { .. } => vec![1, 3],
|
||||
_ => vec![],
|
||||
};
|
||||
for hasher_idx in hasher_indices {
|
||||
args.args[hasher_idx] = syn::GenericArgument::Type(
|
||||
syn::parse_quote!(#pezframe_support::Blake2_128Concat),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if query_idx < args.args.len() {
|
||||
if let syn::GenericArgument::Type(query_kind) = args.args.index_mut(query_idx) {
|
||||
set_result_query_type_parameter(query_kind)?;
|
||||
}
|
||||
} else if let Some(QueryKind::ResultQuery(error_path, _)) =
|
||||
storage_def.query_kind.as_ref()
|
||||
{
|
||||
args.args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)))
|
||||
}
|
||||
|
||||
// Here, we only need to check if OnEmpty is *not* specified, and if so, then we have to
|
||||
// generate a default OnEmpty struct for it.
|
||||
if on_empty_idx >= args.args.len() &&
|
||||
matches!(storage_def.query_kind.as_ref(), Some(QueryKind::ResultQuery(_, _)))
|
||||
{
|
||||
let value_ty = match args.args[value_idx].clone() {
|
||||
syn::GenericArgument::Type(ty) => ty,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let on_empty = default_on_empty(value_ty);
|
||||
args.args.push(syn::GenericArgument::Type(on_empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(on_empty_struct_metadata)
|
||||
}
|
||||
|
||||
fn augment_final_docs(def: &mut Def) {
|
||||
// expand the docs with a new line showing the storage type (value, map, double map, etc), and
|
||||
// the key/value type(s).
|
||||
let mut push_string_literal = |doc_line: &str, storage: &mut StorageDef| {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage.index];
|
||||
let typ_item = match item {
|
||||
syn::Item::Type(t) => t,
|
||||
_ => unreachable!("Checked by def"),
|
||||
};
|
||||
typ_item.attrs.push(syn::parse_quote!(#[doc = ""]));
|
||||
typ_item.attrs.push(syn::parse_quote!(#[doc = #doc_line]));
|
||||
};
|
||||
def.storages.iter_mut().for_each(|storage| match &storage.metadata {
|
||||
Metadata::Value { value } => {
|
||||
let doc_line = format!(
|
||||
"Storage type is [`StorageValue`] with value type `{}`.",
|
||||
value.to_token_stream()
|
||||
);
|
||||
push_string_literal(&doc_line, storage);
|
||||
},
|
||||
Metadata::Map { key, value } => {
|
||||
let doc_line = format!(
|
||||
"Storage type is [`StorageMap`] with key type `{}` and value type `{}`.",
|
||||
key.to_token_stream(),
|
||||
value.to_token_stream()
|
||||
);
|
||||
push_string_literal(&doc_line, storage);
|
||||
},
|
||||
Metadata::DoubleMap { key1, key2, value } => {
|
||||
let doc_line = format!(
|
||||
"Storage type is [`StorageDoubleMap`] with key1 type {}, key2 type {} and value type {}.",
|
||||
key1.to_token_stream(),
|
||||
key2.to_token_stream(),
|
||||
value.to_token_stream()
|
||||
);
|
||||
push_string_literal(&doc_line, storage);
|
||||
},
|
||||
Metadata::NMap { keys, value, .. } => {
|
||||
let doc_line = format!(
|
||||
"Storage type is [`StorageNMap`] with keys type ({}) and value type {}.",
|
||||
keys.iter()
|
||||
.map(|k| k.to_token_stream().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
value.to_token_stream()
|
||||
);
|
||||
push_string_literal(&doc_line, storage);
|
||||
},
|
||||
Metadata::CountedNMap { keys, value, .. } => {
|
||||
let doc_line = format!(
|
||||
"Storage type is [`CountedStorageNMap`] with keys type ({}) and value type {}.",
|
||||
keys.iter()
|
||||
.map(|k| k.to_token_stream().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
value.to_token_stream()
|
||||
);
|
||||
push_string_literal(&doc_line, storage);
|
||||
},
|
||||
Metadata::CountedMap { key, value } => {
|
||||
let doc_line = format!(
|
||||
"Storage type is [`CountedStorageMap`] with key type {} and value type {}.",
|
||||
key.to_token_stream(),
|
||||
value.to_token_stream()
|
||||
);
|
||||
push_string_literal(&doc_line, storage);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
/// * generate StoragePrefix structs (e.g. for a storage `MyStorage` a struct with the name
|
||||
/// `_GeneratedPrefixForStorage$NameOfStorage` is generated) and implements StorageInstance trait.
|
||||
/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
|
||||
/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
|
||||
/// * Add `#[allow(type_alias_bounds)]` on storages type alias
|
||||
/// * generate metadatas
|
||||
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let on_empty_struct_metadata = match process_generics(def) {
|
||||
Ok(idents) => idents,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
augment_final_docs(def);
|
||||
|
||||
// Check for duplicate prefixes
|
||||
let mut prefix_set = HashMap::new();
|
||||
let mut errors = def
|
||||
.storages
|
||||
.iter()
|
||||
.filter_map(|storage_def| check_prefix_duplicates(storage_def, &mut prefix_set).err());
|
||||
if let Some(mut final_error) = errors.next() {
|
||||
errors.for_each(|error| final_error.combine(error));
|
||||
return final_error.into_compile_error();
|
||||
}
|
||||
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let mut entries_builder = vec![];
|
||||
for storage in def.storages.iter() {
|
||||
let no_docs = vec![];
|
||||
let docs = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &storage.docs };
|
||||
|
||||
let ident = &storage.ident;
|
||||
let gen = &def.type_use_generics(storage.attr_span);
|
||||
let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
|
||||
|
||||
let cfg_attrs = &storage.cfg_attrs;
|
||||
let deprecation = match crate::deprecation::get_deprecation(
|
||||
"e::quote! { #pezframe_support },
|
||||
&storage.attrs,
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs: Vec<syn::Attribute> =
|
||||
extract_or_return_allow_attrs(&storage.attrs).collect();
|
||||
|
||||
entries_builder.push(quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
#(#maybe_allow_attrs)*
|
||||
(|entries: &mut #pezframe_support::__private::Vec<_>| {
|
||||
{
|
||||
<#full_ident as #pezframe_support::storage::StorageEntryMetadataBuilder>::build_metadata(
|
||||
#deprecation,
|
||||
#pezframe_support::__private::vec![
|
||||
#( #docs, )*
|
||||
],
|
||||
entries,
|
||||
);
|
||||
}
|
||||
})
|
||||
))
|
||||
}
|
||||
|
||||
let getters = def.storages.iter().map(|storage| {
|
||||
if let Some(getter) = &storage.getter {
|
||||
let completed_where_clause =
|
||||
super::merge_where_clauses(&[&storage.where_clause, &def.config.where_clause]);
|
||||
// Extracts #[allow] attributes, necessary so that we don't run into compiler warnings
|
||||
let maybe_allow_attrs: Vec<syn::Attribute> =
|
||||
extract_or_return_allow_attrs(&storage.attrs).collect();
|
||||
let ident = &storage.ident;
|
||||
let gen = &def.type_use_generics(storage.attr_span);
|
||||
let type_impl_gen = &def.type_impl_generics(storage.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(storage.attr_span);
|
||||
let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
|
||||
|
||||
let cfg_attrs = &storage.cfg_attrs;
|
||||
|
||||
// If the storage item is public, link it and otherwise just mention it.
|
||||
//
|
||||
// We can not just copy the docs from a non-public type as it may links to internal
|
||||
// types which makes the compiler very unhappy :(
|
||||
let getter_doc_line = if matches!(storage.vis, syn::Visibility::Public(_)) {
|
||||
format!("An auto-generated getter for [`{}`].", storage.ident)
|
||||
} else {
|
||||
format!("An auto-generated getter for `{}`.", storage.ident)
|
||||
};
|
||||
|
||||
match &storage.metadata {
|
||||
Metadata::Value { value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) => {
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
)
|
||||
},
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#[doc = #getter_doc_line]
|
||||
#(#maybe_allow_attrs)*
|
||||
pub fn #getter() -> #query {
|
||||
<
|
||||
#full_ident as #pezframe_support::storage::StorageValue<#value>
|
||||
>::get()
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
Metadata::Map { key, value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) => {
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
)
|
||||
},
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#[doc = #getter_doc_line]
|
||||
#(#maybe_allow_attrs)*
|
||||
pub fn #getter<KArg>(k: KArg) -> #query where
|
||||
KArg: #pezframe_support::__private::codec::EncodeLike<#key>,
|
||||
{
|
||||
<
|
||||
#full_ident as #pezframe_support::storage::StorageMap<#key, #value>
|
||||
>::get(k)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
Metadata::CountedMap { key, value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) => {
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
)
|
||||
},
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#[doc = #getter_doc_line]
|
||||
#(#maybe_allow_attrs)*
|
||||
pub fn #getter<KArg>(k: KArg) -> #query where
|
||||
KArg: #pezframe_support::__private::codec::EncodeLike<#key>,
|
||||
{
|
||||
// NOTE: we can't use any trait here because CountedStorageMap
|
||||
// doesn't implement any.
|
||||
<#full_ident>::get(k)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
Metadata::DoubleMap { key1, key2, value } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) => {
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
)
|
||||
},
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#[doc = #getter_doc_line]
|
||||
#(#maybe_allow_attrs)*
|
||||
pub fn #getter<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #query where
|
||||
KArg1: #pezframe_support::__private::codec::EncodeLike<#key1>,
|
||||
KArg2: #pezframe_support::__private::codec::EncodeLike<#key2>,
|
||||
{
|
||||
<
|
||||
#full_ident as
|
||||
#pezframe_support::storage::StorageDoubleMap<#key1, #key2, #value>
|
||||
>::get(k1, k2)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
Metadata::NMap { keygen, value, .. } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) => {
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
)
|
||||
},
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#[doc = #getter_doc_line]
|
||||
#(#maybe_allow_attrs)*
|
||||
pub fn #getter<KArg>(key: KArg) -> #query
|
||||
where
|
||||
KArg: #pezframe_support::storage::types::EncodeLikeTuple<
|
||||
<#keygen as #pezframe_support::storage::types::KeyGenerator>::KArg
|
||||
>
|
||||
+ #pezframe_support::storage::types::TupleToEncodedIter,
|
||||
{
|
||||
<
|
||||
#full_ident as
|
||||
#pezframe_support::storage::StorageNMap<#keygen, #value>
|
||||
>::get(key)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
Metadata::CountedNMap { keygen, value, .. } => {
|
||||
let query = match storage.query_kind.as_ref().expect("Checked by def") {
|
||||
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
|
||||
Option<#value>
|
||||
),
|
||||
QueryKind::ResultQuery(error_path, _) => {
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
Result<#value, #error_path>
|
||||
)
|
||||
},
|
||||
QueryKind::ValueQuery => quote::quote!(#value),
|
||||
};
|
||||
quote::quote_spanned!(storage.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #completed_where_clause {
|
||||
#[doc = #getter_doc_line]
|
||||
#(#maybe_allow_attrs)*
|
||||
pub fn #getter<KArg>(key: KArg) -> #query
|
||||
where
|
||||
KArg: #pezframe_support::storage::types::EncodeLikeTuple<
|
||||
<#keygen as #pezframe_support::storage::types::KeyGenerator>::KArg
|
||||
>
|
||||
+ #pezframe_support::storage::types::TupleToEncodedIter,
|
||||
{
|
||||
// NOTE: we can't use any trait here because CountedStorageNMap
|
||||
// doesn't implement any.
|
||||
<#full_ident>::get(key)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
});
|
||||
|
||||
let prefix_structs = def.storages.iter().map(|storage_def| {
|
||||
let type_impl_gen = &def.type_impl_generics(storage_def.attr_span);
|
||||
let type_use_gen = &def.type_use_generics(storage_def.attr_span);
|
||||
let prefix_struct_ident = prefix_ident(storage_def);
|
||||
let prefix_struct_vis = &storage_def.vis;
|
||||
let prefix_struct_const = storage_def.prefix();
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
let cfg_attrs = &storage_def.cfg_attrs;
|
||||
|
||||
let maybe_counter = match storage_def.metadata {
|
||||
Metadata::CountedMap { .. } => {
|
||||
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
|
||||
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
|
||||
let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
|
||||
quote::quote_spanned!(storage_def.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
#[doc(hidden)]
|
||||
#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
|
||||
core::marker::PhantomData<(#type_use_gen,)>
|
||||
);
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezframe_support::traits::StorageInstance
|
||||
for #counter_prefix_struct_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn pezpallet_prefix() -> &'static str {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
|
||||
fn pezpallet_prefix_hash() -> [u8; 16] {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name_hash::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name_hash found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
|
||||
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
|
||||
fn storage_prefix_hash() -> [u8; 16] {
|
||||
#storage_prefix_hash
|
||||
}
|
||||
}
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezframe_support::storage::types::CountedStorageMapInstance
|
||||
for #prefix_struct_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
|
||||
}
|
||||
)
|
||||
},
|
||||
Metadata::CountedNMap { .. } => {
|
||||
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
|
||||
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
|
||||
let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
|
||||
quote::quote_spanned!(storage_def.attr_span =>
|
||||
#(#cfg_attrs)*
|
||||
#[doc(hidden)]
|
||||
#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
|
||||
core::marker::PhantomData<(#type_use_gen,)>
|
||||
);
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezframe_support::traits::StorageInstance
|
||||
for #counter_prefix_struct_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn pezpallet_prefix() -> &'static str {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
fn pezpallet_prefix_hash() -> [u8; 16] {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name_hash::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name_hash found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
|
||||
fn storage_prefix_hash() -> [u8; 16] {
|
||||
#storage_prefix_hash
|
||||
}
|
||||
}
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezframe_support::storage::types::CountedStorageNMapInstance
|
||||
for #prefix_struct_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
|
||||
}
|
||||
)
|
||||
},
|
||||
_ => proc_macro2::TokenStream::default(),
|
||||
};
|
||||
|
||||
let storage_prefix_hash = two128_str(&prefix_struct_const);
|
||||
quote::quote_spanned!(storage_def.attr_span =>
|
||||
#maybe_counter
|
||||
|
||||
#(#cfg_attrs)*
|
||||
#[doc(hidden)]
|
||||
#prefix_struct_vis struct #prefix_struct_ident<#type_use_gen>(
|
||||
core::marker::PhantomData<(#type_use_gen,)>
|
||||
);
|
||||
#(#cfg_attrs)*
|
||||
impl<#type_impl_gen> #pezframe_support::traits::StorageInstance
|
||||
for #prefix_struct_ident<#type_use_gen>
|
||||
#config_where_clause
|
||||
{
|
||||
fn pezpallet_prefix() -> &'static str {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
|
||||
fn pezpallet_prefix_hash() -> [u8; 16] {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name_hash::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name_hash found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
|
||||
const STORAGE_PREFIX: &'static str = #prefix_struct_const;
|
||||
fn storage_prefix_hash() -> [u8; 16] {
|
||||
#storage_prefix_hash
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
let on_empty_structs = on_empty_struct_metadata.into_iter().map(|metadata| {
|
||||
use crate::pezpallet::parse::GenericKind;
|
||||
use syn::{GenericArgument, Path, PathArguments, PathSegment, Type, TypePath};
|
||||
|
||||
let ResultOnEmptyStructMetadata {
|
||||
name,
|
||||
visibility,
|
||||
value_ty,
|
||||
error_path,
|
||||
variant_name,
|
||||
span,
|
||||
} = metadata;
|
||||
|
||||
let generic_kind = match error_path.segments.last() {
|
||||
Some(PathSegment { arguments: PathArguments::AngleBracketed(args), .. }) => {
|
||||
let (has_config, has_instance) =
|
||||
args.args.iter().fold((false, false), |(has_config, has_instance), arg| {
|
||||
match arg {
|
||||
GenericArgument::Type(Type::Path(TypePath {
|
||||
path: Path { segments, .. },
|
||||
..
|
||||
})) => {
|
||||
let maybe_config =
|
||||
segments.first().map_or(false, |seg| seg.ident == "T");
|
||||
let maybe_instance =
|
||||
segments.first().map_or(false, |seg| seg.ident == "I");
|
||||
|
||||
(has_config || maybe_config, has_instance || maybe_instance)
|
||||
},
|
||||
_ => (has_config, has_instance),
|
||||
}
|
||||
});
|
||||
GenericKind::from_gens(has_config, has_instance).unwrap_or(GenericKind::None)
|
||||
},
|
||||
_ => GenericKind::None,
|
||||
};
|
||||
let type_impl_gen = generic_kind.type_impl_gen(proc_macro2::Span::call_site());
|
||||
let config_where_clause = &def.config.where_clause;
|
||||
|
||||
quote::quote_spanned!(span =>
|
||||
#[doc(hidden)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#visibility struct #name;
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::traits::Get<Result<#value_ty, #error_path>>
|
||||
for #name
|
||||
#config_where_clause
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
fn get() -> Result<#value_ty, #error_path> {
|
||||
Err(<#error_path>::#variant_name)
|
||||
}
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
// aggregated where clause of all storage types and the whole pezpallet.
|
||||
let mut where_clauses = vec![&def.config.where_clause];
|
||||
where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
|
||||
let completed_where_clause = super::merge_where_clauses(&where_clauses);
|
||||
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
|
||||
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
|
||||
|
||||
let try_decode_entire_state = {
|
||||
let mut storage_names = def
|
||||
.storages
|
||||
.iter()
|
||||
.filter_map(|storage| {
|
||||
// A little hacky; don't generate for cfg gated storages to not get compile errors
|
||||
// when building "frame-feature-testing" gated storages in the "pezframe-support-test"
|
||||
// crate.
|
||||
if storage.try_decode && storage.cfg_attrs.is_empty() {
|
||||
let ident = &storage.ident;
|
||||
let gen = &def.type_use_generics(storage.attr_span);
|
||||
Some(quote::quote_spanned!(storage.attr_span => #ident<#gen> ))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
storage_names.sort_by_cached_key(|ident| ident.to_string());
|
||||
|
||||
quote::quote!(
|
||||
#pezframe_support::try_runtime_enabled! {
|
||||
#[allow(deprecated)]
|
||||
impl<#type_impl_gen> #pezframe_support::traits::TryDecodeEntireStorage
|
||||
for #pezpallet_ident<#type_use_gen> #completed_where_clause
|
||||
{
|
||||
fn try_decode_entire_state() -> Result<usize, #pezframe_support::__private::Vec<#pezframe_support::traits::TryDecodeEntireStorageError>> {
|
||||
let pezpallet_name = <<T as #pezframe_system::Config>::PalletInfo as #pezframe_support::traits::PalletInfo>
|
||||
::name::<#pezpallet_ident<#type_use_gen>>()
|
||||
.expect("Every active pezpallet has a name in the runtime; qed");
|
||||
|
||||
#pezframe_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode pezpallet: {pezpallet_name}");
|
||||
|
||||
// NOTE: for now, we have to exclude storage items that are feature gated.
|
||||
let mut errors = #pezframe_support::__private::Vec::new();
|
||||
let mut decoded = 0usize;
|
||||
|
||||
#(
|
||||
#pezframe_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode storage: \
|
||||
{pezpallet_name}::{}", stringify!(#storage_names));
|
||||
|
||||
match <#storage_names as #pezframe_support::traits::TryDecodeEntireStorage>::try_decode_entire_state() {
|
||||
Ok(count) => {
|
||||
decoded += count;
|
||||
},
|
||||
Err(err) => {
|
||||
errors.extend(err);
|
||||
},
|
||||
}
|
||||
)*
|
||||
|
||||
if errors.is_empty() {
|
||||
Ok(decoded)
|
||||
} else {
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
quote::quote!(
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen>
|
||||
#completed_where_clause
|
||||
{
|
||||
#[doc(hidden)]
|
||||
pub fn storage_metadata() -> #pezframe_support::__private::metadata_ir::PalletStorageMetadataIR {
|
||||
#pezframe_support::__private::metadata_ir::PalletStorageMetadataIR {
|
||||
prefix: <
|
||||
<T as #pezframe_system::Config>::PalletInfo as
|
||||
#pezframe_support::traits::PalletInfo
|
||||
>::name::<#pezpallet_ident<#type_use_gen>>()
|
||||
.expect("No name found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`."),
|
||||
entries: {
|
||||
#[allow(unused_mut)]
|
||||
let mut entries = #pezframe_support::__private::vec![];
|
||||
#( #entries_builder(&mut entries); )*
|
||||
entries
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#( #getters )*
|
||||
#( #prefix_structs )*
|
||||
#( #on_empty_structs )*
|
||||
|
||||
#try_decode_entire_state
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
//! Contains logic for expanding task-related items.
|
||||
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Home of the expansion code for the Tasks API
|
||||
|
||||
use crate::pezpallet::{parse::tasks::*, Def};
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{parse_quote_spanned, spanned::Spanned};
|
||||
|
||||
impl TaskEnumDef {
|
||||
/// Since we optionally allow users to manually specify a `#[pezpallet::task_enum]`, in the
|
||||
/// event they _don't_ specify one (which is actually the most common behavior) we have to
|
||||
/// generate one based on the existing [`TasksDef`]. This method performs that generation.
|
||||
pub fn generate(tasks: &TasksDef, def: &Def) -> Self {
|
||||
// We use the span of the attribute to indicate that the error comes from code generated
|
||||
// for the specific section, otherwise the item impl.
|
||||
let span = tasks
|
||||
.tasks_attr
|
||||
.as_ref()
|
||||
.map_or_else(|| tasks.item_impl.span(), |attr| attr.span());
|
||||
|
||||
let type_decl_bounded_generics = def.type_decl_bounded_generics(span);
|
||||
|
||||
let variants = if tasks.tasks_attr.is_some() {
|
||||
tasks
|
||||
.tasks
|
||||
.iter()
|
||||
.map(|task| {
|
||||
let ident = &task.item.sig.ident;
|
||||
let ident =
|
||||
format_ident!("{}", ident.to_string().to_class_case(), span = ident.span());
|
||||
|
||||
let args = task.item.sig.inputs.iter().collect::<Vec<_>>();
|
||||
|
||||
if args.is_empty() {
|
||||
quote!(#ident)
|
||||
} else {
|
||||
quote!(#ident {
|
||||
#(#args),*
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
parse_quote_spanned! { span =>
|
||||
/// Auto-generated enum that encapsulates all tasks defined by this pezpallet.
|
||||
///
|
||||
/// Conceptually similar to the [`Call`] enum, but for tasks. This is only
|
||||
/// generated if there are tasks present in this pezpallet.
|
||||
#[pezpallet::task_enum]
|
||||
pub enum Task<#type_decl_bounded_generics> {
|
||||
#(
|
||||
#variants,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskEnumDef {
|
||||
fn expand_to_tokens(&self, def: &Def) -> TokenStream2 {
|
||||
if let Some(attr) = &self.attr {
|
||||
let ident = &self.item_enum.ident;
|
||||
let vis = &self.item_enum.vis;
|
||||
let attrs = &self.item_enum.attrs;
|
||||
let generics = &self.item_enum.generics;
|
||||
let variants = &self.item_enum.variants;
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let type_use_generics = &def.type_use_generics(attr.span());
|
||||
let type_impl_generics = &def.type_impl_generics(attr.span());
|
||||
|
||||
// `item_enum` is short-hand / generated enum
|
||||
quote! {
|
||||
#(#attrs)*
|
||||
#[derive(
|
||||
#pezframe_support::CloneNoBound,
|
||||
#pezframe_support::EqNoBound,
|
||||
#pezframe_support::PartialEqNoBound,
|
||||
#pezframe_support::pezpallet_prelude::Encode,
|
||||
#pezframe_support::pezpallet_prelude::Decode,
|
||||
#pezframe_support::pezpallet_prelude::DecodeWithMemTracking,
|
||||
#pezframe_support::pezpallet_prelude::TypeInfo,
|
||||
)]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(skip_type_params(#type_use_generics))]
|
||||
#vis enum #ident #generics {
|
||||
#variants
|
||||
#[doc(hidden)]
|
||||
#[codec(skip)]
|
||||
__Ignore(core::marker::PhantomData<(#type_use_generics)>, #pezframe_support::Never),
|
||||
}
|
||||
|
||||
impl<#type_impl_generics> core::fmt::Debug for #ident<#type_use_generics> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct(stringify!(#ident)).field("value", self).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// `item_enum` is a manually specified enum (no attribute)
|
||||
self.item_enum.to_token_stream()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TasksDef {
|
||||
fn expand_to_tokens(&self, def: &Def) -> TokenStream2 {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let enum_ident = syn::Ident::new("Task", self.enum_ident.span());
|
||||
let enum_arguments = &self.enum_arguments;
|
||||
let enum_use = quote!(#enum_ident #enum_arguments);
|
||||
|
||||
let task_fn_idents = self
|
||||
.tasks
|
||||
.iter()
|
||||
.map(|task| {
|
||||
format_ident!(
|
||||
"{}",
|
||||
&task.item.sig.ident.to_string().to_class_case(),
|
||||
span = task.item.sig.ident.span()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let task_indices = self.tasks.iter().map(|task| &task.index_attr.meta.index);
|
||||
let task_conditions = self.tasks.iter().map(|task| &task.condition_attr.meta.expr);
|
||||
let task_weights = self.tasks.iter().map(|task| &task.weight_attr.meta.expr);
|
||||
let task_iters = self.tasks.iter().map(|task| &task.list_attr.meta.expr);
|
||||
|
||||
let task_fn_impls = self.tasks.iter().map(|task| {
|
||||
let mut task_fn_impl = task.item.clone();
|
||||
task_fn_impl.attrs = vec![];
|
||||
task_fn_impl
|
||||
});
|
||||
|
||||
let task_fn_names = self.tasks.iter().map(|task| &task.item.sig.ident);
|
||||
let task_arg_names = self.tasks.iter().map(|task| &task.arg_names).collect::<Vec<_>>();
|
||||
|
||||
let impl_generics = &self.item_impl.generics;
|
||||
quote! {
|
||||
impl #impl_generics #enum_use
|
||||
{
|
||||
#(#task_fn_impls)*
|
||||
}
|
||||
|
||||
impl #impl_generics #pezframe_support::traits::Task for #enum_use
|
||||
{
|
||||
type Enumeration = #pezframe_support::__private::IntoIter<#enum_use>;
|
||||
|
||||
fn iter() -> Self::Enumeration {
|
||||
let mut all_tasks = #pezframe_support::__private::vec![];
|
||||
#(all_tasks
|
||||
.extend(#task_iters.map(|(#(#task_arg_names),*)| #enum_ident::#task_fn_idents { #(#task_arg_names: #task_arg_names.clone()),* })
|
||||
.collect::<#pezframe_support::__private::Vec<_>>());
|
||||
)*
|
||||
all_tasks.into_iter()
|
||||
}
|
||||
|
||||
fn task_index(&self) -> u32 {
|
||||
match self.clone() {
|
||||
#(#enum_ident::#task_fn_idents { .. } => #task_indices,)*
|
||||
Task::__Ignore(_, _) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
match self.clone() {
|
||||
#(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => (#task_conditions)(#(#task_arg_names),* ),)*
|
||||
Task::__Ignore(_, _) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&self) -> Result<(), #pezframe_support::pezpallet_prelude::DispatchError> {
|
||||
match self.clone() {
|
||||
#(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => {
|
||||
<#enum_use>::#task_fn_names(#( #task_arg_names, )* )
|
||||
},)*
|
||||
Task::__Ignore(_, _) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn weight(&self) -> #pezframe_support::pezpallet_prelude::Weight {
|
||||
match self.clone() {
|
||||
#(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => #task_weights,)*
|
||||
Task::__Ignore(_, _) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate code related to tasks.
|
||||
pub fn expand_tasks(def: &Def) -> TokenStream2 {
|
||||
let Some(tasks_def) = &def.tasks else {
|
||||
return quote!();
|
||||
};
|
||||
|
||||
let default_task_enum = TaskEnumDef::generate(&tasks_def, def);
|
||||
|
||||
let task_enum = def.task_enum.as_ref().unwrap_or_else(|| &default_task_enum);
|
||||
|
||||
let tasks_expansion = tasks_def.expand_to_tokens(def);
|
||||
let task_enum_expansion = task_enum.expand_to_tokens(def);
|
||||
|
||||
quote! {
|
||||
#tasks_expansion
|
||||
#task_enum_expansion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{
|
||||
pezpallet::{CompositeKeyword, Def},
|
||||
COUNTER,
|
||||
};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Generate the `tt_default_parts` macro.
|
||||
pub fn expand_tt_default_parts(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
let default_parts_unique_id =
|
||||
syn::Ident::new(&format!("__tt_default_parts_{}", count), def.item.span());
|
||||
let extra_parts_unique_id =
|
||||
syn::Ident::new(&format!("__tt_extra_parts_{}", count), def.item.span());
|
||||
let default_parts_unique_id_v2 =
|
||||
syn::Ident::new(&format!("__tt_default_parts_v2_{}", count), def.item.span());
|
||||
|
||||
let call_part = def.call.as_ref().map(|_| quote::quote!(Call,));
|
||||
|
||||
let task_part = def.tasks.as_ref().map(|_| quote::quote!(Task,));
|
||||
|
||||
let storage_part = (!def.storages.is_empty()).then(|| quote::quote!(Storage,));
|
||||
|
||||
let event_part = def.event.as_ref().map(|event| {
|
||||
let gen = event.gen_kind.is_generic().then(|| quote::quote!( <T> ));
|
||||
quote::quote!( Event #gen , )
|
||||
});
|
||||
|
||||
let error_part = def.error.as_ref().map(|_| quote::quote!(Error<T>,));
|
||||
|
||||
let origin_part = def.origin.as_ref().map(|origin| {
|
||||
let gen = origin.is_generic.then(|| quote::quote!( <T> ));
|
||||
quote::quote!( Origin #gen , )
|
||||
});
|
||||
|
||||
let config_part = def.genesis_config.as_ref().map(|genesis_config| {
|
||||
let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!( <T> ));
|
||||
quote::quote!( Config #gen , )
|
||||
});
|
||||
|
||||
let inherent_part = def.inherent.as_ref().map(|_| quote::quote!(Inherent,));
|
||||
|
||||
let validate_unsigned_part =
|
||||
def.validate_unsigned.as_ref().map(|_| quote::quote!(ValidateUnsigned,));
|
||||
|
||||
let freeze_reason_part = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_)))
|
||||
.then_some(quote::quote!(FreezeReason,));
|
||||
|
||||
let hold_reason_part = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_)))
|
||||
.then_some(quote::quote!(HoldReason,));
|
||||
|
||||
let lock_id_part = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_)))
|
||||
.then_some(quote::quote!(LockId,));
|
||||
|
||||
let slash_reason_part = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_)))
|
||||
.then_some(quote::quote!(SlashReason,));
|
||||
|
||||
let call_part_v2 = def.call.as_ref().map(|_| quote::quote!(+ Call));
|
||||
|
||||
let task_part_v2 = def.tasks.as_ref().map(|_| quote::quote!(+ Task));
|
||||
|
||||
let storage_part_v2 = (!def.storages.is_empty()).then(|| quote::quote!(+ Storage));
|
||||
|
||||
let event_part_v2 = def.event.as_ref().map(|event| {
|
||||
let gen = event.gen_kind.is_generic().then(|| quote::quote!(<T>));
|
||||
quote::quote!(+ Event #gen)
|
||||
});
|
||||
|
||||
let error_part_v2 = def.error.as_ref().map(|_| quote::quote!(+ Error<T>));
|
||||
|
||||
let origin_part_v2 = def.origin.as_ref().map(|origin| {
|
||||
let gen = origin.is_generic.then(|| quote::quote!(<T>));
|
||||
quote::quote!(+ Origin #gen)
|
||||
});
|
||||
|
||||
let config_part_v2 = def.genesis_config.as_ref().map(|genesis_config| {
|
||||
let gen = genesis_config.gen_kind.is_generic().then(|| quote::quote!(<T>));
|
||||
quote::quote!(+ Config #gen)
|
||||
});
|
||||
|
||||
let inherent_part_v2 = def.inherent.as_ref().map(|_| quote::quote!(+ Inherent));
|
||||
|
||||
let validate_unsigned_part_v2 =
|
||||
def.validate_unsigned.as_ref().map(|_| quote::quote!(+ ValidateUnsigned));
|
||||
|
||||
let freeze_reason_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::FreezeReason(_)))
|
||||
.then_some(quote::quote!(+ FreezeReason));
|
||||
|
||||
let hold_reason_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::HoldReason(_)))
|
||||
.then_some(quote::quote!(+ HoldReason));
|
||||
|
||||
let lock_id_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::LockId(_)))
|
||||
.then_some(quote::quote!(+ LockId));
|
||||
|
||||
let slash_reason_part_v2 = def
|
||||
.composites
|
||||
.iter()
|
||||
.any(|c| matches!(c.composite_keyword, CompositeKeyword::SlashReason(_)))
|
||||
.then_some(quote::quote!(+ SlashReason));
|
||||
|
||||
quote::quote!(
|
||||
// This macro follows the conventions as laid out by the `tt-call` crate. It does not
|
||||
// accept any arguments and simply returns the pezpallet parts, separated by commas, then
|
||||
// wrapped inside of braces and finally prepended with double colons, to the caller inside
|
||||
// of a key named `tokens`.
|
||||
//
|
||||
// We need to accept a path argument here, because this macro gets expanded on the
|
||||
// crate that called the `construct_runtime!` macro, and the actual path is unknown.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #default_parts_unique_id {
|
||||
{
|
||||
$caller:tt
|
||||
your_tt_return = [{ $my_tt_return:path }]
|
||||
} => {
|
||||
$my_tt_return! {
|
||||
$caller
|
||||
tokens = [{
|
||||
expanded::{
|
||||
Pezpallet, #call_part #storage_part #event_part #error_part #origin_part #config_part
|
||||
#inherent_part #validate_unsigned_part #freeze_reason_part #task_part
|
||||
#hold_reason_part #lock_id_part #slash_reason_part
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use #default_parts_unique_id as tt_default_parts;
|
||||
|
||||
|
||||
// This macro is similar to the `tt_default_parts!`. It expands the pallets that are declared
|
||||
// explicitly (`System: pezframe_system::{Pezpallet, Call}`) with extra parts.
|
||||
//
|
||||
// For example, after expansion an explicit pezpallet would look like:
|
||||
// `System: expanded::{Error} ::{Pezpallet, Call}`.
|
||||
//
|
||||
// The `expanded` keyword is a marker of the final state of the `construct_runtime!`.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #extra_parts_unique_id {
|
||||
{
|
||||
$caller:tt
|
||||
your_tt_return = [{ $my_tt_return:path }]
|
||||
} => {
|
||||
$my_tt_return! {
|
||||
$caller
|
||||
tokens = [{
|
||||
expanded::{
|
||||
#error_part
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use #extra_parts_unique_id as tt_extra_parts;
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #default_parts_unique_id_v2 {
|
||||
{
|
||||
$caller:tt
|
||||
your_tt_return = [{ $my_tt_return:path }]
|
||||
} => {
|
||||
$my_tt_return! {
|
||||
$caller
|
||||
tokens = [{
|
||||
+ Pezpallet #call_part_v2 #storage_part_v2 #event_part_v2 #error_part_v2 #origin_part_v2 #config_part_v2
|
||||
#inherent_part_v2 #validate_unsigned_part_v2 #freeze_reason_part_v2 #task_part_v2
|
||||
#hold_reason_part_v2 #lock_id_part_v2 #slash_reason_part_v2
|
||||
}]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub use #default_parts_unique_id_v2 as tt_default_parts_v2;
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::Def;
|
||||
|
||||
///
|
||||
/// * Generate the struct
|
||||
/// * implement the `Get<..>` on it
|
||||
/// * Rename the name of the function to internal name
|
||||
pub fn expand_type_values(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
let mut expand = quote::quote!();
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
|
||||
for type_value in &def.type_values {
|
||||
let fn_name_str = &type_value.ident.to_string();
|
||||
let fn_name_snakecase = inflector::cases::snakecase::to_snake_case(fn_name_str);
|
||||
let fn_ident_renamed = syn::Ident::new(
|
||||
&format!("__type_value_for_{}", fn_name_snakecase),
|
||||
type_value.ident.span(),
|
||||
);
|
||||
|
||||
let type_value_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def").1[type_value.index];
|
||||
if let syn::Item::Fn(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by error parser")
|
||||
}
|
||||
};
|
||||
|
||||
// Rename the type_value function name
|
||||
type_value_item.sig.ident = fn_ident_renamed.clone();
|
||||
|
||||
let vis = &type_value.vis;
|
||||
let ident = &type_value.ident;
|
||||
let type_ = &type_value.type_;
|
||||
let where_clause = &type_value.where_clause;
|
||||
|
||||
let (struct_impl_gen, struct_use_gen) = if type_value.is_generic {
|
||||
(
|
||||
def.type_impl_generics(type_value.attr_span),
|
||||
def.type_use_generics(type_value.attr_span),
|
||||
)
|
||||
} else {
|
||||
(Default::default(), Default::default())
|
||||
};
|
||||
|
||||
let docs = &type_value.docs;
|
||||
|
||||
expand.extend(quote::quote_spanned!(type_value.attr_span =>
|
||||
#( #[doc = #docs] )*
|
||||
#vis struct #ident<#struct_use_gen>(core::marker::PhantomData<((), #struct_use_gen)>);
|
||||
impl<#struct_impl_gen> #pezframe_support::traits::Get<#type_> for #ident<#struct_use_gen>
|
||||
#where_clause
|
||||
{
|
||||
fn get() -> #type_ {
|
||||
#fn_ident_renamed::<#struct_use_gen>()
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
expand
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::{pezpallet::Def, COUNTER};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{spanned::Spanned, Ident};
|
||||
|
||||
pub fn expand_validate_unsigned(def: &mut Def) -> TokenStream {
|
||||
let count = COUNTER.with(|counter| counter.borrow_mut().inc());
|
||||
let macro_ident =
|
||||
Ident::new(&format!("__is_validate_unsigned_part_defined_{}", count), def.item.span());
|
||||
|
||||
let maybe_compile_error = if def.validate_unsigned.is_none() {
|
||||
quote! {
|
||||
compile_error!(concat!(
|
||||
"`",
|
||||
stringify!($pezpallet_name),
|
||||
"` does not have #[pezpallet::validate_unsigned] defined, perhaps you should \
|
||||
remove `ValidateUnsigned` from construct_runtime?",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
pub mod __bizinikiwi_validate_unsigned_check {
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! #macro_ident {
|
||||
($pezpallet_name:ident) => {
|
||||
#maybe_compile_error
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use #macro_ident as is_validate_unsigned_part_defined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pezpallet::{parse::view_functions::ViewFunctionDef, Def};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
pub fn expand_view_functions(def: &Def) -> TokenStream {
|
||||
let (span, where_clause, view_fns) = match def.view_functions.as_ref() {
|
||||
Some(view_fns) =>
|
||||
(view_fns.attr_span, view_fns.where_clause.clone(), view_fns.view_functions.clone()),
|
||||
None => (def.item.span(), def.config.where_clause.clone(), Vec::new()),
|
||||
};
|
||||
|
||||
let view_function_prefix_impl =
|
||||
expand_view_function_prefix_impl(def, span, where_clause.as_ref());
|
||||
|
||||
let view_fn_impls = view_fns
|
||||
.iter()
|
||||
.map(|view_fn| expand_view_function(def, span, where_clause.as_ref(), view_fn));
|
||||
let impl_dispatch_view_function =
|
||||
impl_dispatch_view_function(def, span, where_clause.as_ref(), &view_fns);
|
||||
let impl_view_function_metadata =
|
||||
impl_view_function_metadata(def, span, where_clause.as_ref(), &view_fns);
|
||||
|
||||
quote::quote! {
|
||||
#view_function_prefix_impl
|
||||
#( #view_fn_impls )*
|
||||
#impl_dispatch_view_function
|
||||
#impl_view_function_metadata
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_view_function_prefix_impl(
|
||||
def: &Def,
|
||||
span: Span,
|
||||
where_clause: Option<&syn::WhereClause>,
|
||||
) -> TokenStream {
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezframe_system = &def.pezframe_system;
|
||||
let type_impl_gen = &def.type_impl_generics(span);
|
||||
let type_use_gen = &def.type_use_generics(span);
|
||||
|
||||
quote::quote! {
|
||||
impl<#type_impl_gen> #pezframe_support::view_functions::ViewFunctionIdPrefix for #pezpallet_ident<#type_use_gen> #where_clause {
|
||||
fn prefix() -> [::core::primitive::u8; 16usize] {
|
||||
<
|
||||
<T as #pezframe_system::Config>::PalletInfo
|
||||
as #pezframe_support::traits::PalletInfo
|
||||
>::name_hash::<Pezpallet<#type_use_gen>>()
|
||||
.expect("No name_hash found for the pezpallet in the runtime! This usually means that the pezpallet wasn't added to `construct_runtime!`.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_view_function(
|
||||
def: &Def,
|
||||
span: Span,
|
||||
where_clause: Option<&syn::WhereClause>,
|
||||
view_fn: &ViewFunctionDef,
|
||||
) -> TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let type_impl_gen = &def.type_impl_generics(span);
|
||||
let type_decl_bounded_gen = &def.type_decl_bounded_generics(span);
|
||||
let type_use_gen = &def.type_use_generics(span);
|
||||
let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" };
|
||||
|
||||
let view_function_struct_ident = view_fn.view_function_struct_ident();
|
||||
let view_fn_name = &view_fn.name;
|
||||
let (arg_names, arg_types) = match view_fn.args_names_types() {
|
||||
Ok((arg_names, arg_types)) => (arg_names, arg_types),
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
let return_type = &view_fn.return_type;
|
||||
let docs = &view_fn.docs;
|
||||
|
||||
let view_function_id_suffix_bytes_raw = match view_fn.view_function_id_suffix_bytes() {
|
||||
Ok(view_function_id_suffix_bytes_raw) => view_function_id_suffix_bytes_raw,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
let view_function_id_suffix_bytes = view_function_id_suffix_bytes_raw
|
||||
.map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), Span::call_site()));
|
||||
|
||||
quote::quote! {
|
||||
#( #[doc = #docs] )*
|
||||
#[allow(missing_docs)]
|
||||
#[derive(
|
||||
#pezframe_support::RuntimeDebugNoBound,
|
||||
#pezframe_support::CloneNoBound,
|
||||
#pezframe_support::EqNoBound,
|
||||
#pezframe_support::PartialEqNoBound,
|
||||
#pezframe_support::__private::codec::Encode,
|
||||
#pezframe_support::__private::codec::Decode,
|
||||
#pezframe_support::__private::codec::DecodeWithMemTracking,
|
||||
#pezframe_support::__private::scale_info::TypeInfo,
|
||||
)]
|
||||
#[codec(encode_bound())]
|
||||
#[codec(decode_bound())]
|
||||
#[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)]
|
||||
pub struct #view_function_struct_ident<#type_decl_bounded_gen> #where_clause {
|
||||
#(
|
||||
pub #arg_names: #arg_types,
|
||||
)*
|
||||
_marker: ::core::marker::PhantomData<(#type_use_gen,)>,
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #view_function_struct_ident<#type_use_gen> #where_clause {
|
||||
/// Create a new [`#view_function_struct_ident`] instance.
|
||||
pub fn new(#( #arg_names: #arg_types, )*) -> Self {
|
||||
Self {
|
||||
#( #arg_names, )*
|
||||
_marker: ::core::default::Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::view_functions::ViewFunctionIdSuffix for #view_function_struct_ident<#type_use_gen> #where_clause {
|
||||
const SUFFIX: [::core::primitive::u8; 16usize] = [ #( #view_function_id_suffix_bytes ),* ];
|
||||
}
|
||||
|
||||
impl<#type_impl_gen> #pezframe_support::view_functions::ViewFunction for #view_function_struct_ident<#type_use_gen> #where_clause {
|
||||
fn id() -> #pezframe_support::view_functions::ViewFunctionId {
|
||||
#pezframe_support::view_functions::ViewFunctionId {
|
||||
prefix: <#pezpallet_ident<#type_use_gen> as #pezframe_support::view_functions::ViewFunctionIdPrefix>::prefix(),
|
||||
suffix: <Self as #pezframe_support::view_functions::ViewFunctionIdSuffix>::SUFFIX,
|
||||
}
|
||||
}
|
||||
|
||||
type ReturnType = #return_type;
|
||||
|
||||
fn invoke(self) -> Self::ReturnType {
|
||||
let Self { #( #arg_names, )* _marker } = self;
|
||||
#pezpallet_ident::<#type_use_gen> :: #view_fn_name( #( #arg_names, )* )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_dispatch_view_function(
|
||||
def: &Def,
|
||||
span: Span,
|
||||
where_clause: Option<&syn::WhereClause>,
|
||||
view_fns: &[ViewFunctionDef],
|
||||
) -> TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let type_impl_gen = &def.type_impl_generics(span);
|
||||
let type_use_gen = &def.type_use_generics(span);
|
||||
|
||||
let query_match_arms = view_fns.iter().map(|view_fn| {
|
||||
let view_function_struct_ident = view_fn.view_function_struct_ident();
|
||||
quote::quote! {
|
||||
<#view_function_struct_ident<#type_use_gen> as #pezframe_support::view_functions::ViewFunctionIdSuffix>::SUFFIX => {
|
||||
<#view_function_struct_ident<#type_use_gen> as #pezframe_support::view_functions::ViewFunction>::execute(input, output)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote::quote! {
|
||||
impl<#type_impl_gen> #pezframe_support::view_functions::DispatchViewFunction
|
||||
for #pezpallet_ident<#type_use_gen> #where_clause
|
||||
{
|
||||
#[deny(unreachable_patterns)]
|
||||
fn dispatch_view_function<O: #pezframe_support::__private::codec::Output>(
|
||||
id: & #pezframe_support::view_functions::ViewFunctionId,
|
||||
input: &mut &[u8],
|
||||
output: &mut O
|
||||
) -> Result<(), #pezframe_support::view_functions::ViewFunctionDispatchError>
|
||||
{
|
||||
match id.suffix {
|
||||
#( #query_match_arms )*
|
||||
_ => Err(#pezframe_support::view_functions::ViewFunctionDispatchError::NotFound(id.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_view_function_metadata(
|
||||
def: &Def,
|
||||
span: Span,
|
||||
where_clause: Option<&syn::WhereClause>,
|
||||
view_fns: &[ViewFunctionDef],
|
||||
) -> TokenStream {
|
||||
let pezframe_support = &def.pezframe_support;
|
||||
let pezpallet_ident = &def.pezpallet_struct.pezpallet;
|
||||
let type_impl_gen = &def.type_impl_generics(span);
|
||||
let type_use_gen = &def.type_use_generics(span);
|
||||
|
||||
let view_functions = view_fns.iter().map(|view_fn| {
|
||||
let view_function_struct_ident = view_fn.view_function_struct_ident();
|
||||
let name = &view_fn.name;
|
||||
let inputs = view_fn.args.iter().filter_map(|fn_arg| {
|
||||
match fn_arg {
|
||||
syn::FnArg::Receiver(_) => None,
|
||||
syn::FnArg::Typed(typed) => {
|
||||
let pat = &typed.pat;
|
||||
let ty = &typed.ty;
|
||||
Some(quote::quote! {
|
||||
#pezframe_support::__private::metadata_ir::PalletViewFunctionParamMetadataIR {
|
||||
name: ::core::stringify!(#pat),
|
||||
ty: #pezframe_support::__private::scale_info::meta_type::<#ty>(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let no_docs = vec![];
|
||||
let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &view_fn.docs };
|
||||
|
||||
let deprecation = match crate::deprecation::get_deprecation(
|
||||
"e::quote! { #pezframe_support },
|
||||
&def.item.attrs,
|
||||
) {
|
||||
Ok(deprecation) => deprecation,
|
||||
Err(e) => return e.into_compile_error(),
|
||||
};
|
||||
|
||||
quote::quote! {
|
||||
#pezframe_support::__private::metadata_ir::PalletViewFunctionMetadataIR {
|
||||
name: ::core::stringify!(#name),
|
||||
id: <#view_function_struct_ident<#type_use_gen> as #pezframe_support::view_functions::ViewFunction>::id().into(),
|
||||
inputs: #pezframe_support::__private::pezsp_std::vec![ #( #inputs ),* ],
|
||||
output: #pezframe_support::__private::scale_info::meta_type::<
|
||||
<#view_function_struct_ident<#type_use_gen> as #pezframe_support::view_functions::ViewFunction>::ReturnType
|
||||
>(),
|
||||
docs: #pezframe_support::__private::pezsp_std::vec![ #( #doc ),* ],
|
||||
deprecation_info: #deprecation,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote::quote! {
|
||||
impl<#type_impl_gen> #pezpallet_ident<#type_use_gen> #where_clause {
|
||||
#[doc(hidden)]
|
||||
pub fn pezpallet_view_functions_metadata()
|
||||
-> #pezframe_support::__private::Vec<#pezframe_support::__private::metadata_ir::PalletViewFunctionMetadataIR> {
|
||||
#pezframe_support::__private::vec![ #( #view_functions ),* ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Generates warnings for undesirable pezpallet code.
|
||||
|
||||
use crate::pezpallet::parse::call::{CallVariantDef, CallWeightDef};
|
||||
use proc_macro_warning::Warning;
|
||||
use syn::{
|
||||
spanned::Spanned,
|
||||
visit::{self, Visit},
|
||||
};
|
||||
|
||||
/// Warn if any of the call arguments starts with a underscore and is used in a weight formula.
|
||||
pub(crate) fn weight_witness_warning(
|
||||
method: &CallVariantDef,
|
||||
dev_mode: bool,
|
||||
warnings: &mut Vec<Warning>,
|
||||
) {
|
||||
if dev_mode {
|
||||
return;
|
||||
}
|
||||
let CallWeightDef::Immediate(w) = &method.weight else { return };
|
||||
|
||||
let partial_warning = Warning::new_deprecated("UncheckedWeightWitness")
|
||||
.old("not check weight witness data")
|
||||
.new("ensure that all witness data for weight calculation is checked before usage")
|
||||
.help_link("https://github.com/pezkuwichain/kurdistan-sdk/issues/108");
|
||||
|
||||
for (_, arg_ident, _) in method.args.iter() {
|
||||
if !arg_ident.to_string().starts_with('_') || !contains_ident(w.clone(), &arg_ident) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let warning = partial_warning
|
||||
.clone()
|
||||
.index(warnings.len())
|
||||
.span(arg_ident.span())
|
||||
.build_or_panic();
|
||||
|
||||
warnings.push(warning);
|
||||
}
|
||||
}
|
||||
|
||||
/// Warn if the weight is a constant and the pezpallet not in `dev_mode`.
|
||||
pub(crate) fn weight_constant_warning(
|
||||
weight: &syn::Expr,
|
||||
dev_mode: bool,
|
||||
warnings: &mut Vec<Warning>,
|
||||
) {
|
||||
if dev_mode {
|
||||
return;
|
||||
}
|
||||
let syn::Expr::Lit(lit) = weight else { return };
|
||||
|
||||
let warning = Warning::new_deprecated("ConstantWeight")
|
||||
.index(warnings.len())
|
||||
.old("use hard-coded constant as call weight")
|
||||
.new("benchmark all calls or put the pezpallet into `dev` mode")
|
||||
.help_link("https://github.com/pezkuwichain/kurdistan-sdk/issues/48")
|
||||
.span(lit.span())
|
||||
.build_or_panic();
|
||||
|
||||
warnings.push(warning);
|
||||
}
|
||||
|
||||
/// Returns whether `expr` contains `ident`.
|
||||
fn contains_ident(mut expr: syn::Expr, ident: &syn::Ident) -> bool {
|
||||
struct ContainsIdent {
|
||||
ident: syn::Ident,
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for ContainsIdent {
|
||||
fn visit_ident(&mut self, i: &syn::Ident) {
|
||||
if *i == self.ident {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = ContainsIdent { ident: ident.clone(), found: false };
|
||||
visit::visit_expr(&mut visitor, &mut expr);
|
||||
visitor.found
|
||||
}
|
||||
Reference in New Issue
Block a user