#![no_std] //! One foreground process owner retained until a successful wait. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Pid(pub u64); #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Outcome { Exited(i32), Fault(u64) } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Cause { Busy, Injected, Stale } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { AlreadyRunning, NoForeground, Spawn(Cause), Wait(Cause), InvalidPid } pub trait Adapter { /// A failed spawn must not publish a child owned by this coordinator. fn spawn(&mut self) -> Result; /// A failed wait must leave the child owned and retriable. fn wait(&mut self, pid: Pid) -> Result; } #[must_use] pub struct Foreground { pid: Option } impl Default for Foreground { fn default() -> Self { Self::new() } } impl Foreground { pub const fn new() -> Self { Self { pid: None } } pub const fn owner(&self) -> Option { self.pid } pub fn launch(&mut self, adapter: &mut A) -> Result { if self.pid.is_some() { return Err(Error::AlreadyRunning); } let pid = adapter.spawn().map_err(Error::Spawn)?; if pid.0 == 0 { return Err(Error::InvalidPid); } self.pid = Some(pid); Ok(pid) } pub fn collect(&mut self, adapter: &mut A) -> Result { let pid = self.pid.ok_or(Error::NoForeground)?; let outcome = adapter.wait(pid).map_err(Error::Wait)?; self.pid = None; Ok(outcome) } }