ink_macro/event/
metadata.rs1use ink_ir::IsDocAttribute;
16use proc_macro2::TokenStream as TokenStream2;
17use quote::quote_spanned;
18use syn::spanned::Spanned;
19
20pub fn event_metadata_derive(mut s: synstructure::Structure) -> TokenStream2 {
22 s.bind_with(|_| synstructure::BindStyle::Move)
23 .add_bounds(synstructure::AddBounds::Fields)
24 .underscore_const(true);
25 match &s.ast().data {
26 syn::Data::Struct(_) => {
27 event_metadata_derive_struct(s).unwrap_or_else(|err| err.to_compile_error())
28 }
29 _ => {
30 syn::Error::new(
31 s.ast().span(),
32 "can only derive `EventMetadata` for Rust `struct` items",
33 )
34 .to_compile_error()
35 }
36 }
37}
38
39fn event_metadata_derive_struct(s: synstructure::Structure) -> syn::Result<TokenStream2> {
41 assert_eq!(s.variants().len(), 1, "can only operate on structs");
42 let span = s.ast().span();
43
44 let variant = &s.variants()[0];
45 let ident = variant.ast().ident;
46
47 let docs = variant
48 .ast()
49 .attrs
50 .iter()
51 .filter_map(|attr| attr.extract_docs());
52
53 let args = variant.bindings().iter().map( |field| {
54 let field_ty = &field.ast().ty;
55 let field_span = field_ty.span();
56 if let Some(field_name) = field.ast().ident.as_ref() {
57 let indexed = super::has_ink_topic_attribute(field)?;
58 let docs = field
59 .ast()
60 .attrs
61 .iter()
62 .filter_map(|attr| attr.extract_docs());
63 let ty_spec = ink_codegen::generate_type_spec(field_ty);
64 Ok(quote_spanned!(field_span =>
65 ::ink::metadata::EventParamSpec::new(::core::stringify!(#field_name))
66 .of_type(#ty_spec)
67 .indexed(#indexed)
68 .docs([ #( #docs ),* ])
69 .done()
70 ))
71 } else {
72 Err(syn::Error::new(
73 field_span,
74 "can only derive `EventMetadata` for Rust `struct` items with named fields",
75 ))
76 }
77 }).collect::<syn::Result<Vec<_>>>()?;
78
79 Ok(s.bound_impl(
80 quote_spanned!(span=> ::ink::metadata::EventMetadata),
81 quote_spanned!(span=>
82 const MODULE_PATH: &'static str = ::core::module_path!();
83
84 fn event_spec() -> ::ink::metadata::EventSpec {
85 #[::ink::metadata::linkme::distributed_slice(::ink::metadata::EVENTS)]
88 #[linkme(crate = ::ink::metadata::linkme)]
89 static EVENT_METADATA: fn() -> ::ink::metadata::EventSpec =
90 <#ident as ::ink::metadata::EventMetadata>::event_spec;
91
92 ::ink::metadata::EventSpec::new(::core::stringify!(#ident))
93 .module_path(::core::module_path!())
94 .signature_topic(
95 <Self as ::ink::env::Event>::SIGNATURE_TOPIC
96 )
97 .args([
98 #( #args ),*
99 ])
100 .docs([
101 #( #docs ),*
102 ])
103 .done()
104 }
105 ),
106 ))
107}