use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;
use super::error::RuntimeError;
use super::process::FlowId;
use super::sync_lock;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CapId(pub(crate) u64);
impl CapId {
#[inline]
pub fn as_u64(self) -> u64 {
self.0
}
}
impl std::fmt::Display for CapId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "cap#{}", self.0)
}
}
static NEXT_CAP_ID: AtomicU64 = AtomicU64::new(1);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CapRights(u8);
impl CapRights {
pub const SEND: CapRights = CapRights(0b01);
pub const ASK: CapRights = CapRights(0b10);
pub const SEND_ASK: CapRights = CapRights(0b11);
#[inline]
pub fn contains(self, other: CapRights) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub fn bits(self) -> u8 {
self.0
}
}
#[derive(Clone, Copy, Debug)]
pub struct CapEntry {
pub flow: FlowId,
pub rights: CapRights,
}
pub struct CapTable {
inner: Mutex<HashMap<CapId, CapEntry>>,
}
impl CapTable {
pub fn new() -> Self {
Self {
inner: Mutex::new(HashMap::new()),
}
}
pub fn mint(&self, flow: FlowId, rights: CapRights) -> Result<CapId, RuntimeError> {
let id = CapId(NEXT_CAP_ID.fetch_add(1, Ordering::Relaxed));
sync_lock::lock(&self.inner, "CapTable::mint")?.insert(
id,
CapEntry { flow, rights },
);
Ok(id)
}
pub fn resolve(&self, id: CapId) -> Result<Option<CapEntry>, RuntimeError> {
Ok(sync_lock::lock(&self.inner, "CapTable::resolve")?
.get(&id)
.copied())
}
pub fn revoke_target(&self, flow: FlowId) -> Result<(), RuntimeError> {
let mut g = sync_lock::lock(&self.inner, "CapTable::revoke_target")?;
g.retain(|_, e| e.flow != flow);
Ok(())
}
}
impl Default for CapTable {
fn default() -> Self {
Self::new()
}
}