| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| use proc_macro::{Punct, Spacing, TokenStream, TokenTree}; |
| |
| pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { |
| // This proc-macro only does some pre-parsing and then delegates the actual parsing to |
| // `kernel::__pin_data!`. |
| // |
| // In here we only collect the generics, since parsing them in declarative macros is very |
| // elaborate. We also do not need to analyse their structure, we only need to collect them. |
| |
| // `impl_generics`, the declared generics with their bounds. |
| let mut impl_generics = vec![]; |
| // Only the names of the generics, without any bounds. |
| let mut ty_generics = vec![]; |
| // Tokens not related to the generics e.g. the `impl` token. |
| let mut rest = vec![]; |
| // The current level of `<`. |
| let mut nesting = 0; |
| let mut toks = input.into_iter(); |
| // If we are at the beginning of a generic parameter. |
| let mut at_start = true; |
| for tt in &mut toks { |
| match tt.clone() { |
| TokenTree::Punct(p) if p.as_char() == '<' => { |
| if nesting >= 1 { |
| impl_generics.push(tt); |
| } |
| nesting += 1; |
| } |
| TokenTree::Punct(p) if p.as_char() == '>' => { |
| if nesting == 0 { |
| break; |
| } else { |
| nesting -= 1; |
| if nesting >= 1 { |
| impl_generics.push(tt); |
| } |
| if nesting == 0 { |
| break; |
| } |
| } |
| } |
| tt => { |
| if nesting == 1 { |
| match &tt { |
| TokenTree::Ident(i) if i.to_string() == "const" => {} |
| TokenTree::Ident(_) if at_start => { |
| ty_generics.push(tt.clone()); |
| ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); |
| at_start = false; |
| } |
| TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, |
| TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { |
| ty_generics.push(tt.clone()); |
| } |
| _ => {} |
| } |
| } |
| if nesting >= 1 { |
| impl_generics.push(tt); |
| } else if nesting == 0 { |
| rest.push(tt); |
| } |
| } |
| } |
| } |
| rest.extend(toks); |
| // This should be the body of the struct `{...}`. |
| let last = rest.pop(); |
| quote!(::kernel::__pin_data! { |
| parse_input: |
| @args(#args), |
| @sig(#(#rest)*), |
| @impl_generics(#(#impl_generics)*), |
| @ty_generics(#(#ty_generics)*), |
| @body(#last), |
| }) |
| } |