use crate::{fib, thr::prelude::*};
use core::{
fmt::Display,
future::Future,
pin::Pin,
task::{Context, Poll, Waker},
};
pub trait ThrExec: ThrToken {
fn wakeup(self);
fn waker(self) -> Waker;
#[inline]
fn exec<F, O>(self, fut: F)
where
F: Future<Output = O> + Send + 'static,
O: ExecOutput,
{
self.exec_factory(|| fut);
}
#[inline]
fn exec_factory<C, F, O>(self, factory: C)
where
C: FnOnce() -> F + Send + 'static,
F: Future<Output = O> + 'static,
O: ExecOutput,
{
self.add_exec_factory(factory);
self.wakeup();
}
#[inline]
fn add_exec<F, O>(self, fut: F)
where
F: Future<Output = O> + Send + 'static,
O: ExecOutput,
{
self.add_exec_factory(|| fut);
}
#[inline]
fn add_exec_factory<C, F, O>(self, factory: C)
where
C: FnOnce() -> F + Send + 'static,
F: Future<Output = O> + 'static,
O: ExecOutput,
{
fn poll<T: ThrExec, F: Future>(thr: T, fut: Pin<&mut F>) -> Poll<F::Output> {
let waker = thr.waker();
let mut cx = Context::from_waker(&waker);
fut.poll(&mut cx)
}
self.add_fn_factory(move || {
let mut fut = factory();
move || match poll(self, unsafe { Pin::new_unchecked(&mut fut) }) {
Poll::Pending => fib::Yielded(()),
Poll::Ready(output) => {
output.terminate();
fib::Complete(())
}
}
});
}
}
pub trait ExecOutput: Sized + Send {
type Terminate;
fn terminate(self) -> Self::Terminate;
}
impl ExecOutput for () {
type Terminate = ();
#[inline]
fn terminate(self) {}
}
impl<E: Send + Display> ExecOutput for Result<(), E> {
type Terminate = ();
#[inline]
fn terminate(self) {
match self {
Ok(()) => {}
Err(err) => terminate_err(err),
}
}
}
impl ExecOutput for ! {
type Terminate = !;
#[inline]
fn terminate(self) -> ! {
match self {}
}
}
impl<E: Send + Display> ExecOutput for Result<!, E> {
type Terminate = !;
#[inline]
fn terminate(self) -> ! {
let Err(err) = self;
terminate_err(err);
}
}
fn terminate_err<E: Display>(err: E) -> ! {
panic!("root future error: {}", err);
}