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