//! Shared open-description offset and in-flight read lifetime. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { BadFd, NoSpace, Busy, Overflow, Stale } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ReadLease { id: u64 } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Description { pub offset: u64, pub open_fds: u8, pub in_flight: u8, pub live: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct FdTable { fds: [Option; 2], next_fd: u64, next_lease: u64, active_lease: Option, description: Description, } impl FdTable { pub const fn new() -> Self { Self { fds: [Some(1), None], next_fd: 2, next_lease: 1, active_lease: None, description: Description { offset: 0, open_fds: 1, in_flight: 0, live: true } } } pub const fn description(&self) -> Description { self.description } pub fn offset(&self, fd: u64) -> Result { if !self.description.live || !self.fds.contains(&Some(fd)) { return Err(Error::BadFd); } Ok(self.description.offset) } pub fn dup(&mut self, fd: u64) -> Result { if !self.description.live || !self.fds.contains(&Some(fd)) { return Err(Error::BadFd); } let slot = self.fds.iter().position(Option::is_none).ok_or(Error::NoSpace)?; let next_fd = self.next_fd.checked_add(1).ok_or(Error::Overflow)?; let refs = self.description.open_fds.checked_add(1).ok_or(Error::Overflow)?; let duplicate = self.next_fd; self.fds[slot] = Some(duplicate); self.next_fd = next_fd; self.description.open_fds = refs; Ok(duplicate) } pub fn begin_read(&mut self, fd: u64) -> Result { if !self.description.live || !self.fds.contains(&Some(fd)) { return Err(Error::BadFd); } if self.active_lease.is_some() { return Err(Error::Busy); } let next = self.next_lease.checked_add(1).ok_or(Error::Overflow)?; let id = self.next_lease; self.next_lease = next; self.active_lease = Some(id); self.description.in_flight = 1; Ok(ReadLease { id }) } pub fn finish_read(&mut self, lease: ReadLease, actual: u64) -> Result { if !self.description.live || self.active_lease != Some(lease.id) || self.description.in_flight != 1 { return Err(Error::Stale); } let next = self.description.offset.checked_add(actual) .ok_or(Error::Overflow)?; self.description.offset = next; self.description.in_flight = 0; self.active_lease = None; if self.description.open_fds == 0 { self.description.live = false; } Ok(next) } pub fn close(&mut self, fd: u64) -> Result<(), Error> { let slot = self.fds.iter().position(|entry| *entry == Some(fd)) .ok_or(Error::BadFd)?; if !self.description.live || self.description.open_fds == 0 { return Err(Error::Stale); } self.fds[slot] = None; self.description.open_fds -= 1; if self.description.open_fds == 0 { self.description.live = false; } Ok(()) } }