//! Two-frame shared object reference and mapping lifetime model. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Access, Invalid, Busy, Stale } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Snapshot { pub frames: [u64; 2], pub contents: [u8; 2], pub recipient: Option

, pub owner_handle: bool, pub recipient_handle: bool, pub owner_maps: [bool; 2], pub recipient_maps: [bool; 2], pub backing_live: bool, pub free_count: u32, } pub struct Lifetime { owner: P, state: Snapshot

, } impl Lifetime

{ pub fn new(owner: P, frames: [u64; 2]) -> Result { if frames[0] == 0 || frames[1] == 0 || frames[0] == frames[1] { return Err(Error::Invalid); } Ok(Self { owner, state: Snapshot { frames, contents: [0; 2], recipient: None, owner_handle: true, recipient_handle: false, owner_maps: [false; 2], recipient_maps: [false; 2], backing_live: true, free_count: 0, }}) } pub fn snapshot(&self) -> Snapshot

{ self.state } fn maybe_free(&mut self) { if self.state.backing_live && !self.state.owner_handle && !self.state.recipient_handle && !self.state.owner_maps.into_iter().any(|mapped| mapped) && !self.state.recipient_maps.into_iter().any(|mapped| mapped) { self.state.backing_live = false; self.state.free_count += 1; } } pub fn grant(&mut self, caller: P, recipient: P) -> Result<(), Error> { if !self.state.backing_live { return Err(Error::Stale); } if caller != self.owner || !self.state.owner_handle { return Err(Error::Access); } if recipient == self.owner { return Err(Error::Invalid); } if self.state.recipient.is_some() { return Err(Error::Busy); } self.state.recipient = Some(recipient); self.state.recipient_handle = true; Ok(()) } pub fn map(&mut self, caller: P, page: usize) -> Result { if !self.state.backing_live { return Err(Error::Stale); } let frame = *self.state.frames.get(page).ok_or(Error::Invalid)?; let maps = if caller == self.owner && self.state.owner_handle { &mut self.state.owner_maps } else if self.state.recipient == Some(caller) && self.state.recipient_handle { &mut self.state.recipient_maps } else { return Err(Error::Access); }; if maps[page] { return Err(Error::Busy); } maps[page] = true; Ok(frame) } pub fn write(&mut self, caller: P, page: usize, byte: u8) -> Result<(), Error> { if !self.state.backing_live { return Err(Error::Stale); } if page >= 2 { return Err(Error::Invalid); } if caller == self.owner && self.state.owner_maps[page] || self.state.recipient == Some(caller) && self.state.recipient_maps[page] { self.state.contents[page] = byte; Ok(()) } else { Err(Error::Access) } } pub fn read(&self, caller: P, page: usize) -> Result { if !self.state.backing_live { return Err(Error::Stale); } if page >= 2 { return Err(Error::Invalid); } if caller == self.owner && self.state.owner_maps[page] || self.state.recipient == Some(caller) && self.state.recipient_maps[page] { Ok(self.state.contents[page]) } else { Err(Error::Access) } } pub fn close_handle(&mut self, caller: P) -> Result<(), Error> { if !self.state.backing_live { return Err(Error::Stale); } let handle = if caller == self.owner { &mut self.state.owner_handle } else if self.state.recipient == Some(caller) { &mut self.state.recipient_handle } else { return Err(Error::Access); }; if !*handle { return Err(Error::Stale); } *handle = false; self.maybe_free(); Ok(()) } pub fn unmap(&mut self, caller: P, page: usize) -> Result<(), Error> { if !self.state.backing_live { return Err(Error::Stale); } if page >= 2 { return Err(Error::Invalid); } let maps = if caller == self.owner { &mut self.state.owner_maps } else if self.state.recipient == Some(caller) { &mut self.state.recipient_maps } else { return Err(Error::Access); }; if !maps[page] { return Err(Error::Invalid); } maps[page] = false; self.maybe_free(); Ok(()) } pub fn free_backing(&mut self, caller: P) -> Result<(), Error> { if !self.state.backing_live { return Err(Error::Stale); } if caller != self.owner { return Err(Error::Access); } if self.state.owner_handle || self.state.recipient_handle || self.state.owner_maps.into_iter().any(|mapped| mapped) || self.state.recipient_maps.into_iter().any(|mapped| mapped) { return Err(Error::Busy); } self.maybe_free(); Ok(()) } }