mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-15 22:01:04 +00:00
Adds ability to provide defaults for types provided by construct_runtime (#14682)
* Adds ability to use defaults for verbatim types * Adds RuntimeOrigin and PalletInfo in DefaultConfig * Adds RuntimeEvent in DefaultConfig * Adds RuntimeEvent in DefaultConfig * Minor fix * Minor fix * Everything in frame_system can now have a default * Adds docs * Adds UI Test for no_bounds * Updates docs * Adds UI tests for verbatim * Minor update * Minor updates * Minor updates * Addresses review comments * Fixes test * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * Minor fix * Minor * Fixes build * Uses runtime_type * Fixes comment * Fixes comment * Fixes test * Uses no_aggregated_types as an option in derive_impl * Uses specific imports * Fmt * Updates doc * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Bastian Köcher <git@kchr.de> * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Bastian Köcher <git@kchr.de> * Addresses review comment * Addresses review comment * fmt * Renames test files * Adds docs using docify * Fixes test * Fixes UI tests --------- Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -22,14 +22,46 @@ use macro_magic::mm_core::ForeignPath;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::HashSet;
|
||||
use syn::{parse2, parse_quote, spanned::Spanned, Ident, ImplItem, ItemImpl, Path, Result, Token};
|
||||
use syn::{
|
||||
parse2, parse_quote, spanned::Spanned, token, Ident, ImplItem, ItemImpl, Path, Result, Token,
|
||||
};
|
||||
|
||||
#[derive(Parse)]
|
||||
mod keyword {
|
||||
syn::custom_keyword!(inject_runtime_type);
|
||||
syn::custom_keyword!(no_aggregated_types);
|
||||
}
|
||||
|
||||
#[derive(derive_syn_parse::Parse, PartialEq, Eq)]
|
||||
pub enum PalletAttrType {
|
||||
#[peek(keyword::inject_runtime_type, name = "inject_runtime_type")]
|
||||
RuntimeType(keyword::inject_runtime_type),
|
||||
}
|
||||
|
||||
#[derive(derive_syn_parse::Parse)]
|
||||
pub struct PalletAttr {
|
||||
_pound: Token![#],
|
||||
#[bracket]
|
||||
_bracket: token::Bracket,
|
||||
#[inside(_bracket)]
|
||||
typ: PalletAttrType,
|
||||
}
|
||||
|
||||
fn get_first_item_pallet_attr<Attr>(item: &syn::ImplItemType) -> syn::Result<Option<Attr>>
|
||||
where
|
||||
Attr: syn::parse::Parse,
|
||||
{
|
||||
item.attrs.get(0).map(|a| syn::parse2(a.into_token_stream())).transpose()
|
||||
}
|
||||
|
||||
#[derive(Parse, Debug)]
|
||||
pub struct DeriveImplAttrArgs {
|
||||
pub default_impl_path: Path,
|
||||
_as: Option<Token![as]>,
|
||||
#[parse_if(_as.is_some())]
|
||||
pub disambiguation_path: Option<Path>,
|
||||
_comma: Option<Token![,]>,
|
||||
#[parse_if(_comma.is_some())]
|
||||
pub no_aggregated_types: Option<keyword::no_aggregated_types>,
|
||||
}
|
||||
|
||||
impl ForeignPath for DeriveImplAttrArgs {
|
||||
@@ -43,6 +75,8 @@ impl ToTokens for DeriveImplAttrArgs {
|
||||
tokens.extend(self.default_impl_path.to_token_stream());
|
||||
tokens.extend(self._as.to_token_stream());
|
||||
tokens.extend(self.disambiguation_path.to_token_stream());
|
||||
tokens.extend(self._comma.to_token_stream());
|
||||
tokens.extend(self.no_aggregated_types.to_token_stream());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +112,7 @@ fn combine_impls(
|
||||
foreign_impl: ItemImpl,
|
||||
default_impl_path: Path,
|
||||
disambiguation_path: Path,
|
||||
inject_runtime_types: bool,
|
||||
) -> ItemImpl {
|
||||
let (existing_local_keys, existing_unsupported_items): (HashSet<ImplItem>, HashSet<ImplItem>) =
|
||||
local_impl
|
||||
@@ -96,7 +131,20 @@ fn combine_impls(
|
||||
// do not copy colliding items that have an ident
|
||||
return None
|
||||
}
|
||||
if matches!(item, ImplItem::Type(_)) {
|
||||
if let ImplItem::Type(typ) = item.clone() {
|
||||
let mut typ = typ.clone();
|
||||
if let Ok(Some(PalletAttr { typ: PalletAttrType::RuntimeType(_), .. })) =
|
||||
get_first_item_pallet_attr::<PalletAttr>(&mut typ)
|
||||
{
|
||||
let item: ImplItem = if inject_runtime_types {
|
||||
parse_quote! {
|
||||
type #ident = #ident;
|
||||
}
|
||||
} else {
|
||||
item
|
||||
};
|
||||
return Some(item)
|
||||
}
|
||||
// modify and insert uncolliding type items
|
||||
let modified_item: ImplItem = parse_quote! {
|
||||
type #ident = <#default_impl_path as #disambiguation_path>::#ident;
|
||||
@@ -132,6 +180,7 @@ pub fn derive_impl(
|
||||
foreign_tokens: TokenStream2,
|
||||
local_tokens: TokenStream2,
|
||||
disambiguation_path: Option<Path>,
|
||||
no_aggregated_types: Option<keyword::no_aggregated_types>,
|
||||
) -> Result<TokenStream2> {
|
||||
let local_impl = parse2::<ItemImpl>(local_tokens)?;
|
||||
let foreign_impl = parse2::<ItemImpl>(foreign_tokens)?;
|
||||
@@ -151,8 +200,13 @@ pub fn derive_impl(
|
||||
};
|
||||
|
||||
// generate the combined impl
|
||||
let combined_impl =
|
||||
combine_impls(local_impl, foreign_impl, default_impl_path, disambiguation_path);
|
||||
let combined_impl = combine_impls(
|
||||
local_impl,
|
||||
foreign_impl,
|
||||
default_impl_path,
|
||||
disambiguation_path,
|
||||
no_aggregated_types.is_none(),
|
||||
);
|
||||
|
||||
Ok(quote!(#combined_impl))
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ use macro_magic::import_tokens_attr;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use std::{cell::RefCell, str::FromStr};
|
||||
use syn::{parse_macro_input, Error, ItemImpl, ItemMod};
|
||||
use syn::{parse_macro_input, Error, ItemImpl, ItemMod, TraitItemType};
|
||||
|
||||
pub(crate) const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance";
|
||||
|
||||
@@ -596,6 +596,19 @@ pub fn storage_alias(attributes: TokenStream, input: TokenStream) -> TokenStream
|
||||
///
|
||||
/// Conversely, the `default_impl_path` argument is required and cannot be omitted.
|
||||
///
|
||||
/// Optionally, `no_aggregated_types` can be specified as follows:
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[derive_impl(default_impl_path as disambiguation_path, no_aggregated_types)]
|
||||
/// impl SomeTrait for SomeStruct {
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If specified, this indicates that the aggregated types (as denoted by impl items
|
||||
/// attached with [`#[inject_runtime_type]`]) should not be injected with the respective concrete
|
||||
/// types. By default, all such types are injected.
|
||||
///
|
||||
/// You can also make use of `#[pallet::no_default]` on specific items in your default impl that you
|
||||
/// want to ensure will not be copied over but that you nonetheless want to use locally in the
|
||||
/// context of the foreign impl and the pallet (or context) in which it is defined.
|
||||
@@ -759,6 +772,7 @@ pub fn derive_impl(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
attrs.into(),
|
||||
input.into(),
|
||||
custom_attrs.disambiguation_path,
|
||||
custom_attrs.no_aggregated_types,
|
||||
)
|
||||
.unwrap_or_else(|r| r.into_compile_error())
|
||||
.into()
|
||||
@@ -774,6 +788,19 @@ pub fn no_default(_: TokenStream, _: TokenStream) -> TokenStream {
|
||||
pallet_macro_stub()
|
||||
}
|
||||
|
||||
/// The optional attribute `#[pallet::no_default_bounds]` can be attached to trait items within a
|
||||
/// `Config` trait impl that has [`#[pallet::config(with_default)]`](`macro@config`) attached.
|
||||
///
|
||||
/// Attaching this attribute to a trait item ensures that the generated trait `DefaultConfig`
|
||||
/// will not have any bounds for this trait item.
|
||||
///
|
||||
/// As an example, if you have a trait item `type AccountId: SomeTrait;` in your `Config` trait,
|
||||
/// the generated `DefaultConfig` will only have `type AccountId;` with no trait bound.
|
||||
#[proc_macro_attribute]
|
||||
pub fn no_default_bounds(_: TokenStream, _: TokenStream) -> TokenStream {
|
||||
pallet_macro_stub()
|
||||
}
|
||||
|
||||
/// Attach this attribute to an impl statement that you want to use with
|
||||
/// [`#[derive_impl(..)]`](`macro@derive_impl`).
|
||||
///
|
||||
@@ -843,6 +870,25 @@ pub fn register_default_impl(attrs: TokenStream, tokens: TokenStream) -> TokenSt
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn inject_runtime_type(_: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
let item = tokens.clone();
|
||||
let item = syn::parse_macro_input!(item as TraitItemType);
|
||||
if item.ident != "RuntimeCall" &&
|
||||
item.ident != "RuntimeEvent" &&
|
||||
item.ident != "RuntimeOrigin" &&
|
||||
item.ident != "PalletInfo"
|
||||
{
|
||||
return syn::Error::new_spanned(
|
||||
item,
|
||||
"`#[inject_runtime_type]` can only be attached to `RuntimeCall`, `RuntimeEvent`, `RuntimeOrigin` or `PalletInfo`",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
/// Used internally to decorate pallet attribute macro stubs when they are erroneously used
|
||||
/// outside of a pallet module
|
||||
fn pallet_macro_stub() -> TokenStream {
|
||||
|
||||
@@ -52,7 +52,23 @@ Consequently, a runtime that wants to include this pallet must implement this tr
|
||||
// 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;
|
||||
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.frame_system;
|
||||
|
||||
@@ -34,12 +34,16 @@ mod keyword {
|
||||
syn::custom_keyword!(frame_system);
|
||||
syn::custom_keyword!(disable_frame_system_supertrait_check);
|
||||
syn::custom_keyword!(no_default);
|
||||
syn::custom_keyword!(no_default_bounds);
|
||||
syn::custom_keyword!(constant);
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DefaultTrait {
|
||||
pub items: Vec<syn::TraitItem>,
|
||||
/// A bool for each sub-trait item indicates whether the item has
|
||||
/// `#[pallet::no_default_bounds]` attached to it. If true, the item will not have any bounds
|
||||
/// in the generated default sub-trait.
|
||||
pub items: Vec<(syn::TraitItem, bool)>,
|
||||
pub has_system: bool,
|
||||
}
|
||||
|
||||
@@ -142,6 +146,8 @@ impl syn::parse::Parse for DisableFrameSystemSupertraitCheck {
|
||||
pub enum PalletAttrType {
|
||||
#[peek(keyword::no_default, name = "no_default")]
|
||||
NoDefault(keyword::no_default),
|
||||
#[peek(keyword::no_default_bounds, name = "no_default_bounds")]
|
||||
NoBounds(keyword::no_default_bounds),
|
||||
#[peek(keyword::constant, name = "constant")]
|
||||
Constant(keyword::constant),
|
||||
}
|
||||
@@ -366,6 +372,7 @@ impl ConfigDef {
|
||||
|
||||
let mut already_no_default = false;
|
||||
let mut already_constant = false;
|
||||
let mut already_no_default_bounds = false;
|
||||
|
||||
while let Ok(Some(pallet_attr)) =
|
||||
helper::take_first_item_pallet_attr::<PalletAttr>(trait_item)
|
||||
@@ -403,15 +410,31 @@ impl ConfigDef {
|
||||
|
||||
already_no_default = true;
|
||||
},
|
||||
(PalletAttrType::NoBounds(_), _) => {
|
||||
if !enable_default {
|
||||
return Err(syn::Error::new(
|
||||
pallet_attr._bracket.span.join(),
|
||||
"`#[pallet:no_default_bounds]` can only be used if `#[pallet::config(with_default)]` \
|
||||
has been specified"
|
||||
))
|
||||
}
|
||||
if already_no_default_bounds {
|
||||
return Err(syn::Error::new(
|
||||
pallet_attr._bracket.span.join(),
|
||||
"Duplicate #[pallet::no_default_bounds] attribute not allowed.",
|
||||
))
|
||||
}
|
||||
already_no_default_bounds = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if !already_no_default && !is_event && enable_default {
|
||||
if !already_no_default && enable_default {
|
||||
default_sub_trait
|
||||
.as_mut()
|
||||
.expect("is 'Some(_)' if 'enable_default'; qed")
|
||||
.items
|
||||
.push(trait_item.clone());
|
||||
.push((trait_item.clone(), already_no_default_bounds));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user