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