//! Isolated one-slot waitset deadline and cancellation race model. //! See CONTRACT.md for the owner and timer-adapter boundary. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Token(u64); impl Token { pub const fn raw(self) -> u64 { self.0 } pub const fn from_raw(raw: u64) -> Self { Self(raw) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Access, Busy, Stale, NotDue, Late, Pending, Overflow } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Completion { Event, Timeout } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Phase { Waiting, DeadlinePending, Done(Completion) } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Entry { pub token: Token, pub deadline: u64, pub phase: Phase } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub generation: u64, pub entry: Option, pub timers: usize } pub struct DeadlineWait { owner: P, generation: u64, entry: Option, } impl DeadlineWait

{ pub const fn new(owner: P) -> Self { Self { owner, generation: 0, entry: None } } pub const fn with_generation_seed(owner: P, generation: u64) -> Self { Self { owner, generation, entry: None } } pub fn arm(&mut self, caller: P, deadline: u64) -> Result { if caller != self.owner { return Err(Error::Access); } if self.entry.is_some() { return Err(Error::Busy); } let generation = self.generation.checked_add(1).ok_or(Error::Overflow)?; let token = Token(generation); self.entry = Some(Entry { token, deadline, phase: Phase::Waiting }); self.generation = generation; Ok(token) } fn current(&self, token: Token) -> Result { self.entry.filter(|entry| entry.token == token).ok_or(Error::Stale) } pub fn timer(&mut self, token: Token, tick: u64) -> Result<(), Error> { let mut entry = self.current(token)?; if tick < entry.deadline { return Err(Error::NotDue); } match entry.phase { Phase::Waiting if tick == entry.deadline => { entry.phase = Phase::DeadlinePending; self.entry = Some(entry); Ok(()) } Phase::Waiting => { entry.phase = Phase::Done(Completion::Timeout); self.entry = Some(entry); Ok(()) } _ => Err(Error::Stale), } } pub fn event(&mut self, token: Token, tick: u64) -> Result<(), Error> { let mut entry = self.current(token)?; if tick > entry.deadline { return Err(Error::Late); } match entry.phase { Phase::Waiting => { entry.phase = Phase::Done(Completion::Event); self.entry = Some(entry); Ok(()) } Phase::DeadlinePending if tick == entry.deadline => { entry.phase = Phase::Done(Completion::Event); self.entry = Some(entry); Ok(()) } Phase::DeadlinePending => Err(Error::Late), Phase::Done(_) => Err(Error::Stale), } } pub fn close_tick(&mut self, token: Token, tick: u64) -> Result<(), Error> { let mut entry = self.current(token)?; if tick < entry.deadline { return Err(Error::NotDue); } if entry.phase != Phase::DeadlinePending { return Err(Error::Stale); } entry.phase = Phase::Done(Completion::Timeout); self.entry = Some(entry); Ok(()) } pub fn take(&mut self, caller: P, token: Token) -> Result { if caller != self.owner { return Err(Error::Access); } let entry = self.current(token)?; let Phase::Done(result) = entry.phase else { return Err(Error::Pending); }; self.entry = None; Ok(result) } pub fn snapshot(&self) -> Snapshot { Snapshot {generation: self.generation, entry: self.entry, timers: usize::from(self.entry.is_some_and(|entry| matches!(entry.phase, Phase::Waiting | Phase::DeadlinePending)))} } }