73 lines · 2.6 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 use crate::helpers::{parse_generics, Generics};use proc_macro::{TokenStream, TokenTree}; pub(crate) fn derive(input: TokenStream) -> TokenStream {    let (        Generics {            impl_generics,            decl_generics: _,            ty_generics,        },        mut rest,    ) = parse_generics(input);    // This should be the body of the struct `{...}`.    let last = rest.pop();    // Now we insert `Zeroable` as a bound for every generic parameter in `impl_generics`.    let mut new_impl_generics = Vec::with_capacity(impl_generics.len());    // Are we inside of a generic where we want to add `Zeroable`?    let mut in_generic = !impl_generics.is_empty();    // Have we already inserted `Zeroable`?    let mut inserted = false;    // Level of `<>` nestings.    let mut nested = 0;    for tt in impl_generics {        match &tt {            // If we find a `,`, then we have finished a generic/constant/lifetime parameter.            TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => {                if in_generic && !inserted {                    new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });                }                in_generic = true;                inserted = false;                new_impl_generics.push(tt);            }            // If we find `'`, then we are entering a lifetime.            TokenTree::Punct(p) if nested == 0 && p.as_char() == '\'' => {                in_generic = false;                new_impl_generics.push(tt);            }            TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => {                new_impl_generics.push(tt);                if in_generic {                    new_impl_generics.extend(quote! { ::kernel::init::Zeroable + });                    inserted = true;                }            }            TokenTree::Punct(p) if p.as_char() == '<' => {                nested += 1;                new_impl_generics.push(tt);            }            TokenTree::Punct(p) if p.as_char() == '>' => {                assert!(nested > 0);                nested -= 1;                new_impl_generics.push(tt);            }            _ => new_impl_generics.push(tt),        }    }    assert_eq!(nested, 0);    if in_generic && !inserted {        new_impl_generics.extend(quote! { : ::kernel::init::Zeroable });    }    quote! {        ::kernel::__derive_zeroable!(            parse_input:                @sig(#(#rest)*),                @impl_generics(#(#new_impl_generics)*),                @ty_generics(#(#ty_generics)*),                @body(#last),        );    }}