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