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}