Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork93
Type erasure for async trait methods
License
Apache-2.0, MIT licenses found
Licenses found
dtolnay/async-trait
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
The stabilization of async functions in traits in Rust 1.75 did not includesupport for using traits containing async functions asdyn Trait. Trying touse dyn with an async trait produces the following error:
pubtraitTrait{asyncfnf(&self);}pubfnmake() ->Box<dynTrait>{unimplemented!()}
error[E0038]: the trait `Trait` is not dyn compatible --> src/main.rs:5:22 |5 | pub fn make() -> Box<dyn Trait> { | ^^^^^^^^^ `Trait` is not dyn compatible |note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> src/main.rs:2:14 |1 | pub trait Trait { | ----- this trait is not dyn compatible...2 | async fn f(&self); | ^ ...because method `f` is `async` = help: consider moving `f` to another trait
This crate provides an attribute macro to make async fn in traits work with dyntraits.
Please refer towhy async fn in traits are hard for a deeper analysisof how this implementation differs from what the compiler and language delivernatively.
This example implements the core of a highly effective advertising platformusing async fn in a trait.
The only thing to notice here is that we write an#[async_trait] macro on topof traits and trait impls that contain async fn, and then they work. We get tohaveVec<Box<dyn Advertisement + Sync>> or&[&dyn Advertisement], forexample.
use async_trait::async_trait;#[async_trait]traitAdvertisement{asyncfnrun(&self);}structModal;#[async_trait]implAdvertisementforModal{asyncfnrun(&self){self.render_fullscreen().await;for _in0..4u16{remind_user_to_join_mailing_list().await;}self.hide_for_now().await;}}structAutoplayingVideo{media_url:String,}#[async_trait]implAdvertisementforAutoplayingVideo{asyncfnrun(&self){let stream =connect(&self.media_url).await; stream.play().await;// Video probably persuaded user to join our mailing list!Modal.run().await;}}
It is the intention that all features of Rust traits should work nicely with#[async_trait], but the edge cases are numerous.Please file an issue if yousee unexpected borrow checker errors, type errors, or warnings. There is no useofunsafe in the expanded code, so rest assured that if your code compiles itcan't be that badly broken.
- 👍 Self by value, by reference, by mut reference, or no self;
- 👍 Any number of arguments, any return value;
- 👍 Generic type parameters and lifetime parameters;
- 👍 Associated types;
- 👍 Having async and non-async functions in the same trait;
- 👍 Default implementations provided by the trait;
- 👍 Elided lifetimes.
Async fns get transformed into methods that returnPin<Box<dyn Future + Send + 'async_trait>> and delegate to an async block.
For example theimpl Advertisement for AutoplayingVideo above would beexpanded as:
implAdvertisementforAutoplayingVideo{fnrun<'async_trait>(&'async_traitself,) ->Pin<Box<dyn std::future::Future<Output =()> +Send +'async_trait>>whereSelf:Sync +'async_trait,{Box::pin(asyncmove{/* the original method body */})}}
Not all async traits need futures that aredyn Future + Send. To avoid havingSend and Sync bounds placed on the async trait methods, invoke the async traitmacro as#[async_trait(?Send)] on both the trait and the impl blocks.
Be aware that async fn syntax does not allow lifetime elision outside of& and&mut references. (This is true even when not using #[async_trait].)Lifetimes must be named or marked by the placeholder'_.
Fortunately the compiler is able to diagnose missing lifetimes with a good errormessage.
typeElided<'a> =&'ausize;#[async_trait]traitTest{asyncfntest(not_okay:Elided,okay:&usize){}}
error[E0726]: implicit elided lifetime not allowed here --> src/main.rs:9:29 |9 | async fn test(not_okay: Elided, okay: &usize) {} | ^^^^^^- help: indicate the anonymous lifetime: `<'_>`
The fix is to name the lifetime or use'_.
#[async_trait]traitTest{// eitherasyncfntest<'e>(elided:Elided<'e>){}// orasyncfntest(elided:Elided<'_>){}}
Licensed under either ofApache License, Version2.0 orMIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submittedfor inclusion in this crate by you, as defined in the Apache-2.0 license, shallbe dual licensed as above, without any additional terms or conditions.
About
Type erasure for async trait methods
Resources
License
Apache-2.0, MIT licenses found
Licenses found
Code of conduct
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.