Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[package]
name = "async-trait"
version = "0.1.57"
authors = ["David Tolnay <dtolnay@gmail.com>"]
name = "stackfuture-async-trait"
version = "0.1.0"
authors = ["David Tolnay <dtolnay@gmail.com>", "Eric Holk <ericholk@microsoft.com>"]
categories = ["asynchronous", "no-std"]
description = "Type erasure for async trait methods"
documentation = "https://docs.rs/async-trait"
edition = "2018"
documentation = "https://docs.rs/stackfuture-async-trait"
edition = "2021"
keywords = ["async"]
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/dtolnay/async-trait"
rust-version = "1.39"
repository = "https://github.com/eholk/stackfuture-async-trait"
rust-version = "1.56"

[lib]
proc-macro = true
Expand All @@ -23,6 +23,7 @@ syn = { version = "1.0.96", features = ["full", "visit-mut"] }
[dev-dependencies]
futures = "0.3"
rustversion = "1.0"
stackfuture = "0.2.0"
tracing = "0.1.14"
tracing-attributes = "0.1.14"
trybuild = { version = "1.0.49", features = ["diff"] }
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Async trait methods
===================

[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/async--trait-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/async-trait)
[<img alt="crates.io" src="https://img.shields.io/crates/v/async-trait.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/async-trait)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-async--trait-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/async-trait)
[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/async-trait/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)
[<img alt="github" src="https://img.shields.io/badge/github-eholk/async--trait-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/eholk/stackfuture-async-trait)
[<img alt="crates.io" src="https://img.shields.io/crates/v/stackfuture-async-trait.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/stackfuture-async-trait)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-async--trait-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/stackfuture-async-trait)
[<img alt="build status" src="https://img.shields.io/github/workflow/status/eholk/stackfuture-async-trait/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/stackfuture-async-trait/actions?query=branch%3Amaster)

The initial round of stabilizations for the async/await language feature in Rust
1.39 did not include support for async fn in traits. Trying to include an async
Expand Down Expand Up @@ -32,7 +32,10 @@ deliver in the future.

[hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/

<br>
This is a fork of <https://github.com/dtolnay/async-trait> that has been modified to use [StackFuture]
instead of boxing the futures returned by async trait methods.

[StackFuture]: https://crates.io/crates/stackfuture

## Example

Expand Down
26 changes: 18 additions & 8 deletions src/args.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
use proc_macro2::Span;
use syn::parse::{Error, Parse, ParseStream, Result};
use syn::Token;
use syn::{Expr, Token};

#[derive(Copy, Clone)]
#[derive(Clone)]
pub struct Args {
pub local: bool,
pub stack_size: Expr,
}

mod kw {
syn::custom_keyword!(Send);
}

impl Parse for Args {
fn parse(input: ParseStream) -> Result<Self> {
fn parse(input: ParseStream<'_>) -> Result<Self> {
match try_parse(input) {
Ok(args) if input.is_empty() => Ok(args),
_ => Err(error()),
}
}
}

fn try_parse(input: ParseStream) -> Result<Args> {
if input.peek(Token![?]) {
fn try_parse(input: ParseStream<'_>) -> Result<Args> {
let stack_size = input.parse()?;

if input.peek(Token![,]) {
input.parse::<Token![,]>()?;
input.parse::<Token![?]>()?;
input.parse::<kw::Send>()?;
Ok(Args { local: true })
Ok(Args {
local: true,
stack_size,
})
} else {
Ok(Args { local: false })
Ok(Args {
local: false,
stack_size,
})
}
}

fn error() -> Error {
let msg = "expected #[async_trait] or #[async_trait(?Send)]";
let msg = "expected #[async_trait(SIZE)] or #[async_trait(SIZE, ?Send)]";
Error::new(Span::call_site(), msg)
}
27 changes: 11 additions & 16 deletions src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::mem;
use syn::punctuated::Punctuated;
use syn::visit_mut::{self, VisitMut};
use syn::{
parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericParam, Generics, Ident,
parse_quote, parse_quote_spanned, Attribute, Block, Expr, FnArg, GenericParam, Generics, Ident,
ImplItem, Lifetime, LifetimeDef, Pat, PatIdent, Receiver, ReturnType, Signature, Stmt, Token,
TraitItem, Type, TypeParamBound, TypePath, WhereClause,
};
Expand Down Expand Up @@ -53,7 +53,7 @@ impl Context<'_> {

type Supertraits = Punctuated<TypeParamBound, Token![+]>;

pub fn expand(input: &mut Item, is_local: bool) {
pub fn expand(input: &mut Item, is_local: bool, stack_size: &Expr) {
match input {
Item::Trait(input) => {
let context = Context::Trait {
Expand All @@ -75,7 +75,7 @@ pub fn expand(input: &mut Item, is_local: bool) {
method.attrs.push(lint_suppress_without_body());
}
let has_default = method.default.is_some();
transform_sig(context, sig, has_self, has_default, is_local);
transform_sig(context, sig, has_self, has_default, is_local, stack_size);
}
}
}
Expand Down Expand Up @@ -108,7 +108,7 @@ pub fn expand(input: &mut Item, is_local: bool) {
let block = &mut method.block;
let has_self = has_self_in_sig(sig) || has_self_in_block(block);
transform_block(context, sig, block);
transform_sig(context, sig, has_self, false, is_local);
transform_sig(context, sig, has_self, false, is_local, stack_size);
method.attrs.push(lint_suppress_with_body());
}
}
Expand Down Expand Up @@ -153,11 +153,12 @@ fn lint_suppress_without_body() -> Attribute {
// T: 'async_trait,
// Self: Sync + 'async_trait;
fn transform_sig(
context: Context,
context: Context<'_>,
sig: &mut Signature,
has_self: bool,
has_default: bool,
is_local: bool,
stack_size: &Expr,
) {
sig.fn_token.span = sig.asyncness.take().unwrap().span;

Expand Down Expand Up @@ -289,15 +290,9 @@ fn transform_sig(
}

let ret_span = sig.ident.span();
let bounds = if is_local {
quote_spanned!(ret_span=> 'async_trait)
} else {
quote_spanned!(ret_span=> ::core::marker::Send + 'async_trait)
};
let bounds = quote_spanned!(ret_span=> 'async_trait);
sig.output = parse_quote_spanned! {ret_span=>
-> ::core::pin::Pin<Box<
dyn ::core::future::Future<Output = #ret> + #bounds
>>
-> ::stackfuture::StackFuture<#bounds, #ret, #stack_size>
};
}

Expand All @@ -318,7 +313,7 @@ fn transform_sig(
//
// ___ret
// })
fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
fn transform_block(context: Context<'_>, sig: &mut Signature, block: &mut Block) {
if let Some(Stmt::Item(syn::Item::Verbatim(item))) = block.stmts.first() {
if block.stmts.len() == 1 && item.to_string() == ";" {
return;
Expand Down Expand Up @@ -397,7 +392,7 @@ fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
}
};
let box_pin = quote_spanned!(block.brace_token.span=>
Box::pin(async move { #let_ret })
::stackfuture::StackFuture::from(async move { #let_ret })
);
block.stmts = parse_quote!(#box_pin);
}
Expand Down Expand Up @@ -426,7 +421,7 @@ fn has_bound(supertraits: &Supertraits, marker: &Ident) -> bool {
false
}

fn contains_associated_type_impl_trait(context: Context, ret: &mut Type) -> bool {
fn contains_associated_type_impl_trait(context: Context<'_>, ret: &mut Type) -> bool {
struct AssociatedTypeImplTraits<'a> {
set: &'a Set<Ident>,
contains: bool,
Expand Down
43 changes: 21 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,20 @@
//! This example implements the core of a highly effective advertising platform
//! using async fn in a trait.
//!
//! The only thing to notice here is that we write an `#[async_trait]` macro on
//! The only thing to notice here is that we write an `#[async_trait(512)]` macro on
//! top of traits and trait impls that contain async fn, and then they work.
//!
//! ```
//! use async_trait::async_trait;
//! use stackfuture_async_trait::async_trait;
//!
//! #[async_trait]
//! #[async_trait(512)]
//! trait Advertisement {
//! async fn run(&self);
//! }
//!
//! struct Modal;
//!
//! #[async_trait]
//! #[async_trait(512)]
//! impl Advertisement for Modal {
//! async fn run(&self) {
//! self.render_fullscreen().await;
Expand All @@ -69,7 +69,7 @@
//! media_url: String,
//! }
//!
//! #[async_trait]
//! #[async_trait(512)]
//! impl Advertisement for AutoplayingVideo {
//! async fn run(&self) {
//! let stream = connect(&self.media_url).await;
Expand Down Expand Up @@ -163,11 +163,11 @@
//! error message.
//!
//! ```compile_fail
//! # use async_trait::async_trait;
//! # use stackfuture_async_trait::async_trait;
//! #
//! type Elided<'a> = &'a usize;
//!
//! #[async_trait]
//! #[async_trait(512)]
//! trait Test {
//! async fn test(not_okay: Elided, okay: &usize) {}
//! }
Expand All @@ -184,16 +184,16 @@
//! The fix is to name the lifetime or use `'_`.
//!
//! ```
//! # use async_trait::async_trait;
//! # use stackfuture_async_trait::async_trait;
//! #
//! # type Elided<'a> = &'a usize;
//! #
//! #[async_trait]
//! #[async_trait(512)]
//! trait Test {
//! // either
//! async fn test<'e>(elided: Elided<'e>) {}
//! # }
//! # #[async_trait]
//! # #[async_trait(512)]
//! # trait Test2 {
//! // or
//! async fn test(elided: Elided<'_>) {}
Expand All @@ -209,9 +209,9 @@
//! by value, no associated types, etc.
//!
//! ```
//! # use async_trait::async_trait;
//! # use stackfuture_async_trait::async_trait;
//! #
//! #[async_trait]
//! #[async_trait(512)]
//! pub trait ObjectSafe {
//! async fn f(&self);
//! async fn g(&mut self);
Expand All @@ -225,7 +225,7 @@
//! #
//! # struct MyType;
//! #
//! # #[async_trait]
//! # #[async_trait(512)]
//! # impl ObjectSafe for MyType {
//! # async fn f(&self) {}
//! # async fn g(&mut self) {}
Expand Down Expand Up @@ -263,16 +263,16 @@
//! the default implementations are applicable to them:
//!
//! ```
//! # use async_trait::async_trait;
//! # use stackfuture_async_trait::async_trait;
//! #
//! #[async_trait]
//! #[async_trait(512)]
//! pub trait ObjectSafe: Sync { // added supertrait
//! async fn can_dyn(&self) {}
//! }
//! #
//! # struct MyType;
//! #
//! # #[async_trait]
//! # #[async_trait(512)]
//! # impl ObjectSafe for MyType {}
//! #
//! # let value = MyType;
Expand All @@ -284,9 +284,9 @@
//! bounding them with `Self: Sized`:
//!
//! ```
//! # use async_trait::async_trait;
//! # use stackfuture_async_trait::async_trait;
//! #
//! #[async_trait]
//! #[async_trait(512)]
//! pub trait ObjectSafe {
//! async fn cannot_dyn(&self) where Self: Sized {}
//!
Expand All @@ -295,7 +295,7 @@
//! #
//! # struct MyType;
//! #
//! # #[async_trait]
//! # #[async_trait(512)]
//! # impl ObjectSafe for MyType {}
//! #
//! # let value = MyType;
Expand All @@ -314,8 +314,7 @@
clippy::similar_names,
clippy::too_many_lines
)]

extern crate proc_macro;
#![deny(rust_2018_idioms)]

mod args;
mod expand;
Expand All @@ -334,6 +333,6 @@ use syn::parse_macro_input;
pub fn async_trait(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as Args);
let mut item = parse_macro_input!(input as Item);
expand(&mut item, args.local);
expand(&mut item, args.local, &args.stack_size);
TokenStream::from(quote!(#item))
}
2 changes: 1 addition & 1 deletion src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub enum Item {
}

impl Parse for Item {
fn parse(input: ParseStream) -> Result<Self> {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let mut lookahead = input.lookahead1();
if lookahead.peek(Token![unsafe]) {
Expand Down
Loading