brintos

brintos / linux-shallow public Read only

0
0
Text · 2.6 KiB · cfee2ce Raw
74 lines · rust
1// SPDX-License-Identifier: GPL-2.02 3use crate::helpers::{parse_generics, Generics};4use proc_macro::{TokenStream, TokenTree};5 6pub(crate) fn derive(input: TokenStream) -> TokenStream {7    let (8        Generics {9            impl_generics,10            decl_generics: _,11            ty_generics,12        },13        mut rest,14    ) = parse_generics(input);15    // This should be the body of the struct `{...}`.16    let last = rest.pop();17    // Now we insert `Zeroable` as a bound for every generic parameter in `impl_generics`.18    let mut new_impl_generics = Vec::with_capacity(impl_generics.len());19    // Are we inside of a generic where we want to add `Zeroable`?20    let mut in_generic = !impl_generics.is_empty();21    // Have we already inserted `Zeroable`?22    let mut inserted = false;23    // Level of `<>` nestings.24    let mut nested = 0;25    for tt in impl_generics {26        match &tt {27            // If we find a `,`, then we have finished a generic/constant/lifetime parameter.28            TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => {29                if in_generic && !inserted {30                    new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });31                }32                in_generic = true;33                inserted = false;34                new_impl_generics.push(tt);35            }36            // If we find `'`, then we are entering a lifetime.37            TokenTree::Punct(p) if nested == 0 && p.as_char() == '\'' => {38                in_generic = false;39                new_impl_generics.push(tt);40            }41            TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => {42                new_impl_generics.push(tt);43                if in_generic {44                    new_impl_generics.extend(quote! { ::kernel::init::Zeroable + });45                    inserted = true;46                }47            }48            TokenTree::Punct(p) if p.as_char() == '<' => {49                nested += 1;50                new_impl_generics.push(tt);51            }52            TokenTree::Punct(p) if p.as_char() == '>' => {53                assert!(nested > 0);54                nested -= 1;55                new_impl_generics.push(tt);56            }57            _ => new_impl_generics.push(tt),58        }59    }60    assert_eq!(nested, 0);61    if in_generic && !inserted {62        new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });63    }64    quote! {65        ::kernel::__derive_zeroable!(66            parse_input:67                @sig(#(#rest)*),68                @impl_generics(#(#new_impl_generics)*),69                @ty_generics(#(#ty_generics)*),70                @body(#last),71        );72    }73}74