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