defr/
lib.rs

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}