mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 15:57:55 +00:00
Refactor event type decoding and declaration (#221)
* Refactor event type decoding hand declartion Fixes #196, #181, #28 ## Dyanmic sized types Before this change, the event decoder assume all the event types have fixed sizes. Some counterexamples are: Hashes, AuthorityList. In this change, instead of decoding by skipping the fixed-length bytes, we introduce `type_segmenter` registry which decodes the raw event bytes with the actual scale codec. So variable length types can be handled correctly. ## New attribute for pallet type definition In the past, trait associated type is the only way to add types to the EventsDecoder implementation of a pallet. But in reality it's common that the events in a pallet references some types not defined in the trait associated types. Some examples are: `IdentificationTuple` and `SessionIndex` in Session pallet. In this change, we introduce more attributes to add the types: ```rust #[module] trait Pallet: System { #![event_type(SomeType)] #![event_alias(TypeNameAlias = SomeType)] #![event_alias(SomeOtherAlias = TypeWithAssociatedTypes<T>)] } ``` ## Tested Compile with `nightly-2020-10-01`; smoke test to sync a full Phala bockchain. * Format code * Make rustfmt::skip an outer attribute * Ignore the sample code * Alias the event segmenter closure * Copy AuthorityList from sp_finality_grandpa * Remove the unused static event type size * Make segmenter as a trait, resue grandpa::Public * Wrap PhantomData in struct TypeMarker
This commit is contained in:
@@ -69,16 +69,62 @@ fn events_decoder_trait_name(module: &syn::Ident) -> syn::Ident {
|
||||
fn with_module_ident(module: &syn::Ident) -> syn::Ident {
|
||||
format_ident!("with_{}", module.to_string().to_snake_case())
|
||||
}
|
||||
|
||||
type EventAttr = utils::UniAttr<syn::Type>;
|
||||
type EventAliasAttr = utils::UniAttr<utils::Attr<syn::Ident, syn::Type>>;
|
||||
|
||||
/// Parses the event type definition macros within #[module]
|
||||
///
|
||||
/// It supports two ways to define the associated event type:
|
||||
///
|
||||
/// ```ignore
|
||||
/// #[module]
|
||||
/// trait Pallet: System {
|
||||
/// #![event_type(SomeType)]
|
||||
/// #![event_alias(TypeNameAlias = SomeType)]
|
||||
/// #![event_alias(SomeOtherAlias = TypeWithAssociatedTypes<T>)]
|
||||
/// }
|
||||
/// ```
|
||||
fn parse_event_type_attr(attr: &syn::Attribute) -> Option<(String, syn::Type)> {
|
||||
let ident = utils::path_to_ident(&attr.path);
|
||||
if ident == "event_type" {
|
||||
let attrs: EventAttr = syn::parse2(attr.tokens.clone())
|
||||
.map_err(|err| abort!("{}", err))
|
||||
.unwrap();
|
||||
let ty = attrs.attr;
|
||||
let ident_str = quote!(#ty).to_string();
|
||||
Some((ident_str, ty))
|
||||
} else if ident == "event_alias" {
|
||||
let attrs: EventAliasAttr = syn::parse2(attr.tokens.clone())
|
||||
.map_err(|err| abort!("{}", err))
|
||||
.unwrap();
|
||||
let ty = attrs.attr.value;
|
||||
let ident_str = attrs.attr.key.to_string();
|
||||
Some((ident_str, ty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Attribute macro that registers the type sizes used by the module; also sets the `MODULE` constant.
|
||||
pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
let input: Result<syn::ItemTrait, _> = syn::parse2(tokens.clone());
|
||||
let input = if let Ok(input) = input {
|
||||
let mut input = if let Ok(input) = input {
|
||||
input
|
||||
} else {
|
||||
// handle #[module(ignore)] by just returning the tokens
|
||||
return tokens
|
||||
};
|
||||
|
||||
// Parse the inner attributes `event_type` and `event_alias` and remove them from the macro
|
||||
// outputs.
|
||||
let (other_attrs, event_types): (Vec<_>, Vec<_>) = input
|
||||
.attrs
|
||||
.iter()
|
||||
.cloned()
|
||||
.partition(|attr| parse_event_type_attr(attr).is_none());
|
||||
input.attrs = other_attrs;
|
||||
|
||||
let subxt = utils::use_crate("substrate-subxt");
|
||||
let module = &input.ident;
|
||||
let module_name = module.to_string();
|
||||
@@ -96,7 +142,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
None
|
||||
}
|
||||
});
|
||||
let types = input.items.iter().filter_map(|item| {
|
||||
let associated_types = input.items.iter().filter_map(|item| {
|
||||
if let syn::TraitItem::Type(ty) = item {
|
||||
if ignore(&ty.attrs) {
|
||||
return None
|
||||
@@ -110,6 +156,12 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
None
|
||||
}
|
||||
});
|
||||
let types = event_types.iter().map(|attr| {
|
||||
let (ident_str, ty) = parse_event_type_attr(&attr).unwrap();
|
||||
quote! {
|
||||
self.register_type_size::<#ty>(#ident_str);
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
#input
|
||||
@@ -127,6 +179,7 @@ pub fn module(_args: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
{
|
||||
fn #with_module(&mut self) {
|
||||
#(#bounds)*
|
||||
#(#associated_types)*
|
||||
#(#types)*
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +214,21 @@ impl<K: Parse, V: Parse> Parse for Attr<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UniAttr<A> {
|
||||
pub paren: syn::token::Paren,
|
||||
pub attr: A,
|
||||
}
|
||||
|
||||
impl<A: Parse> Parse for UniAttr<A> {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let content;
|
||||
let paren = syn::parenthesized!(content in input);
|
||||
let attr = content.parse()?;
|
||||
Ok(Self { paren, attr })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn assert_proc_macro(
|
||||
result: proc_macro2::TokenStream,
|
||||
|
||||
Reference in New Issue
Block a user