1 #![allow(clippy::needless_doctest_main)]
2 #![warn(
3 missing_debug_implementations,
4 missing_docs,
5 rust_2018_idioms,
6 unreachable_pub
7 )]
8 #![doc(test(
9 no_crate_inject,
10 attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
11 ))]
12
13 //! Macros for use with Tokio
14
15 // This `extern` is required for older `rustc` versions but newer `rustc`
16 // versions warn about the unused `extern crate`.
17 #[allow(unused_extern_crates)]
18 extern crate proc_macro;
19
20 mod entry;
21 mod select;
22
23 use proc_macro::TokenStream;
24
25 /// Marks async function to be executed by the selected runtime. This macro
26 /// helps set up a `Runtime` without requiring the user to use
27 /// [Runtime](../tokio/runtime/struct.Runtime.html) or
28 /// [Builder](../tokio/runtime/struct.Builder.html) directly.
29 ///
30 /// Note: This macro is designed to be simplistic and targets applications that
31 /// do not require a complex setup. If the provided functionality is not
32 /// sufficient, you may be interested in using
33 /// [Builder](../tokio/runtime/struct.Builder.html), which provides a more
34 /// powerful interface.
35 ///
36 /// Note: This macro can be used on any function and not just the `main`
37 /// function. Using it on a non-main function makes the function behave as if it
38 /// was synchronous by starting a new runtime each time it is called. If the
39 /// function is called often, it is preferable to create the runtime using the
40 /// runtime builder so the runtime can be reused across calls.
41 ///
42 /// # Non-worker async function
43 ///
44 /// Note that the async function marked with this macro does not run as a
45 /// worker. The expectation is that other tasks are spawned by the function here.
46 /// Awaiting on other futures from the function provided here will not
47 /// perform as fast as those spawned as workers.
48 ///
49 /// # Multi-threaded runtime
50 ///
51 /// To use the multi-threaded runtime, the macro can be configured using
52 ///
53 /// ```
54 /// #[tokio::main(flavor = "multi_thread", worker_threads = 10)]
55 /// # async fn main() {}
56 /// ```
57 ///
58 /// The `worker_threads` option configures the number of worker threads, and
59 /// defaults to the number of cpus on the system. This is the default flavor.
60 ///
61 /// Note: The multi-threaded runtime requires the `rt-multi-thread` feature
62 /// flag.
63 ///
64 /// # Current thread runtime
65 ///
66 /// To use the single-threaded runtime known as the `current_thread` runtime,
67 /// the macro can be configured using
68 ///
69 /// ```
70 /// #[tokio::main(flavor = "current_thread")]
71 /// # async fn main() {}
72 /// ```
73 ///
74 /// ## Function arguments:
75 ///
76 /// Arguments are allowed for any functions aside from `main` which is special
77 ///
78 /// ## Usage
79 ///
80 /// ### Using the multi-thread runtime
81 ///
82 /// ```rust
83 /// #[tokio::main]
84 /// async fn main() {
85 /// println!("Hello world");
86 /// }
87 /// ```
88 ///
89 /// Equivalent code not using `#[tokio::main]`
90 ///
91 /// ```rust
92 /// fn main() {
93 /// tokio::runtime::Builder::new_multi_thread()
94 /// .enable_all()
95 /// .build()
96 /// .unwrap()
97 /// .block_on(async {
98 /// println!("Hello world");
99 /// })
100 /// }
101 /// ```
102 ///
103 /// ### Using current thread runtime
104 ///
105 /// The basic scheduler is single-threaded.
106 ///
107 /// ```rust
108 /// #[tokio::main(flavor = "current_thread")]
109 /// async fn main() {
110 /// println!("Hello world");
111 /// }
112 /// ```
113 ///
114 /// Equivalent code not using `#[tokio::main]`
115 ///
116 /// ```rust
117 /// fn main() {
118 /// tokio::runtime::Builder::new_current_thread()
119 /// .enable_all()
120 /// .build()
121 /// .unwrap()
122 /// .block_on(async {
123 /// println!("Hello world");
124 /// })
125 /// }
126 /// ```
127 ///
128 /// ### Set number of worker threads
129 ///
130 /// ```rust
131 /// #[tokio::main(worker_threads = 2)]
132 /// async fn main() {
133 /// println!("Hello world");
134 /// }
135 /// ```
136 ///
137 /// Equivalent code not using `#[tokio::main]`
138 ///
139 /// ```rust
140 /// fn main() {
141 /// tokio::runtime::Builder::new_multi_thread()
142 /// .worker_threads(2)
143 /// .enable_all()
144 /// .build()
145 /// .unwrap()
146 /// .block_on(async {
147 /// println!("Hello world");
148 /// })
149 /// }
150 /// ```
151 ///
152 /// ### Configure the runtime to start with time paused
153 ///
154 /// ```rust
155 /// #[tokio::main(flavor = "current_thread", start_paused = true)]
156 /// async fn main() {
157 /// println!("Hello world");
158 /// }
159 /// ```
160 ///
161 /// Equivalent code not using `#[tokio::main]`
162 ///
163 /// ```rust
164 /// fn main() {
165 /// tokio::runtime::Builder::new_current_thread()
166 /// .enable_all()
167 /// .start_paused(true)
168 /// .build()
169 /// .unwrap()
170 /// .block_on(async {
171 /// println!("Hello world");
172 /// })
173 /// }
174 /// ```
175 ///
176 /// Note that `start_paused` requires the `test-util` feature to be enabled.
177 ///
178 /// ### Rename package
179 ///
180 /// ```rust
181 /// use tokio as tokio1;
182 ///
183 /// #[tokio1::main(crate = "tokio1")]
184 /// async fn main() {
185 /// println!("Hello world");
186 /// }
187 /// ```
188 ///
189 /// Equivalent code not using `#[tokio::main]`
190 ///
191 /// ```rust
192 /// use tokio as tokio1;
193 ///
194 /// fn main() {
195 /// tokio1::runtime::Builder::new_multi_thread()
196 /// .enable_all()
197 /// .build()
198 /// .unwrap()
199 /// .block_on(async {
200 /// println!("Hello world");
201 /// })
202 /// }
203 /// ```
204 #[proc_macro_attribute]
205 #[cfg(not(test))] // Work around for rust-lang/rust#62127
main(args: TokenStream, item: TokenStream) -> TokenStream206 pub fn main(args: TokenStream, item: TokenStream) -> TokenStream {
207 entry::main(args.into(), item.into(), true).into()
208 }
209
210 /// Marks async function to be executed by selected runtime. This macro helps set up a `Runtime`
211 /// without requiring the user to use [Runtime](../tokio/runtime/struct.Runtime.html) or
212 /// [Builder](../tokio/runtime/struct.builder.html) directly.
213 ///
214 /// ## Function arguments:
215 ///
216 /// Arguments are allowed for any functions aside from `main` which is special
217 ///
218 /// ## Usage
219 ///
220 /// ### Using default
221 ///
222 /// ```rust
223 /// #[tokio::main(flavor = "current_thread")]
224 /// async fn main() {
225 /// println!("Hello world");
226 /// }
227 /// ```
228 ///
229 /// Equivalent code not using `#[tokio::main]`
230 ///
231 /// ```rust
232 /// fn main() {
233 /// tokio::runtime::Builder::new_current_thread()
234 /// .enable_all()
235 /// .build()
236 /// .unwrap()
237 /// .block_on(async {
238 /// println!("Hello world");
239 /// })
240 /// }
241 /// ```
242 ///
243 /// ### Rename package
244 ///
245 /// ```rust
246 /// use tokio as tokio1;
247 ///
248 /// #[tokio1::main(crate = "tokio1")]
249 /// async fn main() {
250 /// println!("Hello world");
251 /// }
252 /// ```
253 ///
254 /// Equivalent code not using `#[tokio::main]`
255 ///
256 /// ```rust
257 /// use tokio as tokio1;
258 ///
259 /// fn main() {
260 /// tokio1::runtime::Builder::new_multi_thread()
261 /// .enable_all()
262 /// .build()
263 /// .unwrap()
264 /// .block_on(async {
265 /// println!("Hello world");
266 /// })
267 /// }
268 /// ```
269 #[proc_macro_attribute]
270 #[cfg(not(test))] // Work around for rust-lang/rust#62127
main_rt(args: TokenStream, item: TokenStream) -> TokenStream271 pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream {
272 entry::main(args.into(), item.into(), false).into()
273 }
274
275 /// Marks async function to be executed by runtime, suitable to test environment.
276 /// This macro helps set up a `Runtime` without requiring the user to use
277 /// [Runtime](../tokio/runtime/struct.Runtime.html) or
278 /// [Builder](../tokio/runtime/struct.Builder.html) directly.
279 ///
280 /// Note: This macro is designed to be simplistic and targets applications that
281 /// do not require a complex setup. If the provided functionality is not
282 /// sufficient, you may be interested in using
283 /// [Builder](../tokio/runtime/struct.Builder.html), which provides a more
284 /// powerful interface.
285 ///
286 /// # Multi-threaded runtime
287 ///
288 /// To use the multi-threaded runtime, the macro can be configured using
289 ///
290 /// ```no_run
291 /// #[tokio::test(flavor = "multi_thread", worker_threads = 1)]
292 /// async fn my_test() {
293 /// assert!(true);
294 /// }
295 /// ```
296 ///
297 /// The `worker_threads` option configures the number of worker threads, and
298 /// defaults to the number of cpus on the system.
299 ///
300 /// Note: The multi-threaded runtime requires the `rt-multi-thread` feature
301 /// flag.
302 ///
303 /// # Current thread runtime
304 ///
305 /// The default test runtime is single-threaded. Each test gets a
306 /// separate current-thread runtime.
307 ///
308 /// ```no_run
309 /// #[tokio::test]
310 /// async fn my_test() {
311 /// assert!(true);
312 /// }
313 /// ```
314 ///
315 /// ## Usage
316 ///
317 /// ### Using the multi-thread runtime
318 ///
319 /// ```no_run
320 /// #[tokio::test(flavor = "multi_thread")]
321 /// async fn my_test() {
322 /// assert!(true);
323 /// }
324 /// ```
325 ///
326 /// Equivalent code not using `#[tokio::test]`
327 ///
328 /// ```no_run
329 /// #[test]
330 /// fn my_test() {
331 /// tokio::runtime::Builder::new_multi_thread()
332 /// .enable_all()
333 /// .build()
334 /// .unwrap()
335 /// .block_on(async {
336 /// assert!(true);
337 /// })
338 /// }
339 /// ```
340 ///
341 /// ### Using current thread runtime
342 ///
343 /// ```no_run
344 /// #[tokio::test]
345 /// async fn my_test() {
346 /// assert!(true);
347 /// }
348 /// ```
349 ///
350 /// Equivalent code not using `#[tokio::test]`
351 ///
352 /// ```no_run
353 /// #[test]
354 /// fn my_test() {
355 /// tokio::runtime::Builder::new_current_thread()
356 /// .enable_all()
357 /// .build()
358 /// .unwrap()
359 /// .block_on(async {
360 /// assert!(true);
361 /// })
362 /// }
363 /// ```
364 ///
365 /// ### Set number of worker threads
366 ///
367 /// ```no_run
368 /// #[tokio::test(flavor ="multi_thread", worker_threads = 2)]
369 /// async fn my_test() {
370 /// assert!(true);
371 /// }
372 /// ```
373 ///
374 /// Equivalent code not using `#[tokio::test]`
375 ///
376 /// ```no_run
377 /// #[test]
378 /// fn my_test() {
379 /// tokio::runtime::Builder::new_multi_thread()
380 /// .worker_threads(2)
381 /// .enable_all()
382 /// .build()
383 /// .unwrap()
384 /// .block_on(async {
385 /// assert!(true);
386 /// })
387 /// }
388 /// ```
389 ///
390 /// ### Configure the runtime to start with time paused
391 ///
392 /// ```no_run
393 /// #[tokio::test(start_paused = true)]
394 /// async fn my_test() {
395 /// assert!(true);
396 /// }
397 /// ```
398 ///
399 /// Equivalent code not using `#[tokio::test]`
400 ///
401 /// ```no_run
402 /// #[test]
403 /// fn my_test() {
404 /// tokio::runtime::Builder::new_current_thread()
405 /// .enable_all()
406 /// .start_paused(true)
407 /// .build()
408 /// .unwrap()
409 /// .block_on(async {
410 /// assert!(true);
411 /// })
412 /// }
413 /// ```
414 ///
415 /// Note that `start_paused` requires the `test-util` feature to be enabled.
416 ///
417 /// ### Rename package
418 ///
419 /// ```rust
420 /// use tokio as tokio1;
421 ///
422 /// #[tokio1::test(crate = "tokio1")]
423 /// async fn my_test() {
424 /// println!("Hello world");
425 /// }
426 /// ```
427 #[proc_macro_attribute]
test(args: TokenStream, item: TokenStream) -> TokenStream428 pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
429 entry::test(args.into(), item.into(), true).into()
430 }
431
432 /// Marks async function to be executed by runtime, suitable to test environment
433 ///
434 /// ## Usage
435 ///
436 /// ```no_run
437 /// #[tokio::test]
438 /// async fn my_test() {
439 /// assert!(true);
440 /// }
441 /// ```
442 #[proc_macro_attribute]
test_rt(args: TokenStream, item: TokenStream) -> TokenStream443 pub fn test_rt(args: TokenStream, item: TokenStream) -> TokenStream {
444 entry::test(args.into(), item.into(), false).into()
445 }
446
447 /// Always fails with the error message below.
448 /// ```text
449 /// The #[tokio::main] macro requires rt or rt-multi-thread.
450 /// ```
451 #[proc_macro_attribute]
main_fail(_args: TokenStream, _item: TokenStream) -> TokenStream452 pub fn main_fail(_args: TokenStream, _item: TokenStream) -> TokenStream {
453 syn::Error::new(
454 proc_macro2::Span::call_site(),
455 "The #[tokio::main] macro requires rt or rt-multi-thread.",
456 )
457 .to_compile_error()
458 .into()
459 }
460
461 /// Always fails with the error message below.
462 /// ```text
463 /// The #[tokio::test] macro requires rt or rt-multi-thread.
464 /// ```
465 #[proc_macro_attribute]
test_fail(_args: TokenStream, _item: TokenStream) -> TokenStream466 pub fn test_fail(_args: TokenStream, _item: TokenStream) -> TokenStream {
467 syn::Error::new(
468 proc_macro2::Span::call_site(),
469 "The #[tokio::test] macro requires rt or rt-multi-thread.",
470 )
471 .to_compile_error()
472 .into()
473 }
474
475 /// Implementation detail of the `select!` macro. This macro is **not** intended
476 /// to be used as part of the public API and is permitted to change.
477 #[proc_macro]
478 #[doc(hidden)]
select_priv_declare_output_enum(input: TokenStream) -> TokenStream479 pub fn select_priv_declare_output_enum(input: TokenStream) -> TokenStream {
480 select::declare_output_enum(input)
481 }
482
483 /// Implementation detail of the `select!` macro. This macro is **not** intended
484 /// to be used as part of the public API and is permitted to change.
485 #[proc_macro]
486 #[doc(hidden)]
select_priv_clean_pattern(input: TokenStream) -> TokenStream487 pub fn select_priv_clean_pattern(input: TokenStream) -> TokenStream {
488 select::clean_pattern_macro(input)
489 }
490