sails_macros_core/event/
mod.rs1use crate::sails_paths::sails_path_or_default;
2use args::{CratePathAttr, SAILS_PATH};
3use parity_scale_codec::Encode;
4use proc_macro_error::abort;
5use proc_macro2::TokenStream;
6use quote::quote;
7use syn::{Fields, ItemEnum, Path, parse::Parse};
8
9mod args;
10#[cfg(feature = "ethexe")]
11mod ethexe;
12
13pub fn event(attrs: TokenStream, input: TokenStream) -> TokenStream {
14 #[cfg_attr(not(feature = "ethexe"), allow(unused_mut))]
16 let mut input: ItemEnum = syn::parse2(input).unwrap_or_else(|err| {
17 abort!(
18 err.span(),
19 "`event` attribute can be applied to enums only: {}",
20 err
21 )
22 });
23
24 let sails_path_attr = syn::parse2::<CratePathAttr>(attrs).ok();
26 let sails_path = &sails_path_or_default(sails_path_attr.map(|attr| attr.path()));
27
28 let event_impl = generate_sails_event_impl(&input, sails_path);
29
30 #[cfg(feature = "ethexe")]
31 let eth_event_impl = ethexe::generate_eth_event_impl(&input, sails_path);
32 #[cfg(feature = "ethexe")]
33 ethexe::process_indexed(&mut input);
34 #[cfg(not(feature = "ethexe"))]
35 let eth_event_impl = quote!();
36
37 quote! {
38 #input
39
40 #event_impl
41
42 #eth_event_impl
43 }
44}
45
46fn generate_sails_event_impl(input: &ItemEnum, sails_path: &Path) -> TokenStream {
47 let enum_ident = &input.ident;
49 let variants = &input.variants;
50 if variants.len() > 256 {
52 abort!(
53 input,
54 "`event` enum can have at most 256 variants, but found {}",
55 variants.len()
56 )
57 }
58
59 let mut match_arms = Vec::new();
61
62 for variant in variants {
63 let variant_ident = &variant.ident;
64 let pattern = match &variant.fields {
66 Fields::Unit => {
67 quote! { #enum_ident::#variant_ident }
69 }
70 Fields::Unnamed(_) => {
71 quote! { #enum_ident::#variant_ident ( .. ) }
73 }
74 Fields::Named(_) => {
75 quote! { #enum_ident::#variant_ident { .. } }
77 }
78 };
79 let encoded_name = variant_ident.to_string().encode();
81
82 let arm = quote! {
84 #pattern => &[ #( #encoded_name ),* ]
85 };
86 match_arms.push(arm);
87 }
88
89 quote! {
91 impl #sails_path::SailsEvent for #enum_ident {
92 fn encoded_event_name(&self) -> &'static [u8] {
93 match self {
94 #( #match_arms ),*
95 }
96 }
97
98 fn skip_bytes() -> usize {
99 1 }
101 }
102 }
103}
104
105pub fn derive_sails_event(input: TokenStream) -> TokenStream {
106 let input: ItemEnum = syn::parse2(input).unwrap_or_else(|err| {
108 abort!(
109 err.span(),
110 "`SailsEvent` can only be derived for enums: {}",
111 err
112 )
113 });
114
115 let sails_path_attr = input
116 .attrs
117 .iter()
118 .find(|attr| attr.path().is_ident(SAILS_PATH))
119 .map(|attr| {
120 attr.parse_args_with(CratePathAttr::parse)
121 .unwrap_or_else(|_| abort!(attr, "unexpected value for `crate` argument",))
122 });
123 let sails_path = &sails_path_or_default(sails_path_attr.map(|attr| attr.path()));
124
125 generate_sails_event_impl(&input, sails_path)
126}