From 5f041087a98b657982793f704e779e0354c0c14a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 22:53:05 -0400 Subject: [PATCH 1/8] Update ui test suite to nightly-2023-10-31 --- tests/ui/no-attribute-macro.stderr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ui/no-attribute-macro.stderr b/tests/ui/no-attribute-macro.stderr index 35d8d5a..cb15522 100644 --- a/tests/ui/no-attribute-macro.stderr +++ b/tests/ui/no-attribute-macro.stderr @@ -12,3 +12,5 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all 2 | async fn method(&self); | ^^^^^^ ...because method `method` is `async` = help: consider moving `method` to another trait + = help: only type `Struct` is seen to implement the trait in this crate, consider using it directly instead + = note: `Trait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type From b4a3886153fa49c833e22e9a8259a8bf5b897cd2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 19 Nov 2023 18:22:11 -0800 Subject: [PATCH 2/8] Update ui test suite to nightly-2023-11-20 --- tests/ui/must-use.stderr | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/ui/must-use.stderr b/tests/ui/must-use.stderr index 9b71d10..79e0a7a 100644 --- a/tests/ui/must-use.stderr +++ b/tests/ui/must-use.stderr @@ -1,14 +1,22 @@ -error: unused return value of `Interface::f` that must be used +error: unused pinned boxed `Future` trait object that must be used --> tests/ui/must-use.rs:18:5 | 18 | Thing.f(); | ^^^^^^^^^ | + = note: futures do nothing unless you `.await` or poll them note: the lint level is defined here --> tests/ui/must-use.rs:1:9 | 1 | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ + +error: unused return value of `Interface::f` that must be used + --> tests/ui/must-use.rs:18:5 + | +18 | Thing.f(); + | ^^^^^^^^^ + | help: use `let _ = ...` to ignore the resulting value | 18 | let _ = Thing.f(); From 0d469fcea4cd16c49e8d0bc797ea4b51a11054f0 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 20 Dec 2023 15:54:14 -0800 Subject: [PATCH 3/8] Add a funding file --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7507077 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: dtolnay From 034d8db0b851a3e401b3a374ee57fe4492283a74 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 20 Dec 2023 15:54:47 -0800 Subject: [PATCH 4/8] Release 0.1.75 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e0e3762..d181809 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-trait" -version = "0.1.74" +version = "0.1.75" authors = ["David Tolnay "] categories = ["asynchronous", "no-std"] description = "Type erasure for async trait methods" diff --git a/src/lib.rs b/src/lib.rs index 435d508..37d0869 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -304,7 +304,7 @@ //! let object = &value as &dyn ObjectSafe; //! ``` -#![doc(html_root_url = "https://docs.rs/async-trait/0.1.74")] +#![doc(html_root_url = "https://docs.rs/async-trait/0.1.75")] #![allow( clippy::default_trait_access, clippy::doc_markdown, From c1576be43953b849e65963ea67930be789dfb372 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Dec 2023 15:10:50 -0800 Subject: [PATCH 5/8] Update documentation to discuss object safety in Rust 1.75+ --- README.md | 45 ++++++++++++++++++++++++++++++--------------- build.rs | 4 ---- src/lib.rs | 50 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 39e368b..301ce3f 100644 --- a/README.md +++ b/README.md @@ -6,29 +6,43 @@ Async trait methods [docs.rs](https://docs.rs/async-trait) [build status](https://github.com/dtolnay/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 -fn in a trait produces the following error: +The stabilization of async functions in traits in Rust 1.75 did not include +support for using traits containing async functions as `dyn Trait`. Trying to +use dyn with an async trait produces the following error: ```rust -trait MyTrait { - async fn f() {} +pub trait Trait { + async fn f(&self); +} + +pub fn make() -> Box { + unimplemented!() } ``` ```console -error[E0706]: trait fns cannot be declared `async` - --> src/main.rs:4:5 +error[E0038]: the trait `Trait` cannot be made into an object + --> src/main.rs:5:22 + | +5 | pub fn make() -> Box { + | ^^^^^^^^^ `Trait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> src/main.rs:2:14 | -4 | async fn f() {} - | ^^^^^^^^^^^^^^^ +1 | pub trait Trait { + | ----- this trait cannot be made into an object... +2 | async fn f(&self); + | ^ ...because method `f` is `async` + = help: consider moving `f` to another trait ``` -This crate provides an attribute macro to make async fn in traits work. +This crate provides an attribute macro to make async fn in traits work with dyn +traits. Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis -of how this implementation differs from what the compiler and language hope to -deliver in the future. +of how this implementation differs from what the compiler and language deliver +natively. [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/ @@ -40,7 +54,9 @@ 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 top -of traits and trait impls that contain async fn, and then they work. +of traits and trait impls that contain async fn, and then they work. We get to +have `Vec>` or `&[&dyn Advertisement]`, for +example. ```rust use async_trait::async_trait; @@ -95,8 +111,7 @@ can't be that badly broken. - 👍 Associated types; - 👍 Having async and non-async functions in the same trait; - 👍 Default implementations provided by the trait; -- 👍 Elided lifetimes; -- 👍 Dyn-capable traits. +- 👍 Elided lifetimes.
diff --git a/build.rs b/build.rs index f25fb0a..db7c5f0 100644 --- a/build.rs +++ b/build.rs @@ -17,10 +17,6 @@ fn main() { if compiler < 47 { println!("cargo:rustc-cfg=self_span_hack"); } - - if compiler >= 75 && env::var_os("DOCS_RS").is_none() { - println!("cargo:rustc-cfg=native_async_fn_in_trait"); - } } fn rustc_minor_version() -> Option { diff --git a/src/lib.rs b/src/lib.rs index 37d0869..e2365c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,32 +6,45 @@ //! //!
//! -//!
Type erasure for async trait methods
+//!

Type erasure for async trait methods

//! -//! 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 fn in a trait produces the following error: +//! The stabilization of async functions in traits in Rust 1.75 did not include +//! support for using traits containing async functions as `dyn Trait`. Trying +//! to use dyn with an async trait produces the following error: //! -#![cfg_attr(not(native_async_fn_in_trait), doc = "```compile_fail")] -#![cfg_attr(native_async_fn_in_trait, doc = "```")] -//! trait MyTrait { -//! async fn f() {} +//! ```compile_fail +//! pub trait Trait { +//! async fn f(&self); //! } -#![doc = "```"] +//! +//! pub fn make() -> Box { +//! unimplemented!() +//! } +//! ``` //! //! ```text -//! error[E0706]: trait fns cannot be declared `async` -//! --> src/main.rs:4:5 +//! error[E0038]: the trait `Trait` cannot be made into an object +//! --> src/main.rs:5:22 +//! | +//! 5 | pub fn make() -> Box { +//! | ^^^^^^^^^ `Trait` cannot be made into an object +//! | +//! note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit +//! --> src/main.rs:2:14 //! | -//! 4 | async fn f() {} -//! | ^^^^^^^^^^^^^^^ +//! 1 | pub trait Trait { +//! | ----- this trait cannot be made into an object... +//! 2 | async fn f(&self); +//! | ^ ...because method `f` is `async` +//! = help: consider moving `f` to another trait //! ``` //! -//! This crate provides an attribute macro to make async fn in traits work. +//! This crate provides an attribute macro to make async fn in traits work with +//! dyn traits. //! //! Please refer to [*why async fn in traits are hard*][hard] for a deeper //! analysis of how this implementation differs from what the compiler and -//! language hope to deliver in the future. +//! language deliver natively. //! //! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/ //! @@ -43,7 +56,9 @@ //! using async fn in a trait. //! //! The only thing to notice here is that we write an `#[async_trait]` macro on -//! top of traits and trait impls that contain async fn, and then they work. +//! top of traits and trait impls that contain async fn, and then they work. We +//! get to have `Vec>` or `&[&dyn Advertisement]`, +//! for example. //! //! ``` //! use async_trait::async_trait; @@ -111,8 +126,7 @@ //! > ☑ Associated types;
//! > ☑ Having async and non-async functions in the same trait;
//! > ☑ Default implementations provided by the trait;
-//! > ☑ Elided lifetimes;
-//! > ☑ Dyn-capable traits.
+//! > ☑ Elided lifetimes.
//! //!
//! From 381fd7564e6d29d6647da1099e12de36136a4a03 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Dec 2023 15:34:18 -0800 Subject: [PATCH 6/8] Update explanation to show async block expansion --- README.md | 8 +++----- src/lib.rs | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 301ce3f..97dbac9 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ can't be that badly broken. ## Explanation Async fns get transformed into methods that return `Pin>` and delegate to a private async freestanding function. +'async_trait>>` and delegate to an async block. For example the `impl Advertisement for AutoplayingVideo` above would be expanded as: @@ -131,11 +131,9 @@ impl Advertisement for AutoplayingVideo { where Self: Sync + 'async_trait, { - async fn run(_self: &AutoplayingVideo) { + Box::pin(async move { /* the original method body */ - } - - Box::pin(run(self)) + }) } } ``` diff --git a/src/lib.rs b/src/lib.rs index e2365c3..d7223ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,7 +133,7 @@ //! # Explanation //! //! Async fns get transformed into methods that return `Pin>` and delegate to a private async freestanding function. +//! Send + 'async_trait>>` and delegate to an async block. //! //! For example the `impl Advertisement for AutoplayingVideo` above would be //! expanded as: @@ -147,11 +147,9 @@ //! where //! Self: Sync + 'async_trait, //! { -//! async fn run(_self: &AutoplayingVideo) { +//! Box::pin(async move { //! /* the original method body */ -//! } -//! -//! Box::pin(run(self)) +//! }) //! } //! } //! # }; From 48e29e43c0a3d64166f805fb15978e8ffd487e43 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Dec 2023 15:40:07 -0800 Subject: [PATCH 7/8] Re-enable tracing integration test under Miri --- Cargo.toml | 6 +++--- tests/test.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d181809..9d839f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,10 @@ quote = "1.0.29" syn = { version = "2.0.23", features = ["full", "visit-mut"] } [dev-dependencies] -futures = "0.3.28" +futures = "0.3.30" rustversion = "1.0.13" -tracing = "0.1.37" -tracing-attributes = "0.1.26" +tracing = "0.1.40" +tracing-attributes = "0.1.27" trybuild = { version = "1.0.81", features = ["diff"] } [package.metadata.docs.rs] diff --git a/tests/test.rs b/tests/test.rs index 650959c..b78c9ff 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -620,7 +620,6 @@ pub mod issue45 { } #[test] - #[cfg_attr(miri, ignore)] // https://github.com/matklad/once_cell/pull/185 fn tracing() { // Create the future outside of the subscriber, as no call to tracing // should be made until the future is polled. From 627124bf67cc173c7564454e71dfccc30f6bc5f5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Dec 2023 15:42:46 -0800 Subject: [PATCH 8/8] Release 0.1.76 --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9d839f1..d614fba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-trait" -version = "0.1.75" +version = "0.1.76" authors = ["David Tolnay "] categories = ["asynchronous", "no-std"] description = "Type erasure for async trait methods" diff --git a/src/lib.rs b/src/lib.rs index d7223ca..708b870 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -316,7 +316,7 @@ //! let object = &value as &dyn ObjectSafe; //! ``` -#![doc(html_root_url = "https://docs.rs/async-trait/0.1.75")] +#![doc(html_root_url = "https://docs.rs/async-trait/0.1.76")] #![allow( clippy::default_trait_access, clippy::doc_markdown,