pin_init_internal/
pinned_drop.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3#[cfg(not(kernel))]
4use proc_macro2 as proc_macro;
5
6use proc_macro::{TokenStream, TokenTree};
7
8pub(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: '{:?}'",
32                tt
33            );
34            pinned_drop_idx = Some(i);
35            break;
36        }
37    }
38    let idx = pinned_drop_idx
39        .unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`."));
40    // Fully qualify the `PinnedDrop`, as to avoid any tampering.
41    toks.splice(idx..idx, quote!(::pin_init::));
42    // Take the `{}` body and call the declarative macro.
43    if let Some(TokenTree::Group(last)) = toks.pop() {
44        let last = last.stream();
45        quote!(::pin_init::__pinned_drop! {
46            @impl_sig(#(#toks)*),
47            @impl_body(#last),
48        })
49    } else {
50        TokenStream::from_iter(toks)
51    }
52}