Skip to content

Commit 5689b60

Browse files
authored
Merge pull request #1 from kezhuw/not-send
Support !Send async function in #[asyncs::test]
2 parents 1249a1f + 17034f0 commit 5689b60

File tree

2 files changed

+83
-13
lines changed

2 files changed

+83
-13
lines changed

asyncs-test/src/lib.rs

+56-12
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,22 @@ type AttributeArgs = Punctuated<syn::Meta, syn::Token![,]>;
1212
struct Configuration {
1313
crate_name: Option<Ident>,
1414
parallelism: Option<usize>,
15+
send: Option<bool>,
1516
}
1617

1718
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+
1831
fn set_crate_name(&mut self, lit: &syn::Lit) -> Result<(), syn::Error> {
1932
let span = lit.span();
2033
if self.crate_name.is_some() {
@@ -65,6 +78,7 @@ fn parse_config(args: AttributeArgs) -> Result<Configuration, syn::Error> {
6578
match name.as_str() {
6679
"parallelism" => config.set_parallelism(lit)?,
6780
"crate" => config.set_crate_name(lit)?,
81+
"send" => config.set_send(lit)?,
6882
_ => return Err(syn::Error::new_spanned(&name_value, "unknown attribute name")),
6983
}
7084
},
@@ -128,21 +142,50 @@ fn generate(attr: TokenStream, item: TokenStream) -> TokenStream {
128142

129143
let prefer_env_parallelism = config.parallelism.is_none();
130144
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>() {
137150
::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)
141183
}
142184
}
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+
}
146189
}
147190
}
148191
}
@@ -153,6 +196,7 @@ fn generate(attr: TokenStream, item: TokenStream) -> TokenStream {
153196
/// * `parallelism`: non negative integer to specify parallelism for executor. Defaults to
154197
/// environment variable `ASYNCS_TEST_PARALLELISM` and `2` in fallback. `0` means available
155198
/// cores.
199+
/// * `send`: whether the async function need to be `Send`. Defaults to `true`.
156200
///
157201
/// ## Examples
158202
/// ```ignore

src/lib.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ pub use asyncs_test::test;
2929

3030
#[cfg(test)]
3131
mod tests {
32-
use std::future::{pending, ready};
32+
use std::future::{pending, ready, Future};
33+
use std::pin::Pin;
34+
use std::task::{Context, Poll};
3335

3436
use crate::select;
3537

@@ -56,4 +58,28 @@ mod tests {
5658
async fn with_test_case(input: i32) {
5759
assert_eq!(input, 6);
5860
}
61+
62+
struct NotSend {
63+
_rc: std::rc::Rc<()>,
64+
}
65+
66+
impl NotSend {
67+
fn new() -> Self {
68+
Self { _rc: std::rc::Rc::new(()) }
69+
}
70+
}
71+
72+
impl Future for NotSend {
73+
type Output = ();
74+
75+
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
76+
Poll::Ready(())
77+
}
78+
}
79+
80+
#[crate::test(crate = "crate", send = false)]
81+
async fn with_not_send() {
82+
let not_send = NotSend::new();
83+
not_send.await
84+
}
5985
}

0 commit comments

Comments
 (0)