diff options
| author | Maxime Ripard <mripard@kernel.org> | 2023-07-11 09:23:20 +0200 | 
|---|---|---|
| committer | Maxime Ripard <mripard@kernel.org> | 2023-07-11 09:23:20 +0200 | 
| commit | 2f98e686ef59b5d19af5847d755798e2031bee3a (patch) | |
| tree | 7b47919242853d088decf898ca79d6cda0d49381 /rust/macros/helpers.rs | |
| parent | a2848d08742c8e8494675892c02c0d22acbe3cf8 (diff) | |
| parent | 06c2afb862f9da8dc5efa4b6076a0e48c3fbaaa5 (diff) | |
Merge v6.5-rc1 into drm-misc-fixes
Boris needs 6.5-rc1 in drm-misc-fixes to prevent a conflict.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
Diffstat (limited to 'rust/macros/helpers.rs')
| -rw-r--r-- | rust/macros/helpers.rs | 86 | 
1 files changed, 85 insertions, 1 deletions
diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs index b2bdd4d8c958..afb0f2e3a36a 100644 --- a/rust/macros/helpers.rs +++ b/rust/macros/helpers.rs @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 -use proc_macro::{token_stream, Group, TokenTree}; +use proc_macro::{token_stream, Group, Punct, Spacing, TokenStream, TokenTree};  pub(crate) fn try_ident(it: &mut token_stream::IntoIter) -> Option<String> {      if let Some(TokenTree::Ident(ident)) = it.next() { @@ -69,3 +69,87 @@ pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {          panic!("Expected end");      }  } + +pub(crate) struct Generics { +    pub(crate) impl_generics: Vec<TokenTree>, +    pub(crate) ty_generics: Vec<TokenTree>, +} + +/// Parses the given `TokenStream` into `Generics` and the rest. +/// +/// The generics are not present in the rest, but a where clause might remain. +pub(crate) fn parse_generics(input: TokenStream) -> (Generics, Vec<TokenTree>) { +    // `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 `where` token and definition. +    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 { +                    // This is inside of the generics and part of some bound. +                    impl_generics.push(tt); +                } +                nesting += 1; +            } +            TokenTree::Punct(p) if p.as_char() == '>' => { +                // This is a parsing error, so we just end it here. +                if nesting == 0 { +                    break; +                } else { +                    nesting -= 1; +                    if nesting >= 1 { +                        // We are still inside of the generics and part of some bound. +                        impl_generics.push(tt); +                    } +                    if nesting == 0 { +                        break; +                    } +                } +            } +            tt => { +                if nesting == 1 { +                    // Here depending on the token, it might be a generic variable name. +                    match &tt { +                        // Ignore const. +                        TokenTree::Ident(i) if i.to_string() == "const" => {} +                        TokenTree::Ident(_) if at_start => { +                            ty_generics.push(tt.clone()); +                            // We also already push the `,` token, this makes it easier to append +                            // generics. +                            ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); +                            at_start = false; +                        } +                        TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, +                        // Lifetimes begin with `'`. +                        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 { +                    // If we haven't entered the generics yet, we still want to keep these tokens. +                    rest.push(tt); +                } +            } +        } +    } +    rest.extend(toks); +    ( +        Generics { +            impl_generics, +            ty_generics, +        }, +        rest, +    ) +}  | 
