1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 #[cfg(not(kernel))] 4 use proc_macro2 as proc_macro; 5 6 use proc_macro::{TokenStream, TokenTree}; 7 8 /// Parsed generics. 9 /// 10 /// See the field documentation for an explanation what each of the fields represents. 11 /// 12 /// # Examples 13 /// 14 /// ```rust,ignore 15 /// # let input = todo!(); 16 /// let (Generics { decl_generics, impl_generics, ty_generics }, rest) = parse_generics(input); 17 /// quote! { 18 /// struct Foo<$($decl_generics)*> { 19 /// // ... 20 /// } 21 /// 22 /// impl<$impl_generics> Foo<$ty_generics> { 23 /// fn foo() { 24 /// // ... 25 /// } 26 /// } 27 /// } 28 /// ``` 29 pub(crate) struct Generics { 30 /// The generics with bounds and default values (e.g. `T: Clone, const N: usize = 0`). 31 /// 32 /// Use this on type definitions e.g. `struct Foo<$decl_generics> ...` (or `union`/`enum`). 33 pub(crate) decl_generics: Vec<TokenTree>, 34 /// The generics with bounds (e.g. `T: Clone, const N: usize`). 35 /// 36 /// Use this on `impl` blocks e.g. `impl<$impl_generics> Trait for ...`. 37 pub(crate) impl_generics: Vec<TokenTree>, 38 /// The generics without bounds and without default values (e.g. `T, N`). 39 /// 40 /// Use this when you use the type that is declared with these generics e.g. 41 /// `Foo<$ty_generics>`. 42 pub(crate) ty_generics: Vec<TokenTree>, 43 } 44 45 /// Parses the given `TokenStream` into `Generics` and the rest. 46 /// 47 /// The generics are not present in the rest, but a where clause might remain. 48 pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { 49 // The generics with bounds and default values. 50 let mut decl_generics = vec![]; 51 // `impl_generics`, the declared generics with their bounds. 52 let mut impl_generics = vec![]; 53 // Only the names of the generics, without any bounds. 54 let mut ty_generics = vec![]; 55 // Tokens not related to the generics e.g. the `where` token and definition. 56 let mut rest = vec![]; 57 // The current level of `<`. 58 let mut nesting = 0; 59 let mut toks = input.into_iter(); 60 // If we are at the beginning of a generic parameter. 61 let mut at_start = true; 62 let mut skip_until_comma = false; 63 while let Some(tt) = toks.next() { 64 if nesting == 1 && matches!(&tt, TokenTree::Punct(p) if p.as_char() == '>') { 65 // Found the end of the generics. 66 break; 67 } else if nesting >= 1 { 68 decl_generics.push(tt.clone()); 69 } 70 match tt.clone() { 71 TokenTree::Punct(p) if p.as_char() == '<' => { 72 if nesting >= 1 && !skip_until_comma { 73 // This is inside of the generics and part of some bound. 74 impl_generics.push(tt); 75 } 76 nesting += 1; 77 } 78 TokenTree::Punct(p) if p.as_char() == '>' => { 79 // This is a parsing error, so we just end it here. 80 if nesting == 0 { 81 break; 82 } else { 83 nesting -= 1; 84 if nesting >= 1 && !skip_until_comma { 85 // We are still inside of the generics and part of some bound. 86 impl_generics.push(tt); 87 } 88 } 89 } 90 TokenTree::Punct(p) if skip_until_comma && p.as_char() == ',' => { 91 if nesting == 1 { 92 impl_generics.push(tt.clone()); 93 impl_generics.push(tt); 94 skip_until_comma = false; 95 } 96 } 97 _ if !skip_until_comma => { 98 match nesting { 99 // If we haven't entered the generics yet, we still want to keep these tokens. 100 0 => rest.push(tt), 101 1 => { 102 // Here depending on the token, it might be a generic variable name. 103 match tt.clone() { 104 TokenTree::Ident(i) if at_start && i.to_string() == "const" => { 105 let Some(name) = toks.next() else { 106 // Parsing error. 107 break; 108 }; 109 impl_generics.push(tt); 110 impl_generics.push(name.clone()); 111 ty_generics.push(name.clone()); 112 decl_generics.push(name); 113 at_start = false; 114 } 115 TokenTree::Ident(_) if at_start => { 116 impl_generics.push(tt.clone()); 117 ty_generics.push(tt); 118 at_start = false; 119 } 120 TokenTree::Punct(p) if p.as_char() == ',' => { 121 impl_generics.push(tt.clone()); 122 ty_generics.push(tt); 123 at_start = true; 124 } 125 // Lifetimes begin with `'`. 126 TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { 127 impl_generics.push(tt.clone()); 128 ty_generics.push(tt); 129 } 130 // Generics can have default values, we skip these. 131 TokenTree::Punct(p) if p.as_char() == '=' => { 132 skip_until_comma = true; 133 } 134 _ => impl_generics.push(tt), 135 } 136 } 137 _ => impl_generics.push(tt), 138 } 139 } 140 _ => {} 141 } 142 } 143 rest.extend(toks); 144 ( 145 Generics { 146 impl_generics, 147 decl_generics, 148 ty_generics, 149 }, 150 rest, 151 ) 152 } 153