Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | - | - | ||||
src/ | 25-Apr-2025 | - | 1,277 | 813 | ||
tests/ | 25-Apr-2025 | - | 2,340 | 1,812 | ||
.cargo-checksum.json | D | 25-Apr-2025 | 4.3 KiB | 1 | 1 | |
Android.bp | D | 25-Apr-2025 | 941 | 37 | 32 | |
Cargo.toml | D | 25-Apr-2025 | 1.8 KiB | 84 | 70 | |
LICENSE | D | 25-Apr-2025 | 9.5 KiB | 177 | 150 | |
LICENSE-APACHE | D | 25-Apr-2025 | 9.5 KiB | 177 | 150 | |
LICENSE-MIT | D | 25-Apr-2025 | 1,023 | 24 | 21 | |
METADATA | D | 25-Apr-2025 | 392 | 18 | 17 | |
MODULE_LICENSE_APACHE2 | D | 25-Apr-2025 | 0 | |||
README.md | D | 25-Apr-2025 | 8.1 KiB | 276 | 214 | |
TEST_MAPPING | D | 25-Apr-2025 | 731 | 36 | 35 | |
cargo_embargo.json | D | 25-Apr-2025 | 53 | 5 | 4 | |
rules.mk | D | 25-Apr-2025 | 545 | 18 | 11 |
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- 👍 Self by value, by reference, by mut reference, or no self; 109- 👍 Any number of arguments, any return value; 110- 👍 Generic type parameters and lifetime parameters; 111- 👍 Associated types; 112- 👍 Having async and non-async functions in the same trait; 113- 👍 Default implementations provided by the trait; 114- 👍 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