frame_support_procedural_tools/
syn_ext.rs
1use frame_support_procedural_tools_derive::{Parse, ToTokens};
23use proc_macro2::{TokenStream, TokenTree};
24use quote::ToTokens;
25use std::iter::once;
26use syn::{
27 parse::{Parse, ParseStream, Result},
28 visit::{self, Visit},
29 Ident,
30};
31
32#[derive(Parse, ToTokens, Debug)]
35pub struct StopParse {
36 pub inner: TokenStream,
37}
38
39macro_rules! groups_impl {
41 ($name:ident, $tok:ident, $deli:ident, $parse:ident) => {
42 #[derive(Debug)]
43 pub struct $name<P> {
44 pub token: syn::token::$tok,
45 pub content: P,
46 }
47
48 impl<P: Parse> Parse for $name<P> {
49 fn parse(input: ParseStream) -> Result<Self> {
50 let content;
51 let token = syn::$parse!(content in input);
52 let content = content.parse()?;
53 Ok($name { token, content })
54 }
55 }
56
57 impl<P: ToTokens> ToTokens for $name<P> {
58 fn to_tokens(&self, tokens: &mut TokenStream) {
59 let mut inner_stream = TokenStream::new();
60 self.content.to_tokens(&mut inner_stream);
61 let token_tree: proc_macro2::TokenTree =
62 proc_macro2::Group::new(proc_macro2::Delimiter::$deli, inner_stream).into();
63 tokens.extend(once(token_tree));
64 }
65 }
66
67 impl<P: Clone> Clone for $name<P> {
68 fn clone(&self) -> Self {
69 Self { token: self.token.clone(), content: self.content.clone() }
70 }
71 }
72 };
73}
74
75groups_impl!(Braces, Brace, Brace, braced);
76groups_impl!(Brackets, Bracket, Bracket, bracketed);
77groups_impl!(Parens, Paren, Parenthesis, parenthesized);
78
79#[derive(Debug)]
80pub struct PunctuatedInner<P, T, V> {
81 pub inner: syn::punctuated::Punctuated<P, T>,
82 pub variant: V,
83}
84
85#[derive(Debug, Clone)]
86pub struct NoTrailing;
87
88#[derive(Debug, Clone)]
89pub struct Trailing;
90
91pub type Punctuated<P, T> = PunctuatedInner<P, T, NoTrailing>;
92
93pub type PunctuatedTrailing<P, T> = PunctuatedInner<P, T, Trailing>;
94
95impl<P: Parse, T: Parse + syn::token::Token> Parse for PunctuatedInner<P, T, Trailing> {
96 fn parse(input: ParseStream) -> Result<Self> {
97 Ok(PunctuatedInner {
98 inner: syn::punctuated::Punctuated::parse_separated_nonempty(input)?,
99 variant: Trailing,
100 })
101 }
102}
103
104impl<P: Parse, T: Parse> Parse for PunctuatedInner<P, T, NoTrailing> {
105 fn parse(input: ParseStream) -> Result<Self> {
106 Ok(PunctuatedInner {
107 inner: syn::punctuated::Punctuated::parse_terminated(input)?,
108 variant: NoTrailing,
109 })
110 }
111}
112
113impl<P: ToTokens, T: ToTokens, V> ToTokens for PunctuatedInner<P, T, V> {
114 fn to_tokens(&self, tokens: &mut TokenStream) {
115 self.inner.to_tokens(tokens)
116 }
117}
118
119impl<P: Clone, T: Clone, V: Clone> Clone for PunctuatedInner<P, T, V> {
120 fn clone(&self) -> Self {
121 Self { inner: self.inner.clone(), variant: self.variant.clone() }
122 }
123}
124
125#[derive(Debug, Clone)]
127pub struct Meta {
128 pub inner: syn::Meta,
129}
130
131impl Parse for Meta {
132 fn parse(input: ParseStream) -> Result<Self> {
133 Ok(Meta { inner: syn::Meta::parse(input)? })
134 }
135}
136
137impl ToTokens for Meta {
138 fn to_tokens(&self, tokens: &mut TokenStream) {
139 match self.inner {
140 syn::Meta::Path(ref path) => path.to_tokens(tokens),
141 syn::Meta::List(ref l) => l.to_tokens(tokens),
142 syn::Meta::NameValue(ref n) => n.to_tokens(tokens),
143 }
144 }
145}
146
147#[derive(Debug)]
148pub struct OuterAttributes {
149 pub inner: Vec<syn::Attribute>,
150}
151
152impl Parse for OuterAttributes {
153 fn parse(input: ParseStream) -> Result<Self> {
154 let inner = syn::Attribute::parse_outer(input)?;
155 Ok(OuterAttributes { inner })
156 }
157}
158
159impl ToTokens for OuterAttributes {
160 fn to_tokens(&self, tokens: &mut TokenStream) {
161 for att in self.inner.iter() {
162 att.to_tokens(tokens);
163 }
164 }
165}
166
167pub fn extract_type_option(typ: &syn::Type) -> Option<syn::Type> {
168 if let syn::Type::Path(ref path) = typ {
169 let v = path.path.segments.last()?;
170 if v.ident == "Option" {
171 if let syn::PathArguments::AngleBracketed(a) = &v.arguments {
173 if let syn::GenericArgument::Type(typ) = a.args.last()? {
174 return Some(typ.clone())
175 }
176 }
177 }
178 }
179
180 None
181}
182
183struct ContainsIdent<'a> {
185 ident: &'a Ident,
186 result: bool,
187}
188
189impl<'ast> ContainsIdent<'ast> {
190 fn visit_tokenstream(&mut self, stream: TokenStream) {
191 stream.into_iter().for_each(|tt| match tt {
192 TokenTree::Ident(id) => self.visit_ident(&id),
193 TokenTree::Group(ref group) => self.visit_tokenstream(group.stream()),
194 _ => {},
195 })
196 }
197
198 fn visit_ident(&mut self, ident: &Ident) {
199 if ident == self.ident {
200 self.result = true;
201 }
202 }
203}
204
205impl<'ast> Visit<'ast> for ContainsIdent<'ast> {
206 fn visit_ident(&mut self, input: &'ast Ident) {
207 self.visit_ident(input);
208 }
209
210 fn visit_macro(&mut self, input: &'ast syn::Macro) {
211 self.visit_tokenstream(input.tokens.clone());
212 visit::visit_macro(self, input);
213 }
214}
215
216pub fn type_contains_ident(typ: &syn::Type, ident: &Ident) -> bool {
218 let mut visit = ContainsIdent { result: false, ident };
219
220 visit::visit_type(&mut visit, typ);
221 visit.result
222}
223
224pub fn expr_contains_ident(expr: &syn::Expr, ident: &Ident) -> bool {
226 let mut visit = ContainsIdent { result: false, ident };
227
228 visit::visit_expr(&mut visit, expr);
229 visit.result
230}