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