1
- //! Proc Macro attributes for the [Runtime](https://github.com/rustasync/runtime) crate. See the
2
- //! [Runtime](https://docs.rs/runtime) documentation for more details.
1
+ //! Experimental language-level polyfills for Async Rust.
2
+ //!
3
+ //! # Examples
4
+ //!
5
+ //! ```
6
+ //! use async_std::task;
7
+ //!
8
+ //! #[async_attributes::main]
9
+ //! async fn main() {
10
+ //! println!("Hello, world!");
11
+ //! }
12
+ //! ```
13
+ //!
14
+ //! # About
15
+ //!
16
+ //! Async Rust is a work in progress. The language has enabled us to do some
17
+ //! fantastic things, but not everything is figured out yet. This crate exists
18
+ //! to polyfill language-level support for async idioms before they can be part
19
+ //! of the language.
20
+ //!
21
+ //! A great example of this is `async fn main`, which we first introduced as
22
+ //! part of the [`runtime`](https://docs.rs/runtime/0.3.0-alpha.7/runtime/) crate.
23
+ //! Its premise is that if `async fn` is required for every `await` call, it
24
+ //! makes sense to apply that even to `fn main`. Unfortunately this would
25
+ //! require compiler support to enable, so we've provided an experimental
26
+ //! polyfill for it in the mean time.
27
+ //!
28
+ //! # Why isn't this crate part of async-std?
29
+ //!
30
+ //! We want to make sure `async-std`'s surface area is stable, and only includes
31
+ //! things that would make sense to be part of "an async version of std".
32
+ //! Language level support is really important, but _not_ part of the standard
33
+ //! library.
34
+ //!
35
+ //! This has some distinct benefits: in particular it allows us to
36
+ //! version both crates at a different pace. And as features are added to the
37
+ //! language (or we decide they weren't a great idea after all), we can
38
+ //! incrementally shrink the surface area of this crate.
39
+ //!
40
+ //! The other big benefit is that it allows libraries to depend on `async-std`
41
+ //! without needing to pull in the rather heavy `syn`, `quote`, and
42
+ //! `proc-macro2` crates. This should help keep compilation times snappy for
43
+ //! everyone.
3
44
4
45
#![ forbid( unsafe_code, future_incompatible, rust_2018_idioms) ]
5
46
#![ deny( missing_debug_implementations, nonstandard_style) ]
6
- #![ feature( async_await) ]
7
47
#![ recursion_limit = "512" ]
8
48
9
49
extern crate proc_macro;
@@ -17,28 +57,14 @@ use syn::spanned::Spanned;
17
57
/// # Examples
18
58
///
19
59
/// ```ignore
20
- /// #![feature(async_await)]
21
- ///
22
- /// #[runtime::main]
60
+ /// #[async_attributes::main]
23
61
/// async fn main() -> std::io::Result<()> {
24
62
/// Ok(())
25
63
/// }
26
64
/// ```
27
65
#[ cfg( not( test) ) ] // NOTE: exporting main breaks tests, we should file an issue.
28
66
#[ proc_macro_attribute]
29
- pub fn main ( attr : TokenStream , item : TokenStream ) -> TokenStream {
30
- let rt = if attr. is_empty ( ) {
31
- if cfg ! ( feature = "native" ) {
32
- syn:: parse_str ( "runtime::native::Native" ) . unwrap ( )
33
- } else {
34
- let tokens = quote_spanned ! { proc_macro2:: Span :: call_site( ) =>
35
- compile_error!( "async runtime needs to be specified if no default runtime is set" ) ;
36
- } ;
37
- return TokenStream :: from ( tokens) ;
38
- }
39
- } else {
40
- syn:: parse_macro_input!( attr as syn:: Expr )
41
- } ;
67
+ pub fn main ( _attr : TokenStream , item : TokenStream ) -> TokenStream {
42
68
let input = syn:: parse_macro_input!( item as syn:: ItemFn ) ;
43
69
44
70
let ret = & input. decl . output ;
@@ -48,17 +74,15 @@ pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
48
74
let attrs = & input. attrs ;
49
75
50
76
if name != "main" {
51
- let tokens = quote_spanned ! { name. span( ) =>
52
- compile_error!( "only the main function can be tagged with #[runtime::main]" ) ;
53
- } ;
54
- return TokenStream :: from ( tokens) ;
77
+ return TokenStream :: from ( quote_spanned ! { name. span( ) =>
78
+ compile_error!( "only the main function can be tagged with #[runtime::main]" ) ,
79
+ } ) ;
55
80
}
56
81
57
82
if input. asyncness . is_none ( ) {
58
- let tokens = quote_spanned ! { input. span( ) =>
59
- compile_error!( "the async keyword is missing from the function declaration" ) ;
60
- } ;
61
- return TokenStream :: from ( tokens) ;
83
+ return TokenStream :: from ( quote_spanned ! { input. span( ) =>
84
+ compile_error!( "the async keyword is missing from the function declaration" ) ,
85
+ } ) ;
62
86
}
63
87
64
88
let result = quote ! {
@@ -68,7 +92,7 @@ pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
68
92
#body
69
93
}
70
94
71
- runtime :: raw :: enter ( #rt , async {
95
+ async_std :: task :: block_on ( async {
72
96
main( ) . await
73
97
} )
74
98
}
@@ -83,27 +107,14 @@ pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
83
107
/// # Examples
84
108
///
85
109
/// ```ignore
86
- /// #![feature(async_await)]
87
- ///
88
- /// #[runtime::test]
89
- /// async fn main() -> std::io::Result<()> {
110
+ /// #[async_attributes::test]
111
+ /// async fn my_test() -> std::io::Result<()> {
112
+ /// assert_eq(2 * 2, 4);
90
113
/// Ok(())
91
114
/// }
92
115
/// ```
93
116
#[ proc_macro_attribute]
94
- pub fn test ( attr : TokenStream , item : TokenStream ) -> TokenStream {
95
- let rt = if attr. is_empty ( ) {
96
- if cfg ! ( feature = "native" ) {
97
- syn:: parse_str ( "runtime::native::Native" ) . unwrap ( )
98
- } else {
99
- let tokens = quote_spanned ! { proc_macro2:: Span :: call_site( ) =>
100
- compile_error!( "async runtime needs to be specified if no default runtime is set" ) ;
101
- } ;
102
- return TokenStream :: from ( tokens) ;
103
- }
104
- } else {
105
- syn:: parse_macro_input!( attr as syn:: Expr )
106
- } ;
117
+ pub fn test ( _attr : TokenStream , item : TokenStream ) -> TokenStream {
107
118
let input = syn:: parse_macro_input!( item as syn:: ItemFn ) ;
108
119
109
120
let ret = & input. decl . output ;
@@ -112,18 +123,17 @@ pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream {
112
123
let attrs = & input. attrs ;
113
124
114
125
if input. asyncness . is_none ( ) {
115
- let tokens = quote_spanned ! { input. span( ) =>
116
- compile_error!( "the async keyword is missing from the function declaration" ) ;
117
- } ;
118
- return TokenStream :: from ( tokens) ;
126
+ return TokenStream :: from ( quote_spanned ! { input. span( ) =>
127
+ compile_error!( "the async keyword is missing from the function declaration" ) ,
128
+ } ) ;
119
129
}
120
130
121
131
let result = quote ! {
122
- #[ test]
123
- #( #attrs) *
124
- fn #name( ) #ret {
125
- runtime :: raw :: enter ( #rt , async { #body } )
126
- }
132
+ #[ test]
133
+ #( #attrs) *
134
+ fn #name( ) #ret {
135
+ async_std :: task :: block_on ( async { #body } )
136
+ }
127
137
} ;
128
138
129
139
result. into ( )
@@ -134,29 +144,21 @@ pub fn test(attr: TokenStream, item: TokenStream) -> TokenStream {
134
144
/// # Examples
135
145
///
136
146
/// ```ignore
137
- /// #![feature(async_await, test)]
147
+ /// #![feature(test)]
138
148
///
139
149
/// extern crate test;
140
150
///
141
- /// #[runtime::test]
151
+ /// use async_std::task;
152
+ ///
153
+ /// #[async_attributes::test]
142
154
/// async fn spawn_and_await() {
143
- /// runtime::spawn(async {}).await;
155
+ /// task::spawn(async {
156
+ /// println!("hello world");
157
+ /// }).await;
144
158
/// }
145
159
/// ```
146
160
#[ proc_macro_attribute]
147
- pub fn bench ( attr : TokenStream , item : TokenStream ) -> TokenStream {
148
- let rt = if attr. is_empty ( ) {
149
- if cfg ! ( feature = "native" ) {
150
- syn:: parse_str ( "runtime::native::Native" ) . unwrap ( )
151
- } else {
152
- let tokens = quote_spanned ! { proc_macro2:: Span :: call_site( ) =>
153
- compile_error!( "async runtime needs to be specified if no default runtime is set" ) ;
154
- } ;
155
- return TokenStream :: from ( tokens) ;
156
- }
157
- } else {
158
- syn:: parse_macro_input!( attr as syn:: Expr )
159
- } ;
161
+ pub fn bench ( _attr : TokenStream , item : TokenStream ) -> TokenStream {
160
162
let input = syn:: parse_macro_input!( item as syn:: ItemFn ) ;
161
163
162
164
let args = & input. decl . inputs ;
@@ -165,27 +167,25 @@ pub fn bench(attr: TokenStream, item: TokenStream) -> TokenStream {
165
167
let attrs = & input. attrs ;
166
168
167
169
if input. asyncness . is_none ( ) {
168
- let tokens = quote_spanned ! { input. span( ) =>
169
- compile_error!( "the async keyword is missing from the function declaration" ) ;
170
- } ;
171
- return TokenStream :: from ( tokens) ;
170
+ return TokenStream :: from ( quote_spanned ! { input. span( ) =>
171
+ compile_error!( "the async keyword is missing from the function declaration" ) ,
172
+ } ) ;
172
173
}
173
174
174
175
if !args. is_empty ( ) {
175
- let tokens = quote_spanned ! { args. span( ) =>
176
- compile_error!( "async benchmarks don't take any arguments" ) ;
177
- } ;
178
- return TokenStream :: from ( tokens) ;
176
+ return TokenStream :: from ( quote_spanned ! { args. span( ) =>
177
+ compile_error!( "async benchmarks don't take any arguments" ) ,
178
+ } ) ;
179
179
}
180
180
181
181
let result = quote ! {
182
- #[ bench]
183
- #( #attrs) *
184
- fn #name( b: & mut test:: Bencher ) {
185
- b. iter( || {
186
- let _ = runtime :: raw :: enter ( #rt , async { #body } ) ;
187
- } ) ;
188
- }
182
+ #[ bench]
183
+ #( #attrs) *
184
+ fn #name( b: & mut test:: Bencher ) {
185
+ b. iter( || {
186
+ let _ = async_std :: task :: block_on ( async { #body } ) ;
187
+ } ) ;
188
+ }
189
189
} ;
190
190
191
191
result. into ( )
0 commit comments