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;
20#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
21use syn::Fields;
22use syn::spanned::Spanned;
23
24use crate::GenerateCode;
25#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
26use crate::generator::sol;
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()
46 .as_ref()
47 .map(ToString::to_string)
48 .map(|hex_s| quote::quote! { #[ink(signature_topic = #hex_s)] });
49 let name_override = self
50 .item
51 .name()
52 .map(|name| quote::quote! { #[ink(name = #name)] });
53 let cfg_attrs = self.item.get_cfg_attrs(item.span());
54
55 #[cfg(not(ink_abi = "sol"))]
57 let (scale_derive, ink_event_metadata_derive) =
58 (quote! { #[::ink::scale_derive(Encode, Decode)] }, {
59 #[cfg(feature = "std")]
60 quote! { #[derive(::ink::EventMetadata)] }
61 #[cfg(not(feature = "std"))]
62 quote! {}
63 });
64 #[cfg(ink_abi = "sol")]
65 let (scale_derive, ink_event_metadata_derive) = (quote! {}, quote! {});
66
67 #[cfg(not(any(ink_abi = "sol", ink_abi = "all")))]
69 let (sol_codec_derive, sol_event_metadata) = (quote! {}, quote! {});
70 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
71 let (sol_codec_derive, sol_event_metadata) =
72 (quote! { #[derive(::ink::SolEncode, ::ink::SolDecode)] }, {
73 #[cfg(feature = "std")]
74 {
75 self.solidity_event_metadata()
76 }
77 #[cfg(not(feature = "std"))]
78 quote! {}
79 });
80
81 quote::quote! (
82 #( #cfg_attrs )*
83 #ink_event_metadata_derive
84 #[derive(::ink::Event)]
85 #scale_derive
86 #sol_codec_derive
87 #anonymous
88 #signature_topic
89 #name_override
90 #item
91
92 #sol_event_metadata
93 )
94 }
95}
96
97impl Event<'_> {
98 #[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
100 fn solidity_event_metadata(&self) -> TokenStream2 {
101 let item = self.item.item();
102 let ident = &item.ident;
103 let name = self
104 .item
105 .name()
106 .map(ToString::to_string)
107 .unwrap_or_else(|| ident.to_string());
108 let is_anonymous = self.item.anonymous();
109
110 let fields = match &item.fields {
111 Fields::Named(fields) => fields,
112 Fields::Unnamed(_) | Fields::Unit => unreachable!("Expected named fields"),
113 };
114 let params = fields.named.iter().map(|field| {
115 let ty = &field.ty;
116 let sol_ty = sol::utils::sol_type(ty);
117 let ident = field.ident.as_ref().expect("Expected a named field");
118 let name = ident.to_string();
119 let is_topic = field.attrs.iter().any(|attr| {
120 let is_topic_arg = || {
121 attr.parse_nested_meta(|meta| {
122 if meta.path.is_ident("topic") {
123 Ok(())
124 } else {
125 Err(meta.error("Not a topic arg"))
126 }
127 })
128 .is_ok()
129 };
130 attr.path().is_ident("ink") && is_topic_arg()
131 });
132 let docs = field
133 .attrs
134 .iter()
135 .filter_map(|attr| attr.extract_docs())
136 .collect::<Vec<_>>()
137 .join("\n");
138
139 quote! {
140 ::ink::metadata::sol::EventParamMetadata {
141 name: #name.into(),
142 ty: #sol_ty.into(),
143 is_topic: #is_topic,
144 docs: #docs.into(),
145 }
146 }
147 });
148
149 let docs = item
150 .attrs
151 .iter()
152 .filter_map(|attr| attr.extract_docs())
153 .collect::<Vec<_>>()
154 .join("\n");
155
156 quote! {
157 const _: () = {
158 #[::ink::linkme::distributed_slice(::ink::CONTRACT_EVENTS_SOL)]
161 #[linkme(crate = ::ink::linkme)]
162 static EVENT_METADATA_SOL: fn() -> ::ink::metadata::sol::EventMetadata = || {
163 ::ink::metadata::sol::EventMetadata {
164 name: #name.into(),
165 is_anonymous: #is_anonymous,
166 params: vec![ #( #params ),* ],
167 docs: #docs.into(),
168 }
169 };
170 };
171 }
172 }
173}