use core::{
cmp::Ordering::*,
fmt::Display,
future::Future,
ops::Add,
pin::Pin,
task::{Context, Poll},
};
use crate::{config::Config, error::CausalityError, fsm::*};
use super::Sim;
pub(super) struct TryAdvanceTo<'s, C: ?Sized + Config> {
sim: Option<&'s Sim<C>>,
when: C::Time,
}
impl<'s, C: ?Sized + Config> TryAdvanceTo<'s, C> {
pub(super) const fn new(sim: &'s Sim<C>, when: C::Time) -> Self {
TryAdvanceTo {
sim: Some(sim),
when,
}
}
pub(super) const fn unwrap(self) -> Unwrap<Self> {
Unwrap(self)
}
}
impl<C: ?Sized + Config> Future for TryAdvanceTo<'_, C> {
type Output = Result<(), CausalityError<C::Time>>;
#[inline]
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(sim) = self.sim.take() {
advance_impl(sim, sim.now(), self.when)
} else {
Poll::Ready(Ok(()))
}
}
}
pub(super) struct TryAdvance<'s, C: ?Sized + Config> {
sim: Option<&'s Sim<C>>,
dt: C::Time,
}
impl<'s, C: ?Sized + Config> TryAdvance<'s, C> {
pub(super) const fn new(sim: &'s Sim<C>, dt: C::Time) -> Self {
TryAdvance { sim: Some(sim), dt }
}
pub(super) const fn unwrap(self) -> Unwrap<Self> {
Unwrap(self)
}
}
impl<C: ?Sized + Config> Future for TryAdvance<'_, C>
where
C::Time: Add<Output = C::Time>,
{
type Output = Result<(), CausalityError<C::Time>>;
#[inline]
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(sim) = self.sim.take() {
advance_impl(sim, sim.now(), sim.now() + self.dt)
} else {
Poll::Ready(Ok(()))
}
}
}
pub(super) struct Defer<'s, C: ?Sized + Config> {
sim: Option<&'s Sim<C>>,
}
impl<'s, C: ?Sized + Config> Defer<'s, C> {
pub(super) const fn new(sim: &'s Sim<C>) -> Self {
Defer { sim: Some(sim) }
}
}
impl<C: ?Sized + Config> Future for Defer<'_, C> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.sim.take() {
Some(sim) => {
if let Some(active) = sim.active.take() {
active.into_inner().brand(|active, once| {
let busy = active
.token(once)
.into_busy()
.expect("active continuation should be in state 'Busy'");
sim.calendar().defer(active.clone(), busy);
});
}
Poll::Pending
}
None => Poll::Ready(()),
}
}
}
#[must_use = "Futures must be awaited in order to execute them"]
#[pin_project::pin_project]
pub(super) struct Unwrap<F: ?Sized>(#[pin] F);
impl<T, E: Display, F: ?Sized + Future<Output = Result<T, E>>> Future for Unwrap<F> {
type Output = T;
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.project().0.poll(cx) {
Poll::Ready(Ok(res)) => Poll::Ready(res),
Poll::Ready(Err(err)) => panic!("{}", err),
Poll::Pending => Poll::Pending,
}
}
}
fn advance_impl<C: ?Sized + Config>(
sim: &Sim<C>,
now: C::Time,
when: C::Time,
) -> Poll<Result<(), CausalityError<C::Time>>> {
match when.partial_cmp(&now) {
None | Some(Less) => Poll::Ready(Err(CausalityError {
cause: now,
effect: when,
})),
Some(ord) => {
let calendar = sim.calendar();
let task = sim
.active
.take()
.expect("no active continuation")
.into_inner();
task.brand(|task, once| {
let busy = task
.token(once)
.into_busy()
.expect("active continuation should be in state 'Busy'");
let idle = task.state().transition(busy, ());
if ord == Greater {
calendar.schedule(task.clone(), idle, when);
} else {
calendar.activate(task.clone(), idle);
}
});
Poll::Pending
}
}
}