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 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 implementations) 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