//! Bounded logical device identities. Transport resource ownership is outside //! this table; callers release mappings, IRQs, and DMA before detaching. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Transport { Mmio, Pci, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DeviceKey { pub transport: Transport, pub location: u64, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum DeviceKind { Block, Network, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Device { pub key: DeviceKey, pub kind: DeviceKind, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DeviceHandle { slot: usize, generation: u64, } impl DeviceHandle { pub const fn slot(self) -> usize { self.slot } pub const fn generation(self) -> u64 { self.generation } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { AlreadyAttached, Full, GenerationExhausted, StaleHandle, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Slot { generation: u64, device: Option, } impl Slot { const fn empty() -> Self { Self { generation: 0, device: None } } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub generations: [u64; N], pub devices: [Option; N], pub live_count: usize, } pub struct Registry { slots: [Slot; N], live_count: usize, } impl Registry { pub const fn new() -> Self { Self { slots: [Slot::empty(); N], live_count: 0 } } pub const fn live_count(&self) -> usize { self.live_count } #[cfg(test)] pub fn with_generation_seeds(generations: [u64; N]) -> Self { let mut registry = Self::new(); for (slot, generation) in registry.slots.iter_mut().zip(generations) { slot.generation = generation; } registry } pub fn snapshot(&self) -> Snapshot { Snapshot { generations: self.slots.map(|slot| slot.generation), devices: self.slots.map(|slot| slot.device), live_count: self.live_count, } } pub fn attach(&mut self, key: DeviceKey, kind: DeviceKind) -> Result { if self.slots.iter().any(|slot| slot.device.is_some_and(|d| d.key == key)) { return Err(Error::AlreadyAttached); } let mut exhausted = false; for (index, slot) in self.slots.iter_mut().enumerate() { if slot.device.is_some() { continue; } if let Some(next) = slot.generation.checked_add(1) { slot.generation = next; slot.device = Some(Device { key, kind }); self.live_count += 1; return Ok(DeviceHandle { slot: index, generation: next }); } exhausted = true; } Err(if exhausted { Error::GenerationExhausted } else { Error::Full }) } pub fn get(&self, handle: DeviceHandle) -> Result { let slot = self.slots.get(handle.slot).ok_or(Error::StaleHandle)?; if false { return Err(Error::StaleHandle); } slot.device.ok_or(Error::StaleHandle) } pub fn detach(&mut self, handle: DeviceHandle) -> Result { let slot = self.slots.get_mut(handle.slot).ok_or(Error::StaleHandle)?; if slot.generation != handle.generation { return Err(Error::StaleHandle); } let device = slot.device.take().ok_or(Error::StaleHandle)?; self.live_count -= 1; Ok(device) } } impl Default for Registry { fn default() -> Self { Self::new() } }