blob: 435d508b1abd7ef87731d77015269ed4d587c711 [file] [log] [blame]
Andrew Walbrand1b91c72020-08-11 17:12:08 +01001//! [![github]](https://github.com/dtolnay/async-trait) [![crates-io]](https://crates.io/crates/async-trait) [![docs-rs]](https://docs.rs/async-trait)
2//!
3//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
Jeff Vander Stoep0caaeed2022-12-06 08:25:24 +01005//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
Andrew Walbrand1b91c72020-08-11 17:12:08 +01006//!
7//! <br>
8//!
9//! <h5>Type erasure for async trait methods</h5>
10//!
11//! The initial round of stabilizations for the async/await language feature in
12//! Rust 1.39 did not include support for async fn in traits. Trying to include
13//! an async fn in a trait produces the following error:
14//!
Jeff Vander Stoepa414c4b2023-11-24 15:39:09 +010015#![cfg_attr(not(native_async_fn_in_trait), doc = "```compile_fail")]
16#![cfg_attr(native_async_fn_in_trait, doc = "```")]
Andrew Walbrand1b91c72020-08-11 17:12:08 +010017//! trait MyTrait {
18//! async fn f() {}
19//! }
Jeff Vander Stoepa414c4b2023-11-24 15:39:09 +010020#![doc = "```"]
Andrew Walbrand1b91c72020-08-11 17:12:08 +010021//!
22//! ```text
23//! error[E0706]: trait fns cannot be declared `async`
24//! --> src/main.rs:4:5
25//! |
26//! 4 | async fn f() {}
27//! | ^^^^^^^^^^^^^^^
28//! ```
29//!
30//! This crate provides an attribute macro to make async fn in traits work.
31//!
32//! Please refer to [*why async fn in traits are hard*][hard] for a deeper
33//! analysis of how this implementation differs from what the compiler and
34//! language hope to deliver in the future.
35//!
36//! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
37//!
38//! <br>
39//!
40//! # Example
41//!
42//! This example implements the core of a highly effective advertising platform
43//! using async fn in a trait.
44//!
45//! The only thing to notice here is that we write an `#[async_trait]` macro on
46//! top of traits and trait impls that contain async fn, and then they work.
47//!
48//! ```
49//! use async_trait::async_trait;
50//!
51//! #[async_trait]
52//! trait Advertisement {
53//! async fn run(&self);
54//! }
55//!
56//! struct Modal;
57//!
58//! #[async_trait]
59//! impl Advertisement for Modal {
60//! async fn run(&self) {
61//! self.render_fullscreen().await;
62//! for _ in 0..4u16 {
63//! remind_user_to_join_mailing_list().await;
64//! }
65//! self.hide_for_now().await;
66//! }
67//! }
68//!
69//! struct AutoplayingVideo {
70//! media_url: String,
71//! }
72//!
73//! #[async_trait]
74//! impl Advertisement for AutoplayingVideo {
75//! async fn run(&self) {
76//! let stream = connect(&self.media_url).await;
77//! stream.play().await;
78//!
79//! // Video probably persuaded user to join our mailing list!
80//! Modal.run().await;
81//! }
82//! }
83//! #
84//! # impl Modal {
85//! # async fn render_fullscreen(&self) {}
86//! # async fn hide_for_now(&self) {}
87//! # }
88//! #
89//! # async fn remind_user_to_join_mailing_list() {}
90//! #
91//! # struct Stream;
92//! # async fn connect(_media_url: &str) -> Stream { Stream }
93//! # impl Stream {
94//! # async fn play(&self) {}
95//! # }
96//! ```
97//!
98//! <br><br>
99//!
100//! # Supported features
101//!
102//! It 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
104//! you see unexpected borrow checker errors, type errors, or warnings. There is
105//! no use of `unsafe` in the expanded code, so rest assured that if your code
106//! compiles it can't be that badly broken.
107//!
108//! > &#9745;&emsp;Self by value, by reference, by mut reference, or no self;<br>
109//! > &#9745;&emsp;Any number of arguments, any return value;<br>
110//! > &#9745;&emsp;Generic type parameters and lifetime parameters;<br>
111//! > &#9745;&emsp;Associated types;<br>
112//! > &#9745;&emsp;Having async and non-async functions in the same trait;<br>
113//! > &#9745;&emsp;Default implementations provided by the trait;<br>
114//! > &#9745;&emsp;Elided lifetimes;<br>
115//! > &#9745;&emsp;Dyn-capable traits.<br>
116//!
117//! <br>
118//!
119//! # Explanation
120//!
121//! Async fns get transformed into methods that return `Pin<Box<dyn Future +
James Farrell75bf7192023-08-16 19:13:20 +0000122//! Send + 'async_trait>>` and delegate to a private async freestanding function.
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100123//!
124//! For example the `impl Advertisement for AutoplayingVideo` above would be
125//! expanded as:
126//!
127//! ```
128//! # const IGNORE: &str = stringify! {
129//! impl Advertisement for AutoplayingVideo {
James Farrell75bf7192023-08-16 19:13:20 +0000130//! fn run<'async_trait>(
131//! &'async_trait self,
132//! ) -> Pin<Box<dyn core::future::Future<Output = ()> + Send + 'async_trait>>
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100133//! where
James Farrell75bf7192023-08-16 19:13:20 +0000134//! Self: Sync + 'async_trait,
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100135//! {
136//! async fn run(_self: &AutoplayingVideo) {
137//! /* the original method body */
138//! }
139//!
140//! Box::pin(run(self))
141//! }
142//! }
143//! # };
144//! ```
145//!
146//! <br><br>
147//!
148//! # Non-threadsafe futures
149//!
150//! Not all async traits need futures that are `dyn Future + Send`. To avoid
151//! having Send and Sync bounds placed on the async trait methods, invoke the
152//! async trait macro as `#[async_trait(?Send)]` on both the trait and the impl
153//! blocks.
154//!
155//! <br>
156//!
157//! # Elided lifetimes
158//!
159//! Be aware that async fn syntax does not allow lifetime elision outside of `&`
160//! and `&mut` references. (This is true even when not using #\[async_trait\].)
161//! Lifetimes must be named or marked by the placeholder `'_`.
162//!
163//! Fortunately the compiler is able to diagnose missing lifetimes with a good
164//! error message.
165//!
166//! ```compile_fail
167//! # use async_trait::async_trait;
168//! #
169//! type Elided<'a> = &'a usize;
170//!
171//! #[async_trait]
172//! trait Test {
173//! async fn test(not_okay: Elided, okay: &usize) {}
174//! }
175//! ```
176//!
177//! ```text
178//! error[E0726]: implicit elided lifetime not allowed here
179//! --> src/main.rs:9:29
180//! |
181//! 9 | async fn test(not_okay: Elided, okay: &usize) {}
182//! | ^^^^^^- help: indicate the anonymous lifetime: `<'_>`
183//! ```
184//!
185//! The fix is to name the lifetime or use `'_`.
186//!
187//! ```
188//! # use async_trait::async_trait;
189//! #
190//! # type Elided<'a> = &'a usize;
191//! #
192//! #[async_trait]
193//! trait Test {
194//! // either
195//! async fn test<'e>(elided: Elided<'e>) {}
196//! # }
197//! # #[async_trait]
198//! # trait Test2 {
199//! // or
200//! async fn test(elided: Elided<'_>) {}
201//! }
202//! ```
203//!
204//! <br><br>
205//!
206//! # Dyn traits
207//!
208//! Traits with async methods can be used as trait objects as long as they meet
209//! the usual requirements for dyn -- no methods with type parameters, no self
210//! by value, no associated types, etc.
211//!
212//! ```
213//! # use async_trait::async_trait;
214//! #
215//! #[async_trait]
216//! pub trait ObjectSafe {
217//! async fn f(&self);
218//! async fn g(&mut self);
219//! }
220//!
221//! # const IGNORE: &str = stringify! {
222//! impl ObjectSafe for MyType {...}
223//!
224//! let value: MyType = ...;
225//! # };
226//! #
227//! # struct MyType;
228//! #
229//! # #[async_trait]
230//! # impl ObjectSafe for MyType {
231//! # async fn f(&self) {}
232//! # async fn g(&mut self) {}
233//! # }
234//! #
235//! # let value: MyType = MyType;
236//! let object = &value as &dyn ObjectSafe; // make trait object
237//! ```
238//!
239//! The one wrinkle is in traits that provide default implementations of async
240//! methods. In order for the default implementation to produce a future that is
241//! Send, the async_trait macro must emit a bound of `Self: Sync` on trait
242//! methods that take `&self` and a bound `Self: Send` on trait methods that
243//! take `&mut self`. An example of the former is visible in the expanded code
244//! in the explanation section above.
245//!
246//! If you make a trait with async methods that have default implementations,
247//! everything will work except that the trait cannot be used as a trait object.
248//! Creating a value of type `&dyn Trait` will produce an error that looks like
249//! this:
250//!
251//! ```text
252//! error: the trait `Test` cannot be made into an object
253//! --> src/main.rs:8:5
254//! |
255//! 8 | async fn cannot_dyn(&self) {}
256//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
257//! ```
258//!
259//! For traits that need to be object safe and need to have default
260//! implementations for some async methods, there are two resolutions. Either
261//! you can add Send and/or Sync as supertraits (Send if there are `&mut self`
262//! methods with default implementations, Sync if there are `&self` methods with
Joel Galensonaa9cbeb2021-08-09 10:24:16 -0700263//! default implementations) to constrain all implementors of the trait such that
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100264//! the default implementations are applicable to them:
265//!
266//! ```
267//! # use async_trait::async_trait;
268//! #
269//! #[async_trait]
270//! pub trait ObjectSafe: Sync { // added supertrait
271//! async fn can_dyn(&self) {}
272//! }
273//! #
274//! # struct MyType;
275//! #
276//! # #[async_trait]
277//! # impl ObjectSafe for MyType {}
278//! #
279//! # let value = MyType;
280//!
281//! let object = &value as &dyn ObjectSafe;
282//! ```
283//!
284//! or you can strike the problematic methods from your trait object by
285//! bounding them with `Self: Sized`:
286//!
287//! ```
288//! # use async_trait::async_trait;
289//! #
290//! #[async_trait]
291//! pub trait ObjectSafe {
292//! async fn cannot_dyn(&self) where Self: Sized {}
293//!
294//! // presumably other methods
295//! }
296//! #
297//! # struct MyType;
298//! #
299//! # #[async_trait]
300//! # impl ObjectSafe for MyType {}
301//! #
302//! # let value = MyType;
303//!
304//! let object = &value as &dyn ObjectSafe;
305//! ```
306
Jeff Vander Stoepa414c4b2023-11-24 15:39:09 +0100307#![doc(html_root_url = "https://docs.rs/async-trait/0.1.74")]
Joel Galenson5448f372021-04-01 15:10:30 -0700308#![allow(
309 clippy::default_trait_access,
310 clippy::doc_markdown,
Jeff Vander Stoep0caaeed2022-12-06 08:25:24 +0100311 clippy::explicit_auto_deref,
Joel Galenson5448f372021-04-01 15:10:30 -0700312 clippy::if_not_else,
313 clippy::items_after_statements,
Matthew Maurer58e0c002023-03-23 00:42:03 +0000314 clippy::match_like_matches_macro,
Joel Galenson5448f372021-04-01 15:10:30 -0700315 clippy::module_name_repetitions,
316 clippy::shadow_unrelated,
317 clippy::similar_names,
318 clippy::too_many_lines
319)]
Haibo Huang7ff84c32020-11-24 20:53:12 -0800320
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100321extern crate proc_macro;
322
323mod args;
Jeff Vander Stoep0caaeed2022-12-06 08:25:24 +0100324mod bound;
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100325mod expand;
326mod lifetime;
327mod parse;
328mod receiver;
James Farrell75bf7192023-08-16 19:13:20 +0000329mod verbatim;
Andrew Walbrand1b91c72020-08-11 17:12:08 +0100330
331use crate::args::Args;
332use crate::expand::expand;
333use crate::parse::Item;
334use proc_macro::TokenStream;
335use quote::quote;
336use syn::parse_macro_input;
337
338#[proc_macro_attribute]
339pub fn async_trait(args: TokenStream, input: TokenStream) -> TokenStream {
340 let args = parse_macro_input!(args as Args);
341 let mut item = parse_macro_input!(input as Item);
342 expand(&mut item, args.local);
343 TokenStream::from(quote!(#item))
344}