1use 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 let last = rest.pop();
17 let mut new_impl_generics = Vec::with_capacity(impl_generics.len());
19 let mut in_generic = !impl_generics.is_empty();
21 let mut inserted = false;
23 let mut nested = 0;
25 for tt in impl_generics {
26 match &tt {
27 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 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}