diff --git a/src/expand.rs b/src/expand.rs index fae434e..785fc14 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -184,6 +184,12 @@ fn transform_sig(sig: &mut Signature, args: &RecursionArgs) { quote!() }; + let sync_bound: TokenStream = if args.sync_bound { + quote!(+ ::core::marker::Sync) + } else { + quote!() + }; + let where_clause = sig .generics .where_clause @@ -207,6 +213,6 @@ fn transform_sig(sig: &mut Signature, args: &RecursionArgs) { // Modify the return type sig.output = parse_quote! { -> ::core::pin::Pin #box_lifetime #send_bound >> + dyn ::core::future::Future #box_lifetime #send_bound #sync_bound >> }; } diff --git a/src/parse.rs b/src/parse.rs index 728dcbf..0785402 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -22,30 +22,48 @@ impl Parse for AsyncItem { pub struct RecursionArgs { pub send_bound: bool, + pub sync_bound: bool, } impl Default for RecursionArgs { fn default() -> Self { - RecursionArgs { send_bound: true } + RecursionArgs { + send_bound: true, + sync_bound: false, + } } } /// Custom keywords for parser mod kw { syn::custom_keyword!(Send); + syn::custom_keyword!(Sync); } impl Parse for RecursionArgs { fn parse(input: ParseStream) -> Result { + let Self { + mut send_bound, + mut sync_bound, + } = Self::default(); // Check for the `?Send` option if input.peek(Token![?]) { input.parse::()?; input.parse::()?; - Ok(Self { send_bound: false }) - } else if !input.is_empty() { + send_bound = false; + } + if input.peek(kw::Sync) { + input.parse::()?; + sync_bound = true; + } + + if !input.is_empty() { Err(input.error("expected `?Send` or empty")) } else { - Ok(Self::default()) + Ok(Self { + send_bound, + sync_bound, + }) } } } diff --git a/tests/sync.rs b/tests/sync.rs new file mode 100644 index 0000000..31566b3 --- /dev/null +++ b/tests/sync.rs @@ -0,0 +1,21 @@ +use std::future::pending; + +use async_recursion::async_recursion; + + +#[async_recursion(Sync)] +async fn send_plus_sync() { + pending::<()>().await; + +} + +#[async_recursion(?Send Sync)] +async fn only_sync() { + pending::<()>().await; +} + +#[async_recursion(?Send)] +async fn neither() { + pending::<()>().await; + +} \ No newline at end of file