ink_codegen/generator/
event.rs1use derive_more::From;
16#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
17use ir::IsDocAttribute;
18use proc_macro2::TokenStream as TokenStream2;
19use quote::quote;
20use syn::spanned::Spanned;
21#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
22use syn::Fields;
23
24#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
25use crate::generator::sol;
26use crate::GenerateCode;
27
28#[derive(From, Copy, Clone)]
30pub struct Event<'a> {
31 item: &'a ir::Event,
33}
34
35impl GenerateCode for Event<'_> {
36 fn generate_code(&self) -> TokenStream2 {
38 let item = self.item.item();
39 let anonymous = self
40 .item
41 .anonymous()
42 .then(|| quote::quote! { #[ink(anonymous)] });
43 let signature_topic = self
44 .item
45 .signature_topic_hex()
46 .map(|hex_s| quote::quote! { #[ink(signature_topic = #hex_s)] });
47 let cfg_attrs = self.item.get_cfg_attrs(item.span());
48
49 #[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
50 let sol_event_metadata = self.solidity_event_metadata();
51
52 #[cfg(not(all(feature = "std", any(ink_abi = "sol", ink_abi = "all"))))]
53 let sol_event_metadata = quote! {};
54
55 quote::quote! (
56 #( #cfg_attrs )*
57 #[cfg_attr(feature = "std", derive(::ink::EventMetadata))]
58 #[derive(::ink::Event)]
59 #[::ink::scale_derive(Encode, Decode)]
60 #anonymous
61 #signature_topic
62 #item
63
64 #sol_event_metadata
65 )
66 }
67}
68
69impl Event<'_> {
70 #[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
72 fn solidity_event_metadata(&self) -> TokenStream2 {
73 let item = self.item.item();
74 let ident = &item.ident;
75 let name = ident.to_string();
76 let is_anonymous = self.item.anonymous();
77
78 let fields = match &item.fields {
79 Fields::Named(fields) => fields,
80 Fields::Unnamed(_) | Fields::Unit => unreachable!("Expected named fields"),
81 };
82 let params = fields.named.iter().map(|field| {
83 let ty = &field.ty;
84 let sol_ty = sol::utils::sol_type(ty);
85 let ident = field.ident.as_ref().expect("Expected a named field");
86 let name = ident.to_string();
87 let is_topic = field.attrs.iter().any(|attr| {
88 let is_topic_arg = || {
89 attr.parse_nested_meta(|meta| {
90 if meta.path.is_ident("topic") {
91 Ok(())
92 } else {
93 Err(meta.error("Not a topic arg"))
94 }
95 })
96 .is_ok()
97 };
98 attr.path().is_ident("ink") && is_topic_arg()
99 });
100 let docs = field
101 .attrs
102 .iter()
103 .filter_map(|attr| attr.extract_docs())
104 .collect::<Vec<_>>()
105 .join("\n");
106
107 quote! {
108 ::ink::metadata::sol::EventParamMetadata {
109 name: #name.into(),
110 ty: #sol_ty.into(),
111 is_topic: #is_topic,
112 docs: #docs.into(),
113 }
114 }
115 });
116
117 let docs = item
118 .attrs
119 .iter()
120 .filter_map(|attr| attr.extract_docs())
121 .collect::<Vec<_>>()
122 .join("\n");
123
124 quote! {
125 const _: () = {
126 #[::ink::linkme::distributed_slice(::ink::CONTRACT_EVENTS_SOL)]
129 #[linkme(crate = ::ink::linkme)]
130 static EVENT_METADATA_SOL: fn() -> ::ink::metadata::sol::EventMetadata = || {
131 ::ink::metadata::sol::EventMetadata {
132 name: #name.into(),
133 is_anonymous: #is_anonymous,
134 params: vec![ #( #params ),* ],
135 docs: #docs.into(),
136 }
137 };
138 };
139 }
140 }
141}