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.78" )] |
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 | )] |
332 | |
333 | extern crate proc_macro; |
334 | |
335 | mod args; |
336 | mod bound; |
337 | mod expand; |
338 | mod lifetime; |
339 | mod parse; |
340 | mod receiver; |
341 | mod verbatim; |
342 | |
343 | use crate::args::Args; |
344 | use crate::expand::expand; |
345 | use crate::parse::Item; |
346 | use proc_macro::TokenStream; |
347 | use quote::quote; |
348 | use syn::parse_macro_input; |
349 | |
350 | #[proc_macro_attribute ] |
351 | pub fn async_trait (args: TokenStream, input: TokenStream) -> TokenStream { |
352 | let args: Args = parse_macro_input!(args as Args); |
353 | let mut item: Item = parse_macro_input!(input as Item); |
354 | expand(&mut item, is_local:args.local); |
355 | TokenStream::from(quote!(#item)) |
356 | } |
357 | |