mod ordering;
mod v5;
use core::{
cell::{Cell, RefCell},
fmt,
ops::Deref,
};
use crate::{
config::{Config, Time},
continuation::{Continuation, token},
fsm::*,
ptr::Irc,
simulator::Mark,
};
pub type DefaultPlan<C> = v5::Calendar<C>;
pub use ordering::Partition;
pub unsafe trait Scheduler {
type Config: ?Sized + Config;
type State: PlanState<Time = <Self::Config as Config>::Time>;
fn new(config: &Self::Config) -> Self;
fn update_rank(
&mut self,
mark: Mark,
rank: &Cell<<Self::Config as Config>::Rank>,
new_rank: <Self::Config as Config>::Rank,
);
fn schedule<'brand>(
&mut self,
cont: Irc<Continuation<'brand, Self::Config>>,
idle: token::Idle<'brand>,
time: <Self::Config as Config>::Time,
) -> token::Next<'brand>;
fn defer<'brand>(
&mut self,
cont: Irc<Continuation<'brand, Self::Config>>,
busy: token::Busy<'brand>,
now: <Self::Config as Config>::Time,
) -> token::Next<'brand>;
fn activate<'brand>(
&mut self,
cont: Irc<Continuation<'brand, Self::Config>>,
idle: token::Idle<'brand>,
now: <Self::Config as Config>::Time,
) -> token::Next<'brand>;
fn remove<'brand>(
&mut self,
cont: &Continuation<'brand, Self::Config>,
next: token::Next<'brand>,
now: <Self::Config as Config>::Time,
) -> token::Idle<'brand>;
fn extract(&mut self) -> Option<ContTimePair<Self::Config>>;
}
pub struct ContTimePair<C: ?Sized + Config> {
pub cont: Irc<Continuation<'static, C>>,
pub time: C::Time,
}
pub trait PlanState: fmt::Debug {
type Time: Time;
fn time(&self) -> Self::Time;
}
pub struct Calendar<C: ?Sized + Config> {
plan: RefCell<C::Plan>,
now: Cell<C::Time>,
}
impl<C: ?Sized + Config> Calendar<C> {
pub(crate) fn new(config: &C) -> Self {
Calendar {
plan: RefCell::new(C::Plan::new(config)),
now: Cell::new(config.default_time()),
}
}
pub fn update_rank(&self, mark: Mark, rank: &Cell<C::Rank>, new_rank: C::Rank) {
self.plan.borrow_mut().update_rank(mark, rank, new_rank);
}
pub fn schedule<'brand>(
&self,
cont: Irc<Continuation<'brand, C>>,
idle: token::Idle<'brand>,
time: C::Time,
) -> token::Next<'brand> {
let _span = cont.enter_span();
self.plan.borrow_mut().schedule(cont.clone(), idle, time)
}
pub fn defer<'brand>(
&self,
cont: Irc<Continuation<'brand, C>>,
busy: token::Busy<'brand>,
) -> token::Next<'brand> {
self.plan.borrow_mut().defer(cont, busy, self.now())
}
pub fn activate<'brand>(
&self,
cont: Irc<Continuation<'brand, C>>,
idle: token::Idle<'brand>,
) -> token::Next<'brand> {
let _span = cont.enter_span();
self.plan
.borrow_mut()
.activate(cont.clone(), idle, self.now())
}
pub fn remove<'brand>(
&self,
cont: &Continuation<'brand, C>,
next: token::Next<'brand>,
) -> token::Idle<'brand> {
let _span = cont.enter_span();
self.plan.borrow_mut().remove(cont, next, self.now())
}
pub fn extract(&self) -> Option<Irc<Continuation<'static, C>>> {
let mut plan = self.plan.borrow_mut();
let ContTimePair { cont, time } = plan.extract()?;
self.now.set(time);
Some(cont)
}
pub fn now(&self) -> C::Time {
self.now.get()
}
}
impl<C: ?Sized + Config> fmt::Debug for Calendar<C>
where
C::Plan: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Calendar")
.field("now", &self.now.get())
.field("plan", &self.plan.borrow())
.finish()
}
}
#[repr(transparent)]
pub struct IdleOnDrop<C: ?Sized + Config>(Irc<Continuation<'static, C>>);
impl<C: ?Sized + Config> IdleOnDrop<C> {
pub fn new<'brand>(task: Irc<Continuation<'brand, C>>, next: &token::Next<'brand>) -> Self {
let _ = next;
unsafe {
task.enter();
}
Self(Irc::map(task, Continuation::detach))
}
pub fn into_inner(self) -> Irc<Continuation<'static, C>> {
let this = core::mem::ManuallyDrop::new(self);
unsafe {
this.0.leave();
}
let ptr = &this.0 as *const Irc<Continuation<'static, C>>;
unsafe { ptr.read() }
}
pub fn brand<F, R>(&self, f: F) -> R
where
F: for<'b> FnOnce(&Continuation<'b, C>, &token::Next<'b>) -> R,
{
(*self.0).brand(|inner, once| {
let next = match inner.token(once).into_next() {
Ok(next) => next,
#[cfg(debug_assertions)]
Err(err) => panic!("{}", err),
#[cfg(not(debug_assertions))]
_ => unsafe { core::hint::unreachable_unchecked() },
};
f(inner, &next)
})
}
}
impl<C: ?Sized + Config> Deref for IdleOnDrop<C> {
type Target = Irc<Continuation<'static, C>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<C: ?Sized + Config> From<Irc<Continuation<'_, C>>> for IdleOnDrop<C> {
fn from(task: Irc<Continuation<'_, C>>) -> Self {
task.brand(move |task, once| {
let next = match task.token(once).into_next() {
Ok(next) => next,
#[cfg(debug_assertions)]
Err(err) => panic!("{}", err),
#[cfg(not(debug_assertions))]
_ => unsafe { core::hint::unreachable_unchecked() },
};
Self::new(task.clone(), &next)
})
}
}
impl<C: ?Sized + Config> From<IdleOnDrop<C>> for Irc<Continuation<'static, C>> {
fn from(guard: IdleOnDrop<C>) -> Self {
guard.into_inner()
}
}
impl<C: ?Sized + Config> Drop for IdleOnDrop<C> {
fn drop(&mut self) {
unsafe {
self.0.leave();
}
(*self.0).brand(move |task, once| {
let next = match task.token(once).into_next() {
Ok(next) => next,
#[cfg(debug_assertions)]
Err(err) => panic!("{}", err),
#[cfg(not(debug_assertions))]
_ => unsafe { core::hint::unreachable_unchecked() },
};
let _: token::Idle<'_> = task.state().transition(next, ());
});
}
}
#[cfg(test)]
mod tests;