//! Process identity is minted from a kernel owned process ID. //! User requests may inspect an assigned identity, but cannot replace it. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Principal(u64); impl Principal { pub const fn id(self) -> u64 { self.0 } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Full, Duplicate, Unknown, Access, Exhausted, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Binding

{ process: P, principal: Principal, } pub struct Registry { next: u64, bindings: [Option>; N], } impl Registry { pub fn new() -> Self { Self { next: 1, bindings: [None; N] } } /// Called only after the kernel has obtained a genuine ProcessId. pub fn bind_kernel(&mut self, process: P) -> Result { if self.bindings.iter().flatten().any(|row| row.process == process) { return Err(Error::Duplicate); } let slot = self.bindings.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let following = self.next.checked_add(1).ok_or(Error::Exhausted)?; let principal = Principal(self.next); *slot = Some(Binding { process, principal }); self.next = following; Ok(principal) } pub fn principal(&self, process: P) -> Result { self.bindings.iter().flatten() .find(|row| row.process == process) .map(|row| row.principal).ok_or(Error::Unknown) } /// The syscall path always returns an explicit denial for a live process. /// `requested` is deliberately never used to construct a Principal. pub fn request_user_change(&self, process: P, _requested: u64) -> Result<(), Error> { self.principal(process)?; Err(Error::Access) } pub fn retire_kernel(&mut self, process: P) -> Result<(), Error> { let slot = self.bindings.iter_mut() .find(|slot| slot.is_some_and(|row| row.process == process)) .ok_or(Error::Unknown)?; *slot = None; Ok(()) } pub fn snapshot(&self) -> (u64, [Option<(P, u64)>; N]) { (self.next, self.bindings.map(|row| row.map(|row| (row.process, row.principal.id())))) } } impl Default for Registry { fn default() -> Self { Self::new() } }