recursive_proc_macro_impl/
lib.rs

1//! This is a helper crate for the `recursive` crate, containing the procedural macro.
2
3use proc_macro::TokenStream;
4use quote::{quote, ToTokens};
5use syn::{parse_macro_input, ItemFn, ReturnType, Type};
6
7#[proc_macro_attribute]
8pub fn recursive(args: TokenStream, item: TokenStream) -> TokenStream {
9    let arg_parser = syn::meta::parser(|meta| {
10        Err(meta.error("#[recursive] does not have configuration options"))
11    });
12    parse_macro_input!(args with arg_parser);
13
14    let mut item_fn: ItemFn =
15        syn::parse(item.clone()).expect("#[recursive] can only be applied to functions");
16    assert!(
17        item_fn.sig.asyncness.is_none(),
18        "#[recursive] does not support async functions"
19    );
20
21    let block = item_fn.block;
22    let ret = match &item_fn.sig.output {
23        // impl trait is not supported in closure return type, override with
24        // default, which is inferring.
25        ReturnType::Type(_, typ) if matches!(**typ, Type::ImplTrait(_)) => ReturnType::Default,
26        _ => item_fn.sig.output.clone(),
27    };
28    let wrapped_block = quote! {
29        {
30            ::recursive::__impl::stacker::maybe_grow(
31                ::recursive::get_minimum_stack_size(),
32                ::recursive::get_stack_allocation_size(),
33                move || #ret { #block }
34            )
35        }
36    };
37    item_fn.block = Box::new(syn::parse(wrapped_block.into()).unwrap());
38    item_fn.into_token_stream().into()
39}