//! [![github]](https://github.com/dtolnay/async-trait) [![crates-io]](https://crates.io/crates/async-trait) [![docs-rs]](https://docs.rs/async-trait) //! //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K //! //!
//! //!
Type erasure for async trait methods
//! //! The initial round of stabilizations for the async/await language feature in //! Rust 1.39 did not include support for async fn in traits. Trying to include //! an async fn in a trait produces the following error: //! //! ```compile_fail //! trait MyTrait { //! async fn f() {} //! } //! ``` //! //! ```text //! error[E0706]: trait fns cannot be declared `async` //! --> src/main.rs:4:5 //! | //! 4 | async fn f() {} //! | ^^^^^^^^^^^^^^^ //! ``` //! //! This crate provides an attribute macro to make async fn in traits work. //! //! Please refer to [*why async fn in traits are hard*][hard] for a deeper //! analysis of how this implementation differs from what the compiler and //! language hope to deliver in the future. //! //! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/ //! //!
//! //! # Example //! //! This example implements the core of a highly effective advertising platform //! using async fn in a trait. //! //! The only thing to notice here is that we write an `#[async_trait]` macro on //! top of traits and trait impls that contain async fn, and then they work. //! //! ``` //! use async_trait::async_trait; //! //! #[async_trait] //! trait Advertisement { //! async fn run(&self); //! } //! //! struct Modal; //! //! #[async_trait] //! impl Advertisement for Modal { //! async fn run(&self) { //! self.render_fullscreen().await; //! for _ in 0..4u16 { //! remind_user_to_join_mailing_list().await; //! } //! self.hide_for_now().await; //! } //! } //! //! struct AutoplayingVideo { //! media_url: String, //! } //! //! #[async_trait] //! impl Advertisement for AutoplayingVideo { //! async fn run(&self) { //! let stream = connect(&self.media_url).await; //! stream.play().await; //! //! // Video probably persuaded user to join our mailing list! //! Modal.run().await; //! } //! } //! # //! # impl Modal { //! # async fn render_fullscreen(&self) {} //! # async fn hide_for_now(&self) {} //! # } //! # //! # async fn remind_user_to_join_mailing_list() {} //! # //! # struct Stream; //! # async fn connect(_media_url: &str) -> Stream { Stream } //! # impl Stream { //! # async fn play(&self) {} //! # } //! ``` //! //!

//! //! # Supported features //! //! 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 //! you see unexpected borrow checker errors, type errors, or warnings. There is //! no use of `unsafe` in the expanded code, so rest assured that if your code //! compiles it can'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;
//! > ☑ Dyn-capable traits.
//! //!
//! //! # Explanation //! //! Async fns get transformed into methods that return `Pin>` and delegate to a private async freestanding function. //! //! For example the `impl Advertisement for AutoplayingVideo` above would be //! expanded as: //! //! ``` //! # const IGNORE: &str = stringify! { //! impl Advertisement for AutoplayingVideo { //! fn run<'async>( //! &'async self, //! ) -> Pin + Send + 'async>> //! where //! Self: Sync + 'async, //! { //! async fn run(_self: &AutoplayingVideo) { //! /* the original method body */ //! } //! //! Box::pin(run(self)) //! } //! } //! # }; //! ``` //! //!

//! //! # Non-threadsafe futures //! //! Not all async traits need futures that are `dyn Future + Send`. To avoid //! having Send and Sync bounds placed on the async trait methods, invoke the //! async trait macro as `#[async_trait(?Send)]` on both the trait and the impl //! blocks. //! //!
//! //! # Elided lifetimes //! //! 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 //! error message. //! //! ```compile_fail //! # use async_trait::async_trait; //! # //! type Elided<'a> = &'a usize; //! //! #[async_trait] //! trait Test { //! async fn test(not_okay: Elided, okay: &usize) {} //! } //! ``` //! //! ```text //! 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 `'_`. //! //! ``` //! # use async_trait::async_trait; //! # //! # type Elided<'a> = &'a usize; //! # //! #[async_trait] //! trait Test { //! // either //! async fn test<'e>(elided: Elided<'e>) {} //! # } //! # #[async_trait] //! # trait Test2 { //! // or //! async fn test(elided: Elided<'_>) {} //! } //! ``` //! //!

//! //! # Dyn traits //! //! Traits with async methods can be used as trait objects as long as they meet //! the usual requirements for dyn -- no methods with type parameters, no self //! by value, no associated types, etc. //! //! ``` //! # use async_trait::async_trait; //! # //! #[async_trait] //! pub trait ObjectSafe { //! async fn f(&self); //! async fn g(&mut self); //! } //! //! # const IGNORE: &str = stringify! { //! impl ObjectSafe for MyType {...} //! //! let value: MyType = ...; //! # }; //! # //! # struct MyType; //! # //! # #[async_trait] //! # impl ObjectSafe for MyType { //! # async fn f(&self) {} //! # async fn g(&mut self) {} //! # } //! # //! # let value: MyType = MyType; //! let object = &value as &dyn ObjectSafe; // make trait object //! ``` //! //! The one wrinkle is in traits that provide default implementations of async //! methods. In order for the default implementation to produce a future that is //! Send, the async_trait macro must emit a bound of `Self: Sync` on trait //! methods that take `&self` and a bound `Self: Send` on trait methods that //! take `&mut self`. An example of the former is visible in the expanded code //! in the explanation section above. //! //! If you make a trait with async methods that have default implementations, //! everything will work except that the trait cannot be used as a trait object. //! Creating a value of type `&dyn Trait` will produce an error that looks like //! this: //! //! ```text //! error: the trait `Test` cannot be made into an object //! --> src/main.rs:8:5 //! | //! 8 | async fn cannot_dyn(&self) {} //! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //! ``` //! //! For traits that need to be object safe and need to have default //! implementations for some async methods, there are two resolutions. Either //! you can add Send and/or Sync as supertraits (Send if there are `&mut self` //! methods with default implementations, Sync if there are `&self` methods with //! default implementions) to constrain all implementors of the trait such that //! the default implementations are applicable to them: //! //! ``` //! # use async_trait::async_trait; //! # //! #[async_trait] //! pub trait ObjectSafe: Sync { // added supertrait //! async fn can_dyn(&self) {} //! } //! # //! # struct MyType; //! # //! # #[async_trait] //! # impl ObjectSafe for MyType {} //! # //! # let value = MyType; //! //! let object = &value as &dyn ObjectSafe; //! ``` //! //! or you can strike the problematic methods from your trait object by //! bounding them with `Self: Sized`: //! //! ``` //! # use async_trait::async_trait; //! # //! #[async_trait] //! pub trait ObjectSafe { //! async fn cannot_dyn(&self) where Self: Sized {} //! //! // presumably other methods //! } //! # //! # struct MyType; //! # //! # #[async_trait] //! # impl ObjectSafe for MyType {} //! # //! # let value = MyType; //! //! let object = &value as &dyn ObjectSafe; //! ``` #![allow( clippy::default_trait_access, clippy::doc_markdown, clippy::if_not_else, clippy::items_after_statements, clippy::module_name_repetitions, clippy::shadow_unrelated, clippy::similar_names, clippy::too_many_lines )] extern crate proc_macro; mod args; mod expand; mod lifetime; mod parse; mod receiver; use crate::args::Args; use crate::expand::expand; use crate::parse::Item; use proc_macro::TokenStream; use quote::quote; use syn::parse_macro_input; #[proc_macro_attribute] pub fn async_trait(args: TokenStream, input: TokenStream) -> TokenStream { let args = parse_macro_input!(args as Args); let mut item = parse_macro_input!(input as Item); expand(&mut item, args.local); TokenStream::from(quote!(#item)) }