xref: /openbmc/linux/rust/macros/pinned_drop.rs (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1*d0fdc396SBenno Lossin // SPDX-License-Identifier: Apache-2.0 OR MIT
2*d0fdc396SBenno Lossin 
3*d0fdc396SBenno Lossin use proc_macro::{TokenStream, TokenTree};
4*d0fdc396SBenno Lossin 
pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream5*d0fdc396SBenno Lossin pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream {
6*d0fdc396SBenno Lossin     let mut toks = input.into_iter().collect::<Vec<_>>();
7*d0fdc396SBenno Lossin     assert!(!toks.is_empty());
8*d0fdc396SBenno Lossin     // Ensure that we have an `impl` item.
9*d0fdc396SBenno Lossin     assert!(matches!(&toks[0], TokenTree::Ident(i) if i.to_string() == "impl"));
10*d0fdc396SBenno Lossin     // Ensure that we are implementing `PinnedDrop`.
11*d0fdc396SBenno Lossin     let mut nesting: usize = 0;
12*d0fdc396SBenno Lossin     let mut pinned_drop_idx = None;
13*d0fdc396SBenno Lossin     for (i, tt) in toks.iter().enumerate() {
14*d0fdc396SBenno Lossin         match tt {
15*d0fdc396SBenno Lossin             TokenTree::Punct(p) if p.as_char() == '<' => {
16*d0fdc396SBenno Lossin                 nesting += 1;
17*d0fdc396SBenno Lossin             }
18*d0fdc396SBenno Lossin             TokenTree::Punct(p) if p.as_char() == '>' => {
19*d0fdc396SBenno Lossin                 nesting = nesting.checked_sub(1).unwrap();
20*d0fdc396SBenno Lossin                 continue;
21*d0fdc396SBenno Lossin             }
22*d0fdc396SBenno Lossin             _ => {}
23*d0fdc396SBenno Lossin         }
24*d0fdc396SBenno Lossin         if i >= 1 && nesting == 0 {
25*d0fdc396SBenno Lossin             // Found the end of the generics, this should be `PinnedDrop`.
26*d0fdc396SBenno Lossin             assert!(
27*d0fdc396SBenno Lossin                 matches!(tt, TokenTree::Ident(i) if i.to_string() == "PinnedDrop"),
28*d0fdc396SBenno Lossin                 "expected 'PinnedDrop', found: '{:?}'",
29*d0fdc396SBenno Lossin                 tt
30*d0fdc396SBenno Lossin             );
31*d0fdc396SBenno Lossin             pinned_drop_idx = Some(i);
32*d0fdc396SBenno Lossin             break;
33*d0fdc396SBenno Lossin         }
34*d0fdc396SBenno Lossin     }
35*d0fdc396SBenno Lossin     let idx = pinned_drop_idx
36*d0fdc396SBenno Lossin         .unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`."));
37*d0fdc396SBenno Lossin     // Fully qualify the `PinnedDrop`, as to avoid any tampering.
38*d0fdc396SBenno Lossin     toks.splice(idx..idx, quote!(::kernel::init::));
39*d0fdc396SBenno Lossin     // Take the `{}` body and call the declarative macro.
40*d0fdc396SBenno Lossin     if let Some(TokenTree::Group(last)) = toks.pop() {
41*d0fdc396SBenno Lossin         let last = last.stream();
42*d0fdc396SBenno Lossin         quote!(::kernel::__pinned_drop! {
43*d0fdc396SBenno Lossin             @impl_sig(#(#toks)*),
44*d0fdc396SBenno Lossin             @impl_body(#last),
45*d0fdc396SBenno Lossin         })
46*d0fdc396SBenno Lossin     } else {
47*d0fdc396SBenno Lossin         TokenStream::from_iter(toks)
48*d0fdc396SBenno Lossin     }
49*d0fdc396SBenno Lossin }
50