1#![no_std]
2
3use quote::quote;
4use syn::parse_macro_input;
5use syn::Token;
6
7#[proc_macro]
8pub fn defr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 parse_macro_input!(input as Tts).0.into()
10}
11
12struct Tts(proc_macro2::TokenStream);
13
14impl syn::parse::Parse for Tts {
15 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
16 let exprs = syn::punctuated::Punctuated::<syn::Expr, Token![;]>::parse_terminated(input)?
17 .into_iter();
18 let b = proc_macro2::Ident::new("__body", proc_macro2::Span::mixed_site());
19 let d = proc_macro2::Ident::new("__defr", proc_macro2::Span::mixed_site());
20 let tts = quote! {
21 let #b = || { #(#exprs;)* };
22 let #d = {
23 #[doc(hidden)]
24 struct __Defr<F: std::ops::FnOnce()>(std::option::Option<F>);
25 impl<F: std::ops::FnOnce()> std::ops::Drop for __Defr<F> {
26 fn drop(&mut self) {
27 self.0.take().unwrap()();
28 }
29 }
30 __Defr(std::option::Option::Some(#b))
31 };
32 };
33 Ok(Tts(tts))
34 }
35}