pinned_drop.rs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  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: '{:?}'",
  27. tt
  28. );
  29. pinned_drop_idx = Some(i);
  30. break;
  31. }
  32. }
  33. let idx = pinned_drop_idx
  34. .unwrap_or_else(|| panic!("Expected an `impl` block implementing `PinnedDrop`."));
  35. // Fully qualify the `PinnedDrop`, as to avoid any tampering.
  36. toks.splice(idx..idx, quote!(::kernel::init::));
  37. // Take the `{}` body and call the declarative macro.
  38. if let Some(TokenTree::Group(last)) = toks.pop() {
  39. let last = last.stream();
  40. quote!(::kernel::__pinned_drop! {
  41. @impl_sig(#(#toks)*),
  42. @impl_body(#last),
  43. })
  44. } else {
  45. TokenStream::from_iter(toks)
  46. }
  47. }