@@ -12,9 +12,22 @@ type AttributeArgs = Punctuated<syn::Meta, syn::Token![,]>;
12
12
struct Configuration {
13
13
crate_name : Option < Ident > ,
14
14
parallelism : Option < usize > ,
15
+ send : Option < bool > ,
15
16
}
16
17
17
18
impl Configuration {
19
+ fn set_send ( & mut self , lit : & syn:: Lit ) -> Result < ( ) , syn:: Error > {
20
+ let span = lit. span ( ) ;
21
+ if self . send . is_some ( ) {
22
+ return Err ( syn:: Error :: new ( span, "`send` already set" ) ) ;
23
+ }
24
+ if let syn:: Lit :: Bool ( lit) = lit {
25
+ self . send = Some ( lit. value ) ;
26
+ return Ok ( ( ) ) ;
27
+ }
28
+ Err ( syn:: Error :: new ( span, "invalid `send` value, bool required" ) )
29
+ }
30
+
18
31
fn set_crate_name ( & mut self , lit : & syn:: Lit ) -> Result < ( ) , syn:: Error > {
19
32
let span = lit. span ( ) ;
20
33
if self . crate_name . is_some ( ) {
@@ -65,6 +78,7 @@ fn parse_config(args: AttributeArgs) -> Result<Configuration, syn::Error> {
65
78
match name. as_str ( ) {
66
79
"parallelism" => config. set_parallelism ( lit) ?,
67
80
"crate" => config. set_crate_name ( lit) ?,
81
+ "send" => config. set_send ( lit) ?,
68
82
_ => return Err ( syn:: Error :: new_spanned ( & name_value, "unknown attribute name" ) ) ,
69
83
}
70
84
} ,
@@ -128,21 +142,50 @@ fn generate(attr: TokenStream, item: TokenStream) -> TokenStream {
128
142
129
143
let prefer_env_parallelism = config. parallelism . is_none ( ) ;
130
144
let parallelism = config. parallelism . unwrap_or ( 2 ) ;
131
- quote ! {
132
- #( #attrs) *
133
- #[ :: core:: prelude:: v1:: test]
134
- #vis fn #name( ) #ret {
135
- let parallelism = match ( #prefer_env_parallelism, #parallelism) {
136
- ( true , parallelism) => match :: std:: env:: var( "ASYNCS_TEST_PARALLELISM" ) {
145
+ let parallelism = quote ! {
146
+ let parallelism = match ( #prefer_env_parallelism, #parallelism) {
147
+ ( true , parallelism) => match :: std:: env:: var( "ASYNCS_TEST_PARALLELISM" ) {
148
+ :: std:: result:: Result :: Err ( _) => parallelism,
149
+ :: std:: result:: Result :: Ok ( val) => match val. parse:: <usize >( ) {
137
150
:: std:: result:: Result :: Err ( _) => parallelism,
138
- :: std:: result:: Result :: Ok ( val) => match val. parse:: <usize >( ) {
139
- :: std:: result:: Result :: Err ( _) => parallelism,
140
- :: std:: result:: Result :: Ok ( n) => n,
151
+ :: std:: result:: Result :: Ok ( n) => n,
152
+ }
153
+ }
154
+ ( false , parallelism) => parallelism,
155
+ } ;
156
+ } ;
157
+
158
+ let send = config. send . unwrap_or ( true ) ;
159
+ if send {
160
+ quote ! {
161
+ #( #attrs) *
162
+ #[ :: core:: prelude:: v1:: test]
163
+ #vis fn #name( ) #ret {
164
+ #parallelism
165
+ #crate_name:: __executor:: Blocking :: new( parallelism) . block_on( async move #body)
166
+ }
167
+ }
168
+ } else {
169
+ quote ! {
170
+ #( #attrs) *
171
+ #[ :: core:: prelude:: v1:: test]
172
+ #vis fn #name( ) #ret {
173
+ struct _Sendable<T >( T ) ;
174
+
175
+ unsafe impl <T > Send for _Sendable<T > { }
176
+
177
+ impl <T : :: core:: future:: Future > :: core:: future:: Future for _Sendable<T > {
178
+ type Output = T :: Output ;
179
+
180
+ fn poll( self : :: core:: pin:: Pin <& mut Self >, cx: & mut :: core:: task:: Context <' _>) -> :: core:: task:: Poll <Self :: Output > {
181
+ let future = unsafe { :: core:: pin:: Pin :: new_unchecked( & mut self . get_unchecked_mut( ) . 0 ) } ;
182
+ future. poll( cx)
141
183
}
142
184
}
143
- ( false , parallelism) => parallelism,
144
- } ;
145
- #crate_name:: __executor:: Blocking :: new( parallelism) . block_on( async move #body)
185
+
186
+ #parallelism
187
+ #crate_name:: __executor:: Blocking :: new( parallelism) . block_on( _Sendable( async move #body) )
188
+ }
146
189
}
147
190
}
148
191
}
@@ -153,6 +196,7 @@ fn generate(attr: TokenStream, item: TokenStream) -> TokenStream {
153
196
/// * `parallelism`: non negative integer to specify parallelism for executor. Defaults to
154
197
/// environment variable `ASYNCS_TEST_PARALLELISM` and `2` in fallback. `0` means available
155
198
/// cores.
199
+ /// * `send`: whether the async function need to be `Send`. Defaults to `true`.
156
200
///
157
201
/// ## Examples
158
202
/// ```ignore
0 commit comments