xref: /linux/rust/pin-init/internal/src/zeroable.rs (revision ec7714e4947909190ffb3041a03311a975350fe0)
1fbf8fb32SBenno Lossin // SPDX-License-Identifier: GPL-2.0
2fbf8fb32SBenno Lossin 
37cb5dee4SBenno Lossin #[cfg(not(kernel))]
47cb5dee4SBenno Lossin use proc_macro2 as proc_macro;
57cb5dee4SBenno Lossin 
6fbf8fb32SBenno Lossin use crate::helpers::{parse_generics, Generics};
7fbf8fb32SBenno Lossin use proc_macro::{TokenStream, TokenTree};
8fbf8fb32SBenno Lossin 
parse_zeroable_derive_input( input: TokenStream, ) -> ( Vec<TokenTree>, Vec<TokenTree>, Vec<TokenTree>, Option<TokenTree>, )9*00fccd3eSBenno Lossin pub(crate) fn parse_zeroable_derive_input(
10*00fccd3eSBenno Lossin     input: TokenStream,
11*00fccd3eSBenno Lossin ) -> (
12*00fccd3eSBenno Lossin     Vec<TokenTree>,
13*00fccd3eSBenno Lossin     Vec<TokenTree>,
14*00fccd3eSBenno Lossin     Vec<TokenTree>,
15*00fccd3eSBenno Lossin     Option<TokenTree>,
16*00fccd3eSBenno Lossin ) {
17fbf8fb32SBenno Lossin     let (
18fbf8fb32SBenno Lossin         Generics {
19fbf8fb32SBenno Lossin             impl_generics,
20fbf8fb32SBenno Lossin             decl_generics: _,
21fbf8fb32SBenno Lossin             ty_generics,
22fbf8fb32SBenno Lossin         },
23fbf8fb32SBenno Lossin         mut rest,
24fbf8fb32SBenno Lossin     ) = parse_generics(input);
25fbf8fb32SBenno Lossin     // This should be the body of the struct `{...}`.
26fbf8fb32SBenno Lossin     let last = rest.pop();
27fbf8fb32SBenno Lossin     // Now we insert `Zeroable` as a bound for every generic parameter in `impl_generics`.
28fbf8fb32SBenno Lossin     let mut new_impl_generics = Vec::with_capacity(impl_generics.len());
29fbf8fb32SBenno Lossin     // Are we inside of a generic where we want to add `Zeroable`?
30fbf8fb32SBenno Lossin     let mut in_generic = !impl_generics.is_empty();
31fbf8fb32SBenno Lossin     // Have we already inserted `Zeroable`?
32fbf8fb32SBenno Lossin     let mut inserted = false;
33fbf8fb32SBenno Lossin     // Level of `<>` nestings.
34fbf8fb32SBenno Lossin     let mut nested = 0;
35fbf8fb32SBenno Lossin     for tt in impl_generics {
36fbf8fb32SBenno Lossin         match &tt {
37fbf8fb32SBenno Lossin             // If we find a `,`, then we have finished a generic/constant/lifetime parameter.
38fbf8fb32SBenno Lossin             TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => {
39fbf8fb32SBenno Lossin                 if in_generic && !inserted {
40dbd5058bSBenno Lossin                     new_impl_generics.extend(quote! { : ::pin_init::Zeroable });
41fbf8fb32SBenno Lossin                 }
42fbf8fb32SBenno Lossin                 in_generic = true;
43fbf8fb32SBenno Lossin                 inserted = false;
44fbf8fb32SBenno Lossin                 new_impl_generics.push(tt);
45fbf8fb32SBenno Lossin             }
46fbf8fb32SBenno Lossin             // If we find `'`, then we are entering a lifetime.
47fbf8fb32SBenno Lossin             TokenTree::Punct(p) if nested == 0 && p.as_char() == '\'' => {
48fbf8fb32SBenno Lossin                 in_generic = false;
49fbf8fb32SBenno Lossin                 new_impl_generics.push(tt);
50fbf8fb32SBenno Lossin             }
51fbf8fb32SBenno Lossin             TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => {
52fbf8fb32SBenno Lossin                 new_impl_generics.push(tt);
53fbf8fb32SBenno Lossin                 if in_generic {
54dbd5058bSBenno Lossin                     new_impl_generics.extend(quote! { ::pin_init::Zeroable + });
55fbf8fb32SBenno Lossin                     inserted = true;
56fbf8fb32SBenno Lossin                 }
57fbf8fb32SBenno Lossin             }
58fbf8fb32SBenno Lossin             TokenTree::Punct(p) if p.as_char() == '<' => {
59fbf8fb32SBenno Lossin                 nested += 1;
60fbf8fb32SBenno Lossin                 new_impl_generics.push(tt);
61fbf8fb32SBenno Lossin             }
62fbf8fb32SBenno Lossin             TokenTree::Punct(p) if p.as_char() == '>' => {
63fbf8fb32SBenno Lossin                 assert!(nested > 0);
64fbf8fb32SBenno Lossin                 nested -= 1;
65fbf8fb32SBenno Lossin                 new_impl_generics.push(tt);
66fbf8fb32SBenno Lossin             }
67fbf8fb32SBenno Lossin             _ => new_impl_generics.push(tt),
68fbf8fb32SBenno Lossin         }
69fbf8fb32SBenno Lossin     }
70fbf8fb32SBenno Lossin     assert_eq!(nested, 0);
71fbf8fb32SBenno Lossin     if in_generic && !inserted {
72dbd5058bSBenno Lossin         new_impl_generics.extend(quote! { : ::pin_init::Zeroable });
73fbf8fb32SBenno Lossin     }
74*00fccd3eSBenno Lossin     (rest, new_impl_generics, ty_generics, last)
75*00fccd3eSBenno Lossin }
76*00fccd3eSBenno Lossin 
derive(input: TokenStream) -> TokenStream77*00fccd3eSBenno Lossin pub(crate) fn derive(input: TokenStream) -> TokenStream {
78*00fccd3eSBenno Lossin     let (rest, new_impl_generics, ty_generics, last) = parse_zeroable_derive_input(input);
79fbf8fb32SBenno Lossin     quote! {
80dbd5058bSBenno Lossin         ::pin_init::__derive_zeroable!(
81fbf8fb32SBenno Lossin             parse_input:
82fbf8fb32SBenno Lossin                 @sig(#(#rest)*),
83fbf8fb32SBenno Lossin                 @impl_generics(#(#new_impl_generics)*),
84fbf8fb32SBenno Lossin                 @ty_generics(#(#ty_generics)*),
85fbf8fb32SBenno Lossin                 @body(#last),
86fbf8fb32SBenno Lossin         );
87fbf8fb32SBenno Lossin     }
88fbf8fb32SBenno Lossin }
89*00fccd3eSBenno Lossin 
maybe_derive(input: TokenStream) -> TokenStream90*00fccd3eSBenno Lossin pub(crate) fn maybe_derive(input: TokenStream) -> TokenStream {
91*00fccd3eSBenno Lossin     let (rest, new_impl_generics, ty_generics, last) = parse_zeroable_derive_input(input);
92*00fccd3eSBenno Lossin     quote! {
93*00fccd3eSBenno Lossin         ::pin_init::__maybe_derive_zeroable!(
94*00fccd3eSBenno Lossin             parse_input:
95*00fccd3eSBenno Lossin                 @sig(#(#rest)*),
96*00fccd3eSBenno Lossin                 @impl_generics(#(#new_impl_generics)*),
97*00fccd3eSBenno Lossin                 @ty_generics(#(#ty_generics)*),
98*00fccd3eSBenno Lossin                 @body(#last),
99*00fccd3eSBenno Lossin         );
100*00fccd3eSBenno Lossin     }
101*00fccd3eSBenno Lossin }
102