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