1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
//! <h5>Procedural macro for recursive async functions</h5> //! //! Consider the following recursive implementation of the fibonacci numbers: //! //! ```compile_fail //! async fn fib(n : u32) -> u64 { //! match n { //! 0 => panic!("zero is not a valid argument to fib()!"), //! 1 | 2 => 1, //! 3 => 2, //! _ => fib(n-1).await + fib(n-2).await //! } //! } //! ``` //! //! The compiler helpfully tells us that: //! //! ```console //! error[E0733]: recursion in an `async fn` requires boxing //! --> src/main.rs:1:26 //! | //! 1 | async fn fib(n : u32) -> u64 { //! | ^^^ recursive `async fn` //! | //! = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`. //! ``` //! //! This crate provides an attribute macro to automatically convert an async recursive function //! to one returning a boxed Future. //! //! This crate provides an attribute macro to automatically convert async fn f(...) -> ReturnType //! to a fn f(...) -> Pin<Box<dyn Future<Output = ReturnType> + Send>> //! //! # Example //! //! ``` //! use async_recursion::async_recursion; //! //! #[async_recursion] //! async fn fib(n : u32) -> u64 { //! match n { //! 0 => panic!("zero is not a valid argument to fib()!"), //! 1 | 2 => 1, //! 3 => 2, //! _ => fib(n-1).await + fib(n-2).await //! } //! } //! ``` //! //! # Limitations //! Currently the macro doesn't consider lifetimes at all; this is something I plan to work //! on in the future. //! //! ### License //! Licensed under either of //! * Apache License, Version 2.0 //! ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) //! * MIT license //! ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) //! at your option. extern crate proc_macro; mod parse; mod expand; use crate::parse::AsyncItem; use crate::expand::expand; use proc_macro::TokenStream; use syn::parse_macro_input; use quote::quote; #[proc_macro_attribute] pub fn async_recursion(_args: TokenStream, input: TokenStream) -> TokenStream { let mut item = parse_macro_input!(input as AsyncItem); expand(&mut item); TokenStream::from(quote!(#item)) }