referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/
tt_macro.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
18//! Implementation of the `create_tt_return_macro` macro
19
20use crate::COUNTER;
21use proc_macro2::{Ident, TokenStream};
22use quote::format_ident;
23
24struct CreateTtReturnMacroDef {
25	name: Ident,
26	args: Vec<(Ident, TokenStream)>,
27}
28
29impl syn::parse::Parse for CreateTtReturnMacroDef {
30	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
31		let name = input.parse()?;
32		input.parse::<syn::Token![,]>()?;
33
34		let mut args = Vec::new();
35		while !input.is_empty() {
36			let mut value;
37			let key: Ident = input.parse()?;
38			input.parse::<syn::Token![=]>()?;
39			let _: syn::token::Bracket = syn::bracketed!(value in input);
40			let _: syn::token::Brace = syn::braced!(value in value);
41			let value: TokenStream = value.parse()?;
42
43			args.push((key, value))
44		}
45
46		Ok(Self { name, args })
47	}
48}
49
50/// A proc macro that accepts a name and any number of key-value pairs, to be used to create a
51/// declarative macro that follows tt-call conventions and simply calls
52/// [`tt_call::tt_return`], accepting an optional `frame-support` argument and returning
53/// the key-value pairs that were supplied to the proc macro.
54///
55/// # Example
56/// ```ignore
57/// __create_tt_macro! {
58///     my_tt_macro,
59///     foo = [{ bar }]
60/// }
61///
62/// // Creates the following declarative macro:
63///
64/// macro_rules! my_tt_macro {
65///     {
66///         $caller:tt
67///         $(your_tt_return = [{ $my_tt_return:path }])?
68///     } => {
69///         $my_tt_return! {
70///             $caller
71///             foo = [{ bar }]
72///         }
73///     }
74/// }
75/// ```
76pub fn create_tt_return_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
77	let CreateTtReturnMacroDef { name, args } =
78		syn::parse_macro_input!(input as CreateTtReturnMacroDef);
79
80	let (keys, values): (Vec<_>, Vec<_>) = args.into_iter().unzip();
81	let count = COUNTER.with(|counter| counter.borrow_mut().inc());
82	let unique_name = format_ident!("{}_{}", name, count);
83
84	let decl_macro = quote::quote! {
85		#[macro_export]
86		#[doc(hidden)]
87		macro_rules! #unique_name {
88			{
89				$caller:tt
90				$(your_tt_return = [{ $my_tt_macro:path }])?
91			} => {
92				$my_tt_return! {
93					$caller
94					#(
95						#keys = [{ #values }]
96					)*
97				}
98			}
99		}
100
101		pub use #unique_name as #name;
102	};
103
104	decl_macro.into()
105}