Skip to content

Commit 3caf301

Browse files
authored
Merge pull request #254 from dtolnay/doc
Update documentation to discuss object safety in Rust 1.75+
2 parents 034d8db + c1576be commit 3caf301

File tree

3 files changed

+62
-37
lines changed

3 files changed

+62
-37
lines changed

README.md

+30-15
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,43 @@ Async trait methods
66
[<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)
77
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/async-trait/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/async-trait/actions?query=branch%3Amaster)
88

9-
The initial round of stabilizations for the async/await language feature in Rust
10-
1.39 did not include support for async fn in traits. Trying to include an async
11-
fn in a trait produces the following error:
9+
The stabilization of async functions in traits in Rust 1.75 did not include
10+
support for using traits containing async functions as `dyn Trait`. Trying to
11+
use dyn with an async trait produces the following error:
1212

1313
```rust
14-
trait MyTrait {
15-
async fn f() {}
14+
pub trait Trait {
15+
async fn f(&self);
16+
}
17+
18+
pub fn make() -> Box<dyn Trait> {
19+
unimplemented!()
1620
}
1721
```
1822

1923
```console
20-
error[E0706]: trait fns cannot be declared `async`
21-
--> src/main.rs:4:5
24+
error[E0038]: the trait `Trait` cannot be made into an object
25+
--> src/main.rs:5:22
26+
|
27+
5 | pub fn make() -> Box<dyn Trait> {
28+
| ^^^^^^^^^ `Trait` cannot be made into an object
29+
|
30+
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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
31+
--> src/main.rs:2:14
2232
|
23-
4 | async fn f() {}
24-
| ^^^^^^^^^^^^^^^
33+
1 | pub trait Trait {
34+
| ----- this trait cannot be made into an object...
35+
2 | async fn f(&self);
36+
| ^ ...because method `f` is `async`
37+
= help: consider moving `f` to another trait
2538
```
2639

27-
This crate provides an attribute macro to make async fn in traits work.
40+
This crate provides an attribute macro to make async fn in traits work with dyn
41+
traits.
2842

2943
Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis
30-
of how this implementation differs from what the compiler and language hope to
31-
deliver in the future.
44+
of how this implementation differs from what the compiler and language deliver
45+
natively.
3246

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

@@ -40,7 +54,9 @@ This example implements the core of a highly effective advertising platform
4054
using async fn in a trait.
4155

4256
The only thing to notice here is that we write an `#[async_trait]` macro on top
43-
of traits and trait impls that contain async fn, and then they work.
57+
of traits and trait impls that contain async fn, and then they work. We get to
58+
have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`, for
59+
example.
4460

4561
```rust
4662
use async_trait::async_trait;
@@ -95,8 +111,7 @@ can't be that badly broken.
95111
- &#128077;&ensp;Associated types;
96112
- &#128077;&ensp;Having async and non-async functions in the same trait;
97113
- &#128077;&ensp;Default implementations provided by the trait;
98-
- &#128077;&ensp;Elided lifetimes;
99-
- &#128077;&ensp;Dyn-capable traits.
114+
- &#128077;&ensp;Elided lifetimes.
100115

101116
<br>
102117

build.rs

-4
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ fn main() {
1717
if compiler < 47 {
1818
println!("cargo:rustc-cfg=self_span_hack");
1919
}
20-
21-
if compiler >= 75 && env::var_os("DOCS_RS").is_none() {
22-
println!("cargo:rustc-cfg=native_async_fn_in_trait");
23-
}
2420
}
2521

2622
fn rustc_minor_version() -> Option<u32> {

src/lib.rs

+32-18
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,45 @@
66
//!
77
//! <br>
88
//!
9-
//! <h5>Type erasure for async trait methods</h5>
9+
//! <h4>Type erasure for async trait methods</h4>
1010
//!
11-
//! The initial round of stabilizations for the async/await language feature in
12-
//! Rust 1.39 did not include support for async fn in traits. Trying to include
13-
//! an async fn in a trait produces the following error:
11+
//! The stabilization of async functions in traits in Rust 1.75 did not include
12+
//! support for using traits containing async functions as `dyn Trait`. Trying
13+
//! to use dyn with an async trait produces the following error:
1414
//!
15-
#![cfg_attr(not(native_async_fn_in_trait), doc = "```compile_fail")]
16-
#![cfg_attr(native_async_fn_in_trait, doc = "```")]
17-
//! trait MyTrait {
18-
//! async fn f() {}
15+
//! ```compile_fail
16+
//! pub trait Trait {
17+
//! async fn f(&self);
1918
//! }
20-
#![doc = "```"]
19+
//!
20+
//! pub fn make() -> Box<dyn Trait> {
21+
//! unimplemented!()
22+
//! }
23+
//! ```
2124
//!
2225
//! ```text
23-
//! error[E0706]: trait fns cannot be declared `async`
24-
//! --> src/main.rs:4:5
26+
//! error[E0038]: the trait `Trait` cannot be made into an object
27+
//! --> src/main.rs:5:22
28+
//! |
29+
//! 5 | pub fn make() -> Box<dyn Trait> {
30+
//! | ^^^^^^^^^ `Trait` cannot be made into an object
31+
//! |
32+
//! 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
33+
//! --> src/main.rs:2:14
2534
//! |
26-
//! 4 | async fn f() {}
27-
//! | ^^^^^^^^^^^^^^^
35+
//! 1 | pub trait Trait {
36+
//! | ----- this trait cannot be made into an object...
37+
//! 2 | async fn f(&self);
38+
//! | ^ ...because method `f` is `async`
39+
//! = help: consider moving `f` to another trait
2840
//! ```
2941
//!
30-
//! This crate provides an attribute macro to make async fn in traits work.
42+
//! This crate provides an attribute macro to make async fn in traits work with
43+
//! dyn traits.
3144
//!
3245
//! Please refer to [*why async fn in traits are hard*][hard] for a deeper
3346
//! analysis of how this implementation differs from what the compiler and
34-
//! language hope to deliver in the future.
47+
//! language deliver natively.
3548
//!
3649
//! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
3750
//!
@@ -43,7 +56,9 @@
4356
//! using async fn in a trait.
4457
//!
4558
//! The only thing to notice here is that we write an `#[async_trait]` macro on
46-
//! top of traits and trait impls that contain async fn, and then they work.
59+
//! top of traits and trait impls that contain async fn, and then they work. We
60+
//! get to have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`,
61+
//! for example.
4762
//!
4863
//! ```
4964
//! use async_trait::async_trait;
@@ -111,8 +126,7 @@
111126
//! > &#9745;&emsp;Associated types;<br>
112127
//! > &#9745;&emsp;Having async and non-async functions in the same trait;<br>
113128
//! > &#9745;&emsp;Default implementations provided by the trait;<br>
114-
//! > &#9745;&emsp;Elided lifetimes;<br>
115-
//! > &#9745;&emsp;Dyn-capable traits.<br>
129+
//! > &#9745;&emsp;Elided lifetimes.<br>
116130
//!
117131
//! <br>
118132
//!

0 commit comments

Comments
 (0)