//! 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() }
}