#![cfg(unix)]
use super::super::real::RealSystem;
use super::Concurrent;
use super::RunLoop;
use super::Select as _;
use futures_util::poll;
use std::pin::pin;
impl Concurrent<RealSystem> {
pub fn run_real<F, T>(&self, task: F) -> T
where
F: Future<Output = T>,
{
use std::task::Poll::{Pending, Ready};
use std::task::{Context, Waker};
let runner = pin!(async move {
let mut task = pin!(task);
loop {
if let Ready(result) = poll!(&mut task) {
return result;
}
self.select().await;
}
});
match runner.poll(&mut Context::from_waker(Waker::noop())) {
Ready(result) => result,
Pending => unreachable!("`RealSystem::select` should never return `Pending`"),
}
}
}
impl RunLoop for RealSystem {
#[inline(always)]
async fn run_loop<F>(concurrent: &Concurrent<Self>, task: F)
where
F: Future<Output = ()>,
{
concurrent.run_real(task)
}
}
#[cfg(test)]
mod tests {
use super::super::Sleep as _;
use super::*;
use std::cell::Cell;
use std::time::Duration;
#[test]
fn run_real_returns_task_output_immediately_if_ready_on_first_poll() {
let system = Concurrent::new(unsafe { RealSystem::new() });
let result = system.run_real(async { 42 });
assert_eq!(result, 42);
}
#[test]
fn run_real_keeps_polling_task_until_completion_when_task_yields_multiple_times() {
let system = Concurrent::new(unsafe { RealSystem::new() });
let progress = Cell::new(0);
let result = system.run_real(async {
progress.set(1);
system.sleep(Duration::from_millis(1)).await;
progress.set(2);
system.sleep(Duration::from_millis(1)).await;
progress.set(3);
42
});
assert_eq!(result, 42);
assert_eq!(progress.get(), 3);
}
#[test]
fn run_real_calls_select_between_task_polls_while_task_is_pending() {
let system = Concurrent::new(unsafe { RealSystem::new() });
let progress = Cell::new(0);
let result = system.run_real(async {
progress.set(1);
system.sleep(Duration::from_millis(1)).await;
progress.set(2);
7
});
assert_eq!(result, 7);
assert_eq!(progress.get(), 2);
}
#[test]
#[should_panic = "boom"]
fn run_real_propagates_task_panic_to_caller() {
let system = Concurrent::new(unsafe { RealSystem::new() });
system.run_real(async { panic!("boom") })
}
}