#! [allow(unknown_lints, unexpected_cfgs)]
#! [cfg(feature =
"macros" )]
#! [allow(clippy::disallowed_names)]
#[ cfg(all(target_family =
"wasm" , not(target_os =
"wasi" )))]
use wasm_bindgen_test::wasm_bindgen_test
as maybe_tokio_test;
#[ cfg(not(all(target_family =
"wasm" , not(target_os =
"wasi" ))))]
use tokio::test
as maybe_tokio_test;
use tokio::sync::oneshot;
use tokio_test::{assert_ok, assert_pending, assert_ready};
use futures::future::poll_fn;
use std::task::Poll::Ready;
#[ maybe_tokio_test]
async fn sync_one_lit_expr_comma() {
let foo = tokio::select! {
foo =
async {
1 } => foo,
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn no_branch_else_only() {
let foo = tokio::select! {
else =>
1 ,
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn no_branch_else_only_biased() {
let foo = tokio::select! {
biased;
else =>
1 ,
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn nested_one() {
let foo = tokio::select! {
foo =
async {
1 } => tokio::select! {
bar =
async { foo } => bar,
},
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn sync_one_lit_expr_no_comma() {
let foo = tokio::select! {
foo =
async {
1 } => foo
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn sync_one_lit_expr_block() {
let foo = tokio::select! {
foo =
async {
1 } => { foo }
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn sync_one_await() {
let foo = tokio::select! {
foo = one() => foo,
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn sync_one_ident() {
let one = one();
let foo = tokio::select! {
foo = one => foo,
};
assert_eq!(foo,
1 );
}
#[ maybe_tokio_test]
async fn sync_two() {
use std::cell::Cell;
let cnt = Cell::new(
0 );
let res = tokio::select! {
foo =
async {
cnt.set(cnt.get() +
1 );
1
} => foo,
bar =
async {
cnt.set(cnt.get() +
1 );
2
} => bar,
};
assert_eq!(
1 , cnt.get());
assert!(res ==
1 || res ==
2 );
}
#[ maybe_tokio_test]
async fn drop_in_fut() {
let s =
"hello" .to_string();
let res = tokio::select! {
foo =
async {
let v = one().
await ;
drop(s);
v
} => foo
};
assert_eq!(res,
1 );
}
#[ maybe_tokio_test]
#[ cfg(feature =
"full" )]
async fn one_ready() {
let (tx1, rx1) = oneshot::channel::<i32>();
let (_tx2, rx2) = oneshot::channel::<i32>();
tx1.send(
1 ).unwrap();
let v = tokio::select! {
res = rx1 => {
assert_ok!(res)
},
_ = rx2 => unreachable!(),
};
assert_eq!(
1 , v);
}
#[ maybe_tokio_test]
#[ cfg(feature =
"full" )]
async fn select_streams() {
use tokio::sync::mpsc;
let (tx1,
mut rx1) = mpsc::unbounded_channel::<i32>();
let (tx2,
mut rx2) = mpsc::unbounded_channel::<i32>();
tokio::spawn(
async move {
assert_ok!(tx2.send(
1 ));
tokio::task::yield_now().
await ;
assert_ok!(tx1.send(
2 ));
tokio::task::yield_now().
await ;
assert_ok!(tx2.send(
3 ));
tokio::task::yield_now().
await ;
drop((tx1, tx2));
});
let mut rem =
true ;
let mut msgs = vec![];
while rem {
tokio::select! {
Some(x) = rx1.recv() => {
msgs.push(x);
}
Some(y) = rx2.recv() => {
msgs.push(y);
}
else => {
rem =
false ;
}
}
}
msgs.sort_unstable();
assert_eq!(&msgs[..], &[
1 ,
2 ,
3 ]);
}
#[ maybe_tokio_test]
async fn move_uncompleted_futures() {
let (tx1,
mut rx1) = oneshot::channel::<i32>();
let (tx2,
mut rx2) = oneshot::channel::<i32>();
tx1.send(
1 ).unwrap();
tx2.send(
2 ).unwrap();
let ran;
tokio::select! {
res = &
mut rx1 => {
assert_eq!(
1 , assert_ok!(res));
assert_eq!(
2 , assert_ok!(rx2.
await ));
ran =
true ;
},
res = &
mut rx2 => {
assert_eq!(
2 , assert_ok!(res));
assert_eq!(
1 , assert_ok!(rx1.
await ));
ran =
true ;
},
}
assert!(ran);
}
#[ maybe_tokio_test]
async fn nested() {
let res = tokio::select! {
x =
async {
1 } => {
tokio::select! {
y =
async {
2 } => x + y,
}
}
};
assert_eq!(res,
3 );
}
#[ cfg(target_pointer_width =
"64" )]
mod pointer_64_tests {
use super ::maybe_tokio_test;
use futures::future;
use std::mem;
#[ maybe_tokio_test]
async fn struct_size_1() {
let fut =
async {
let ready = future::ready(
0 i32);
tokio::select! {
_ = ready => {},
}
};
assert_eq!(mem::size_of_val(&fut),
32 );
}
#[ maybe_tokio_test]
async fn struct_size_2() {
let fut =
async {
let ready1 = future::ready(
0 i32);
let ready2 = future::ready(
0 i32);
tokio::select! {
_ = ready1 => {},
_ = ready2 => {},
}
};
assert_eq!(mem::size_of_val(&fut),
40 );
}
#[ maybe_tokio_test]
async fn struct_size_3() {
let fut =
async {
let ready1 = future::ready(
0 i32);
let ready2 = future::ready(
0 i32);
let ready3 = future::ready(
0 i32);
tokio::select! {
_ = ready1 => {},
_ = ready2 => {},
_ = ready3 => {},
}
};
assert_eq!(mem::size_of_val(&fut),
48 );
}
}
#[ maybe_tokio_test]
async fn mutable_borrowing_future_with_same_borrow_in_block() {
let mut value =
234 ;
tokio::select! {
_ = require_mutable(&
mut value) => { },
_ = async_noop() => {
value +=
5 ;
},
}
assert!(value >=
234 );
}
#[ maybe_tokio_test]
async fn mutable_borrowing_future_with_same_borrow_in_block_and_else() {
let mut value =
234 ;
tokio::select! {
_ = require_mutable(&
mut value) => { },
_ = async_noop() => {
value +=
5 ;
},
else => {
value +=
27 ;
},
}
assert!(value >=
234 );
}
#[ maybe_tokio_test]
async fn future_panics_after_poll() {
use tokio_test::task;
let (tx, rx) = oneshot::channel();
let mut polled =
false ;
let f = poll_fn(|_| {
assert!(!polled);
polled =
true ;
Ready(None::<()>)
});
let mut f = task::spawn(
async {
tokio::select! {
Some(_) = f => unreachable!(),
ret = rx => ret.unwrap(),
}
});
assert_pending!(f.poll());
assert_pending!(f.poll());
assert_ok!(tx.send(
1 ));
let res = assert_ready!(f.poll());
assert_eq!(
1 , res);
}
#[ maybe_tokio_test]
async fn disable_with_if() {
use tokio_test::task;
let f = poll_fn(|_| panic!());
let (tx, rx) = oneshot::channel();
let mut f = task::spawn(
async {
tokio::select! {
_ = f,
if false => unreachable!(),
_ = rx => (),
}
});
assert_pending!(f.poll());
assert_ok!(tx.send(()));
assert!(f.is_woken());
assert_ready!(f.poll());
}
#[ maybe_tokio_test]
async fn join_with_select() {
use tokio_test::task;
let (tx1,
mut rx1) = oneshot::channel();
let (tx2,
mut rx2) = oneshot::channel();
let mut f = task::spawn(
async {
let mut a = None;
let mut b = None;
while a.is_none() || b.is_none() {
tokio::select! {
v1 = &
mut rx1,
if a.is_none() => a = Some(assert_ok!(v1)),
v2 = &
mut rx2,
if b.is_none() => b = Some(assert_ok!(v2))
}
}
(a.unwrap(), b.unwrap())
});
assert_pending!(f.poll());
assert_ok!(tx1.send(
123 ));
assert!(f.is_woken());
assert_pending!(f.poll());
assert_ok!(tx2.send(
456 ));
assert!(f.is_woken());
let (a, b) = assert_ready!(f.poll());
assert_eq!(a,
123 );
assert_eq!(b,
456 );
}
#[ tokio::test]
#[ cfg(feature =
"full" )]
async fn use_future_in_if_condition() {
use tokio::time::{
self , Duration};
tokio::select! {
_ = time::sleep(Duration::from_millis(
10 )),
if false => {
panic!(
"if condition ignored" )
}
_ =
async {
1 u32 } => {
}
}
}
#[ tokio::test]
#[ cfg(feature =
"full" )]
async fn use_future_in_if_condition_biased() {
use tokio::time::{
self , Duration};
tokio::select! {
biased;
_ = time::sleep(Duration::from_millis(
10 )),
if false => {
panic!(
"if condition ignored" )
}
_ =
async {
1 u32 } => {
}
}
}
#[ maybe_tokio_test]
async fn many_branches() {
let num = tokio::select! {
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
x =
async {
1 } => x,
};
assert_eq!(
1 , num);
}
#[ maybe_tokio_test]
async fn never_branch_no_warnings() {
let t = tokio::select! {
_ = async_never() =>
0 ,
one_async_ready = one() => one_async_ready,
};
assert_eq!(t,
1 );
}
async fn one() -> usize {
1
}
async fn require_mutable(_: &
mut i32) {}
async fn async_noop() {}
async fn async_never() -> ! {
futures::future::pending().
await
}
// From https://github.com/tokio-rs/tokio/issues/2857
#[ maybe_tokio_test]
async fn mut_on_left_hand_side() {
let v =
async move {
let ok =
async {
1 };
tokio::pin!(ok);
tokio::select! {
mut a = &
mut ok => {
a +=
1 ;
a
}
}
}
.
await ;
assert_eq!(v,
2 );
}
#[ maybe_tokio_test]
async fn biased_one_not_ready() {
let (_tx1, rx1) = oneshot::channel::<i32>();
let (tx2, rx2) = oneshot::channel::<i32>();
let (tx3, rx3) = oneshot::channel::<i32>();
tx2.send(
2 ).unwrap();
tx3.send(
3 ).unwrap();
let v = tokio::select! {
biased;
_ = rx1 => unreachable!(),
res = rx2 => {
assert_ok!(res)
},
_ = rx3 => {
panic!(
"This branch should never be activated because `rx2` should be polled before `rx3` due to `biased;`." )
}
};
assert_eq!(
2 , v);
}
#[ maybe_tokio_test]
#[ cfg(feature =
"full" )]
async fn biased_eventually_ready() {
use tokio::task::yield_now;
let one =
async {};
let two =
async { yield_now().
await };
let three =
async { yield_now().
await };
let mut count =
0 u8;
tokio::pin!(one, two, three);
loop {
tokio::select! {
biased;
_ = &
mut two,
if count <
2 => {
count +=
1 ;
assert_eq!(count,
2 );
}
_ = &
mut three,
if count <
3 => {
count +=
1 ;
assert_eq!(count,
3 );
}
_ = &
mut one,
if count <
1 => {
count +=
1 ;
assert_eq!(count,
1 );
}
else =>
break ,
}
}
assert_eq!(count,
3 );
}
// https://github.com/tokio-rs/tokio/issues/3830
// https://github.com/rust-lang/rust-clippy/issues/7304
#[ warn(clippy::default_numeric_fallback)]
pub async fn default_numeric_fallback() {
tokio::select! {
_ =
async {} => (),
else => (),
}
}
// https://github.com/tokio-rs/tokio/issues/4182
#[ maybe_tokio_test]
async fn mut_ref_patterns() {
tokio::select! {
Some(
mut foo) =
async { Some(
"1" .to_string()) } => {
assert_eq!(foo,
"1" );
foo =
"2" .to_string();
assert_eq!(foo,
"2" );
},
};
tokio::select! {
Some(
ref foo) =
async { Some(
"1" .to_string()) } => {
assert_eq!(*foo,
"1" );
},
};
tokio::select! {
Some(
ref mut foo) =
async { Some(
"1" .to_string()) } => {
assert_eq!(*foo,
"1" );
*foo =
"2" .to_string();
assert_eq!(*foo,
"2" );
},
};
}
#[ cfg(tokio_unstable)]
mod unstable {
use tokio::runtime::RngSeed;
#[ test]
fn deterministic_select_current_thread() {
let seed = b
"bytes used to generate seed" ;
let rt1 = tokio::runtime::Builder::new_current_thread()
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap();
let rt1_values = rt1.block_on(
async { (select_0_to_9().
await , select_0_to_9().
await ) })
;
let rt2 = tokio::runtime::Builder::new_current_thread()
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap();
let rt2_values = rt2.block_on(async { (select_0_to_9().await , select_0_to_9().await ) });
assert_eq!(rt1_values, rt2_values);
}
#[ test]
#[ cfg(all(feature = "rt-multi-thread" , not(target_os = "wasi" )))]
fn deterministic_select_multi_thread() {
let seed = b"bytes used to generate seed" ;
let rt1 = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1 )
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap();
let rt1_values = rt1.block_on(async {
let _ = tokio::spawn(async { (select_0_to_9().await , select_0_to_9().await ) }).await ;
});
let rt2 = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1 )
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap();
let rt2_values = rt2.block_on(async {
let _ = tokio::spawn(async { (select_0_to_9().await , select_0_to_9().await ) }).await ;
});
assert_eq!(rt1_values, rt2_values);
}
async fn select_0_to_9() -> u32 {
tokio::select!(
x = async { 0 } => x,
x = async { 1 } => x,
x = async { 2 } => x,
x = async { 3 } => x,
x = async { 4 } => x,
x = async { 5 } => x,
x = async { 6 } => x,
x = async { 7 } => x,
x = async { 8 } => x,
x = async { 9 } => x,
)
}
}
#[ tokio::test]
async fn select_into_future() {
struct NotAFuture;
impl std::future::IntoFuture for NotAFuture {
type Output = ();
type IntoFuture = std::future::Ready<()>;
fn into_future(self ) -> Self ::IntoFuture {
std::future::ready(())
}
}
tokio::select! {
() = NotAFuture => {},
}
}
// regression test for https://github.com/tokio-rs/tokio/issues/6721
#[ tokio::test]
async fn temporary_lifetime_extension() {
tokio::select! {
() = &mut std::future::ready(()) => {},
}
}
Messung V0.5 in Prozent C=80 H=87 G=83
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-19)
¤
*© Formatika GbR, Deutschland