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 //! > ☑ Self by value, by reference, by mut reference, or no self;<br>
124 //! > ☑ Any number of arguments, any return value;<br>
125 //! > ☑ Generic type parameters and lifetime parameters;<br>
126 //! > ☑ Associated types;<br>
127 //! > ☑ Having async and non-async functions in the same trait;<br>
128 //! > ☑ Default implementations provided by the trait;<br>
129 //! > ☑ 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