// SPDX-License-Identifier: GPL-2.0use 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), ); }}
// 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),
);
}
}