| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| use proc_macro::{TokenStream, TokenTree}; | |
| pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream { | |
| let mut toks = input.into_iter().collect::<Vec<_>>(); | |
| assert!(!toks.is_empty()); | |
| // Ensure that we have an `impl` item. | |
| assert!(matches!(&toks[0], TokenTree::Ident(i) if i.to_string() == "impl")); | |
| // Ensure that we are implementing `PinnedDrop`. | |
| let mut nesting: usize = 0; | |
| let mut pinned_drop_idx = None; | |
| for (i, tt) in toks.iter().enumerate() { | |
| match tt { | |
| TokenTree::Punct(p) if p.as_char() == '<' => { | |
| nesting += 1; | |
| } | |
| TokenTree::Punct(p) if p.as_char() == '>' => { | |
| nesting = nesting.checked_sub(1).unwrap(); | |
| continue; | |
| } | |
| _ => {} | |
| } | |
| if i >= 1 && nesting == 0 { | |
| // Found the end of the generics, this should be `PinnedDrop`. | |
| assert!( | |
| matches!(tt, TokenTree::Ident(i) if i.to_string() == "PinnedDrop"), | |
| "expected 'PinnedDrop', found: '{:?}'", | |
| tt | |
| ); | |
| pinned_drop_idx = Some(i); | |
| break; | |
| } | |
| } | |
| let idx = pinned_drop_idx | |
| .unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`.")); | |
| // Fully qualify the `PinnedDrop`, as to avoid any tampering. | |
| toks.splice(idx..idx, quote!(::kernel::init::)); | |
| // Take the `{}` body and call the declarative macro. | |
| if let Some(TokenTree::Group(last)) = toks.pop() { | |
| let last = last.stream(); | |
| quote!(::kernel::__pinned_drop! { | |
| @impl_sig(#(#toks)*), | |
| @impl_body(#last), | |
| }) | |
| } else { | |
| TokenStream::from_iter(toks) | |
| } | |
| } |