162306a36Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 OR MIT
262306a36Sopenharmony_ci
362306a36Sopenharmony_ciuse proc_macro::{TokenStream, TokenTree};
462306a36Sopenharmony_ci
562306a36Sopenharmony_cipub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream {
662306a36Sopenharmony_ci    let mut toks = input.into_iter().collect::<Vec<_>>();
762306a36Sopenharmony_ci    assert!(!toks.is_empty());
862306a36Sopenharmony_ci    // Ensure that we have an `impl` item.
962306a36Sopenharmony_ci    assert!(matches!(&toks[0], TokenTree::Ident(i) if i.to_string() == "impl"));
1062306a36Sopenharmony_ci    // Ensure that we are implementing `PinnedDrop`.
1162306a36Sopenharmony_ci    let mut nesting: usize = 0;
1262306a36Sopenharmony_ci    let mut pinned_drop_idx = None;
1362306a36Sopenharmony_ci    for (i, tt) in toks.iter().enumerate() {
1462306a36Sopenharmony_ci        match tt {
1562306a36Sopenharmony_ci            TokenTree::Punct(p) if p.as_char() == '<' => {
1662306a36Sopenharmony_ci                nesting += 1;
1762306a36Sopenharmony_ci            }
1862306a36Sopenharmony_ci            TokenTree::Punct(p) if p.as_char() == '>' => {
1962306a36Sopenharmony_ci                nesting = nesting.checked_sub(1).unwrap();
2062306a36Sopenharmony_ci                continue;
2162306a36Sopenharmony_ci            }
2262306a36Sopenharmony_ci            _ => {}
2362306a36Sopenharmony_ci        }
2462306a36Sopenharmony_ci        if i >= 1 && nesting == 0 {
2562306a36Sopenharmony_ci            // Found the end of the generics, this should be `PinnedDrop`.
2662306a36Sopenharmony_ci            assert!(
2762306a36Sopenharmony_ci                matches!(tt, TokenTree::Ident(i) if i.to_string() == "PinnedDrop"),
2862306a36Sopenharmony_ci                "expected 'PinnedDrop', found: '{:?}'",
2962306a36Sopenharmony_ci                tt
3062306a36Sopenharmony_ci            );
3162306a36Sopenharmony_ci            pinned_drop_idx = Some(i);
3262306a36Sopenharmony_ci            break;
3362306a36Sopenharmony_ci        }
3462306a36Sopenharmony_ci    }
3562306a36Sopenharmony_ci    let idx = pinned_drop_idx
3662306a36Sopenharmony_ci        .unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`."));
3762306a36Sopenharmony_ci    // Fully qualify the `PinnedDrop`, as to avoid any tampering.
3862306a36Sopenharmony_ci    toks.splice(idx..idx, quote!(::kernel::init::));
3962306a36Sopenharmony_ci    // Take the `{}` body and call the declarative macro.
4062306a36Sopenharmony_ci    if let Some(TokenTree::Group(last)) = toks.pop() {
4162306a36Sopenharmony_ci        let last = last.stream();
4262306a36Sopenharmony_ci        quote!(::kernel::__pinned_drop! {
4362306a36Sopenharmony_ci            @impl_sig(#(#toks)*),
4462306a36Sopenharmony_ci            @impl_body(#last),
4562306a36Sopenharmony_ci        })
4662306a36Sopenharmony_ci    } else {
4762306a36Sopenharmony_ci        TokenStream::from_iter(toks)
4862306a36Sopenharmony_ci    }
4962306a36Sopenharmony_ci}
50