• 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&logo=docs.rs
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 #![cfg_attr(not(native_async_fn_in_trait), doc = "```compile_fail")]
16 #![cfg_attr(native_async_fn_in_trait, doc = "```")]
17 //! trait MyTrait {
18 //!     async fn f() {}
19 //! }
20 #![doc = "```"]
21 //!
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 +
122 //! Send + 'async_trait>>` and delegate to a private async freestanding function.
123 //!
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 {
130 //!     fn run<'async_trait>(
131 //!         &'async_trait self,
132 //!     ) -> Pin<Box<dyn core::future::Future<Output = ()> + Send + 'async_trait>>
133 //!     where
134 //!         Self: Sync + 'async_trait,
135 //!     {
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
263 //! default implementations) to constrain all implementors of the trait such that
264 //! 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 
307 #![doc(html_root_url = "https://docs.rs/async-trait/0.1.74")]
308 #![allow(
309     clippy::default_trait_access,
310     clippy::doc_markdown,
311     clippy::explicit_auto_deref,
312     clippy::if_not_else,
313     clippy::items_after_statements,
314     clippy::match_like_matches_macro,
315     clippy::module_name_repetitions,
316     clippy::shadow_unrelated,
317     clippy::similar_names,
318     clippy::too_many_lines
319 )]
320 
321 extern crate proc_macro;
322 
323 mod args;
324 mod bound;
325 mod expand;
326 mod lifetime;
327 mod parse;
328 mod receiver;
329 mod verbatim;
330 
331 use crate::args::Args;
332 use crate::expand::expand;
333 use crate::parse::Item;
334 use proc_macro::TokenStream;
335 use quote::quote;
336 use syn::parse_macro_input;
337 
338 #[proc_macro_attribute]
async_trait(args: TokenStream, input: TokenStream) -> TokenStream339 pub 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 }
345