pinned_drop.rs 1.7 KB

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