frame_support_procedural/pallet/expand/
event.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::{
19	pallet::{parse::event::PalletEventDepositAttr, Def},
20	COUNTER,
21};
22use frame_support_procedural_tools::get_doc_literals;
23use syn::{spanned::Spanned, Ident};
24
25///
26/// * Add __Ignore variant on Event
27/// * Impl various trait on Event including metadata
28/// * if deposit_event is defined, implement deposit_event on module.
29pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
30	let count = COUNTER.with(|counter| counter.borrow_mut().inc());
31
32	let (event, macro_ident) = if let Some(event) = &def.event {
33		let ident = Ident::new(&format!("__is_event_part_defined_{}", count), event.attr_span);
34		(event, ident)
35	} else {
36		let macro_ident =
37			Ident::new(&format!("__is_event_part_defined_{}", count), def.item.span());
38
39		return quote::quote! {
40			#[doc(hidden)]
41			pub mod __substrate_event_check {
42				#[macro_export]
43				#[doc(hidden)]
44				macro_rules! #macro_ident {
45					($pallet_name:ident) => {
46						compile_error!(concat!(
47							"`",
48							stringify!($pallet_name),
49							"` does not have #[pallet::event] defined, perhaps you should \
50							remove `Event` from construct_runtime?",
51						));
52					}
53				}
54
55				#[doc(hidden)]
56				pub use #macro_ident as is_event_part_defined;
57			}
58		}
59	};
60
61	let event_where_clause = &event.where_clause;
62
63	// NOTE: actually event where clause must be a subset of config where clause because of
64	// `type RuntimeEvent: From<Event<Self>>`. But we merge either way for potential better error
65	// message
66	let completed_where_clause =
67		super::merge_where_clauses(&[&event.where_clause, &def.config.where_clause]);
68
69	let event_ident = &event.event;
70	let frame_system = &def.frame_system;
71	let frame_support = &def.frame_support;
72	let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
73	let event_impl_gen = &event.gen_kind.type_impl_gen(event.attr_span);
74	let event_item = {
75		let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[event.index];
76		if let syn::Item::Enum(item) = item {
77			item
78		} else {
79			unreachable!("Checked by event parser")
80		}
81	};
82
83	// Phantom data is added for generic event.
84	if event.gen_kind.is_generic() {
85		let variant = syn::parse_quote!(
86			#[doc(hidden)]
87			#[codec(skip)]
88			__Ignore(
89				::core::marker::PhantomData<(#event_use_gen)>,
90				#frame_support::Never,
91			)
92		);
93
94		// Push ignore variant at the end.
95		event_item.variants.push(variant);
96	}
97
98	let deprecation = match crate::deprecation::get_deprecation_enum(
99		&quote::quote! {#frame_support},
100		&event.attrs,
101		event_item.variants.iter().enumerate().map(|(index, item)| {
102			let index = crate::deprecation::variant_index_for_deprecation(index as u8, item);
103
104			(index, item.attrs.as_ref())
105		}),
106	) {
107		Ok(deprecation) => deprecation,
108		Err(e) => return e.into_compile_error(),
109	};
110
111	if get_doc_literals(&event_item.attrs).is_empty() {
112		event_item
113			.attrs
114			.push(syn::parse_quote!(#[doc = "The `Event` enum of this pallet"]));
115	}
116
117	// derive some traits because system event require Clone, FullCodec, Eq, PartialEq and Debug
118	event_item.attrs.push(syn::parse_quote!(
119		#[derive(
120			#frame_support::CloneNoBound,
121			#frame_support::EqNoBound,
122			#frame_support::PartialEqNoBound,
123			#frame_support::RuntimeDebugNoBound,
124			#frame_support::__private::codec::Encode,
125			#frame_support::__private::codec::Decode,
126			#frame_support::__private::scale_info::TypeInfo,
127		)]
128	));
129
130	let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" };
131
132	// skip requirement for type params to implement `TypeInfo`, and set docs capture
133	event_item.attrs.push(syn::parse_quote!(
134		#[scale_info(skip_type_params(#event_use_gen), capture_docs = #capture_docs)]
135	));
136
137	let deposit_event = if let Some(deposit_event) = &event.deposit_event {
138		let event_use_gen = &event.gen_kind.type_use_gen(event.attr_span);
139		let trait_use_gen = &def.trait_use_generics(event.attr_span);
140		let type_impl_gen = &def.type_impl_generics(event.attr_span);
141		let type_use_gen = &def.type_use_generics(event.attr_span);
142		let pallet_ident = &def.pallet_struct.pallet;
143
144		let PalletEventDepositAttr { fn_vis, fn_span, .. } = deposit_event;
145
146		quote::quote_spanned!(*fn_span =>
147			impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
148				#fn_vis fn deposit_event(event: Event<#event_use_gen>) {
149					let event = <
150						<T as Config #trait_use_gen>::RuntimeEvent as
151						From<Event<#event_use_gen>>
152					>::from(event);
153
154					let event = <
155						<T as Config #trait_use_gen>::RuntimeEvent as
156						Into<<T as #frame_system::Config>::RuntimeEvent>
157					>::into(event);
158
159					<#frame_system::Pallet<T>>::deposit_event(event)
160				}
161			}
162		)
163	} else {
164		Default::default()
165	};
166
167	quote::quote_spanned!(event.attr_span =>
168		#[doc(hidden)]
169		pub mod __substrate_event_check {
170			#[macro_export]
171			#[doc(hidden)]
172			macro_rules! #macro_ident {
173				($pallet_name:ident) => {};
174			}
175
176			#[doc(hidden)]
177			pub use #macro_ident as is_event_part_defined;
178		}
179
180		#deposit_event
181
182		impl<#event_impl_gen> From<#event_ident<#event_use_gen>> for () #event_where_clause {
183			fn from(_: #event_ident<#event_use_gen>) {}
184		}
185
186		impl<#event_impl_gen> #event_ident<#event_use_gen> #event_where_clause {
187			#[allow(dead_code)]
188			#[doc(hidden)]
189			pub fn event_metadata<W: #frame_support::__private::scale_info::TypeInfo + 'static>() -> #frame_support::__private::metadata_ir::PalletEventMetadataIR {
190				#frame_support::__private::metadata_ir::PalletEventMetadataIR {
191					ty: #frame_support::__private::scale_info::meta_type::<W>(),
192					deprecation_info: #deprecation,
193				}
194			}
195		}
196	)
197}