use std::collections::BTreeMap;
#[derive(Debug, Clone)]
pub enum Fd {
Stdin,
Stdout,
Stderr,
File {
path: String,
offset: u64,
},
Dir {
path: String,
pos: usize,
},
PipeRead(usize),
PipeWrite(usize),
Socket {
sock: usize,
end: usize,
},
Eventfd(usize),
Timerfd(usize),
Epoll(usize),
}
#[derive(Debug, Clone)]
pub struct FdTable {
map: BTreeMap<i32, Fd>,
}
impl FdTable {
#[must_use]
pub fn with_standard_streams() -> Self {
let mut map = BTreeMap::new();
map.insert(0, Fd::Stdin);
map.insert(1, Fd::Stdout);
map.insert(2, Fd::Stderr);
Self { map }
}
pub fn alloc(&mut self, fd: Fd) -> i32 {
let mut n = 3;
while self.map.contains_key(&n) {
n += 1;
}
self.map.insert(n, fd);
n
}
pub fn insert(&mut self, n: i32, fd: Fd) -> Option<Fd> {
self.map.insert(n, fd)
}
#[must_use]
pub fn get(&self, fd: i32) -> Option<&Fd> {
self.map.get(&fd)
}
pub fn get_mut(&mut self, fd: i32) -> Option<&mut Fd> {
self.map.get_mut(&fd)
}
pub fn close(&mut self, fd: i32) -> Option<Fd> {
self.map.remove(&fd)
}
pub fn values(&self) -> impl Iterator<Item = &Fd> {
self.map.values()
}
pub fn drain(&mut self) -> Vec<Fd> {
std::mem::take(&mut self.map).into_values().collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn alloc_starts_at_three_and_fills_gaps() {
let mut t = FdTable::with_standard_streams();
assert_eq!(t.alloc(Fd::Stdin), 3);
assert_eq!(t.alloc(Fd::Stdin), 4);
t.close(3);
assert_eq!(t.alloc(Fd::Stdin), 3);
}
}