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