//! Isolated fixed-capacity waitset close and peer-death race model. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Kind { File, Channel, Task } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ObjectKey { pub kind: Kind, pub id: u64 } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct SubscriptionId(u64); impl SubscriptionId { pub const fn from_raw(raw: u64) -> Self { Self(raw) } pub const fn raw(self) -> u64 { self.0 } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Access, Closed, Stale, Exists, Full, Invalid, Overflow } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Row { pub id: SubscriptionId, pub object: ObjectKey, pub peer_dead: bool } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Callback { pub id: SubscriptionId, pub close_epoch: u32 } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub close_epoch: u32, pub closed: bool, pub rows: [Option; N], pub resources: usize, } pub struct Teardown { owner: P, close_epoch: u32, next_generation: u32, closed: bool, rows: [Option; N], } impl Teardown { pub const fn new(owner: P) -> Self { Self {owner, close_epoch: 0, next_generation: 0, closed: false, rows: [None; N]} } pub fn subscribe(&mut self, caller: P, object: ObjectKey) -> Result { if caller != self.owner { return Err(Error::Access); } if self.closed { return Err(Error::Closed); } if object.id == 0 { return Err(Error::Invalid); } if self.rows.iter().flatten().any(|row| row.object == object) { return Err(Error::Exists); } let slot = self.rows.iter().position(Option::is_none).ok_or(Error::Full)?; let slot_id = u32::try_from(slot).ok().and_then(|value| value.checked_add(1)).ok_or(Error::Overflow)?; let generation = self.next_generation.checked_add(1).ok_or(Error::Overflow)?; let id = SubscriptionId((u64::from(generation) << 32) | u64::from(slot_id)); self.rows[slot] = Some(Row {id, object, peer_dead: false}); self.next_generation = generation; Ok(id) } fn index(&self, id: SubscriptionId) -> Result { if self.closed { return Err(Error::Closed); } self.rows.iter().position(|row| row.is_some_and(|row| row.id == id)) .ok_or(Error::Stale) } pub fn begin_peer_callback(&self, id: SubscriptionId) -> Result { self.index(id)?; Ok(Callback {id, close_epoch: self.close_epoch}) } pub fn finish_peer_callback(&mut self, callback: Callback) -> Result<(), Error> { if self.closed || callback.close_epoch != self.close_epoch { return Err(Error::Closed); } let slot = self.index(callback.id)?; let mut row = self.rows[slot].ok_or(Error::Stale)?; row.peer_dead = true; self.rows[slot] = Some(row); Ok(()) } pub fn close(&mut self, caller: P) -> Result { if caller != self.owner { return Err(Error::Access); } if self.closed { return Err(Error::Closed); } let epoch = self.close_epoch.checked_add(1).ok_or(Error::Overflow)?; let released = self.rows.iter().flatten().count(); self.rows = [None; N]; self.close_epoch = epoch; self.closed = true; Ok(released) } pub fn snapshot(&self) -> Snapshot { Snapshot {close_epoch: self.close_epoch, closed: self.closed, rows: self.rows, resources: self.rows.iter().flatten().count()} } }