• Home
  • History
  • Annotate
Name
Date
Size
#Lines
LOC

..--

src/25-Apr-2025-1,277813

tests/25-Apr-2025-2,3401,812

.cargo-checksum.jsonD25-Apr-20254.3 KiB11

Android.bpD25-Apr-2025941 3732

Cargo.tomlD25-Apr-20251.8 KiB8470

LICENSED25-Apr-20259.5 KiB177150

LICENSE-APACHED25-Apr-20259.5 KiB177150

LICENSE-MITD25-Apr-20251,023 2421

METADATAD25-Apr-2025392 1817

MODULE_LICENSE_APACHE2D25-Apr-20250

README.mdD25-Apr-20258.1 KiB276214

TEST_MAPPINGD25-Apr-2025731 3635

cargo_embargo.jsonD25-Apr-202553 54

rules.mkD25-Apr-2025545 1811

README.md

1Async trait methods
2===================
3
4[<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)
5[<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)
6[<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)
7[<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)
8
9The stabilization of async functions in traits in Rust 1.75 did not include
10support for using traits containing async functions as `dyn Trait`. Trying to
11use dyn with an async trait produces the following error:
12
13```rust
14pub trait Trait {
15    async fn f(&self);
16}
17
18pub fn make() -> Box<dyn Trait> {
19    unimplemented!()
20}
21```
22
23```console
24error[E0038]: the trait `Trait` cannot be made into an object
25 --> src/main.rs:5:22
26  |
275 | pub fn make() -> Box<dyn Trait> {
28  |                      ^^^^^^^^^ `Trait` cannot be made into an object
29  |
30note: 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
32  |
331 | pub trait Trait {
34  |           ----- this trait cannot be made into an object...
352 |     async fn f(&self);
36  |              ^ ...because method `f` is `async`
37  = help: consider moving `f` to another trait
38```
39
40This crate provides an attribute macro to make async fn in traits work with dyn
41traits.
42
43Please refer to [*why async fn in traits are hard*][hard] for a deeper analysis
44of how this implementation differs from what the compiler and language deliver
45natively.
46
47[hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
48
49<br>
50
51## Example
52
53This example implements the core of a highly effective advertising platform
54using async fn in a trait.
55
56The only thing to notice here is that we write an `#[async_trait]` macro on top
57of traits and trait impls that contain async fn, and then they work. We get to
58have `Vec<Box<dyn Advertisement + Sync>>` or `&[&dyn Advertisement]`, for
59example.
60
61```rust
62use async_trait::async_trait;
63
64#[async_trait]
65trait Advertisement {
66    async fn run(&self);
67}
68
69struct Modal;
70
71#[async_trait]
72impl Advertisement for Modal {
73    async fn run(&self) {
74        self.render_fullscreen().await;
75        for _ in 0..4u16 {
76            remind_user_to_join_mailing_list().await;
77        }
78        self.hide_for_now().await;
79    }
80}
81
82struct AutoplayingVideo {
83    media_url: String,
84}
85
86#[async_trait]
87impl Advertisement for AutoplayingVideo {
88    async fn run(&self) {
89        let stream = connect(&self.media_url).await;
90        stream.play().await;
91
92        // Video probably persuaded user to join our mailing list!
93        Modal.run().await;
94    }
95}
96```
97
98<br>
99
100## Supported features
101
102It is the intention that all features of Rust traits should work nicely with
103\#\[async_trait\], but the edge cases are numerous. *Please file an issue if you
104see unexpected borrow checker errors, type errors, or warnings.* There is no use
105of `unsafe` in the expanded code, so rest assured that if your code compiles it
106can't be that badly broken.
107
108- &#128077;&ensp;Self by value, by reference, by mut reference, or no self;
109- &#128077;&ensp;Any number of arguments, any return value;
110- &#128077;&ensp;Generic type parameters and lifetime parameters;
111- &#128077;&ensp;Associated types;
112- &#128077;&ensp;Having async and non-async functions in the same trait;
113- &#128077;&ensp;Default implementations provided by the trait;
114- &#128077;&ensp;Elided lifetimes.
115
116<br>
117
118## Explanation
119
120Async fns get transformed into methods that return `Pin<Box<dyn Future + Send +
121'async_trait>>` and delegate to an async block.
122
123For example the `impl Advertisement for AutoplayingVideo` above would be
124expanded as:
125
126```rust
127impl Advertisement for AutoplayingVideo {
128    fn run<'async_trait>(
129        &'async_trait self,
130    ) -> Pin<Box<dyn std::future::Future<Output = ()> + Send + 'async_trait>>
131    where
132        Self: Sync + 'async_trait,
133    {
134        Box::pin(async move {
135            /* the original method body */
136        })
137    }
138}
139```
140
141<br>
142
143## Non-threadsafe futures
144
145Not all async traits need futures that are `dyn Future + Send`. To avoid having
146Send and Sync bounds placed on the async trait methods, invoke the async trait
147macro as `#[async_trait(?Send)]` on both the trait and the impl blocks.
148
149<br>
150
151## Elided lifetimes
152
153Be aware that async fn syntax does not allow lifetime elision outside of `&` and
154`&mut` references. (This is true even when not using #\[async_trait\].)
155Lifetimes must be named or marked by the placeholder `'_`.
156
157Fortunately the compiler is able to diagnose missing lifetimes with a good error
158message.
159
160```rust
161type Elided<'a> = &'a usize;
162
163#[async_trait]
164trait Test {
165    async fn test(not_okay: Elided, okay: &usize) {}
166}
167```
168
169```console
170error[E0726]: implicit elided lifetime not allowed here
171 --> src/main.rs:9:29
172  |
1739 |     async fn test(not_okay: Elided, okay: &usize) {}
174  |                             ^^^^^^- help: indicate the anonymous lifetime: `<'_>`
175```
176
177The fix is to name the lifetime or use `'_`.
178
179```rust
180#[async_trait]
181trait Test {
182    // either
183    async fn test<'e>(elided: Elided<'e>) {}
184    // or
185    async fn test(elided: Elided<'_>) {}
186}
187```
188
189<br>
190
191## Dyn traits
192
193Traits with async methods can be used as trait objects as long as they meet the
194usual requirements for dyn -- no methods with type parameters, no self by value,
195no associated types, etc.
196
197```rust
198#[async_trait]
199pub trait ObjectSafe {
200    async fn f(&self);
201    async fn g(&mut self);
202}
203
204impl ObjectSafe for MyType {...}
205
206let value: MyType = ...;
207let object = &value as &dyn ObjectSafe;  // make trait object
208```
209
210The one wrinkle is in traits that provide default implementations of async
211methods. In order for the default implementation to produce a future that is
212Send, the async\_trait macro must emit a bound of `Self: Sync` on trait methods
213that take `&self` and a bound `Self: Send` on trait methods that take `&mut
214self`. An example of the former is visible in the expanded code in the
215explanation section above.
216
217If you make a trait with async methods that have default implementations,
218everything will work except that the trait cannot be used as a trait object.
219Creating a value of type `&dyn Trait` will produce an error that looks like
220this:
221
222```console
223error: the trait `Test` cannot be made into an object
224 --> src/main.rs:8:5
225  |
2268 |     async fn cannot_dyn(&self) {}
227  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
228```
229
230For traits that need to be object safe and need to have default implementations
231for some async methods, there are two resolutions. Either you can add Send
232and/or Sync as supertraits (Send if there are `&mut self` methods with default
233implementations, Sync if there are `&self` methods with default implementations)
234to constrain all implementors of the trait such that the default implementations
235are applicable to them:
236
237```rust
238#[async_trait]
239pub trait ObjectSafe: Sync {  // added supertrait
240    async fn can_dyn(&self) {}
241}
242
243let object = &value as &dyn ObjectSafe;
244```
245
246or you can strike the problematic methods from your trait object by bounding
247them with `Self: Sized`:
248
249```rust
250#[async_trait]
251pub trait ObjectSafe {
252    async fn cannot_dyn(&self) where Self: Sized {}
253
254    // presumably other methods
255}
256
257let object = &value as &dyn ObjectSafe;
258```
259
260<br>
261
262#### License
263
264<sup>
265Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2662.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
267</sup>
268
269<br>
270
271<sub>
272Unless you explicitly state otherwise, any contribution intentionally submitted
273for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
274be dual licensed as above, without any additional terms or conditions.
275</sub>
276