use std::thread;
use futures::Future;
use tokio::runtime::Handle;
use super::wait;
pub async fn with_thread<
T: Send + 'static,
TFuture: Future<Output = T> + Send + 'static,
>(
original_future: TFuture,
) -> T {
let tokio_handle = Handle::try_current()
.expect("Needs running Tokio runtime.");
let other_thread = thread::spawn(move || {
let _guard = tokio_handle.enter();
return tokio_handle.block_on(original_future);
});
while !other_thread.is_finished() {
wait(5).await;
continue;
}
return other_thread
.join().unwrap();
}
#[cfg(test)]
mod tests {
use std::{thread, pin::Pin, time::Duration};
use futures::{future, Future};
use cs_utils::futures::{wait, with_thread};
#[tokio::test]
async fn run_blocking_future_on_separate_thread() {
static mut NORMAL_FUTURE_RUN_COUNTER: u64 = 0;
let block_for_ms: u64 = 1000;
let run_each_ms: u64 = 100;
let blocking_future = async move {
thread::sleep(Duration::from_millis(block_for_ms));
};
let normal_future = async move {
loop {
wait(run_each_ms).await;
unsafe {
NORMAL_FUTURE_RUN_COUNTER += 1;
}
}
};
let futures: Vec<Pin<Box<dyn Future<Output = ()>>>> = vec![
Box::pin(with_thread(blocking_future)),
Box::pin(normal_future),
];
future::select_all(futures).await;
let expected_run_count = block_for_ms / run_each_ms;
let run_delta = expected_run_count - unsafe { NORMAL_FUTURE_RUN_COUNTER };
assert!(
run_delta <= 3,
"Must run normal future multiple times.",
);
}
#[tokio::test]
async fn shares_runtime() {
static mut NORMAL_FUTURE_RUN_COUNTER: u64 = 0;
let block_for_ms: u64 = 1000;
let run_each_ms: u64 = 100;
let blocking_future = async move {
thread::sleep(Duration::from_millis(block_for_ms));
};
let normal_future = async move {
loop {
wait(run_each_ms).await;
unsafe {
NORMAL_FUTURE_RUN_COUNTER += 1;
}
}
};
let futures: Vec<Pin<Box<dyn Future<Output = ()>>>> = vec![
Box::pin(with_thread(blocking_future)),
Box::pin(
with_thread(normal_future),
),
];
future::select_all(futures).await;
let expected_run_count = block_for_ms / run_each_ms;
let run_delta = expected_run_count - unsafe { NORMAL_FUTURE_RUN_COUNTER };
assert!(
run_delta <= 3,
"Must run normal future multiple times.",
);
}
#[tokio::test]
async fn runs_nested_blocking_futures() {
static mut NORMAL_FUTURE_RUN_COUNTER: u64 = 0;
let block_for_ms: u64 = 1000;
let run_each_ms: u64 = 100;
let blocking_future = async move {
let fut = async move {
thread::sleep(Duration::from_millis(block_for_ms));
};
fut.await;
};
let normal_future = async move {
loop {
wait(run_each_ms).await;
unsafe {
NORMAL_FUTURE_RUN_COUNTER += 1;
}
}
};
let futures: Vec<Pin<Box<dyn Future<Output = ()>>>> = vec![
Box::pin(with_thread(blocking_future)),
Box::pin(normal_future),
];
future::select_all(futures).await;
let expected_run_count = block_for_ms / run_each_ms;
let run_delta = expected_run_count - unsafe { NORMAL_FUTURE_RUN_COUNTER };
assert!(
run_delta <= 3,
"Must run normal future multiple times.",
);
}
#[tokio::test]
async fn runs_nested_futures() {
static mut NORMAL_FUTURE_RUN_COUNTER: u64 = 0;
let block_for_ms: u64 = 1000;
let run_each_ms: u64 = 100;
let blocking_future = async move {
let fut = async move {
thread::sleep(Duration::from_millis(block_for_ms));
};
fut.await;
};
let normal_future = async move {
loop {
wait(run_each_ms).await;
unsafe {
NORMAL_FUTURE_RUN_COUNTER += 1;
}
}
};
let futures: Vec<Pin<Box<dyn Future<Output = ()>>>> = vec![
Box::pin(
with_thread(
with_thread(blocking_future),
),
),
Box::pin(
with_thread(
with_thread(
with_thread(normal_future),
),
),
),
];
future::select_all(futures).await;
let expected_run_count = block_for_ms / run_each_ms;
let run_delta = expected_run_count - unsafe { NORMAL_FUTURE_RUN_COUNTER };
assert!(
run_delta <= 3,
"Must run normal future multiple times.",
);
}
}