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