use drone_core::ffi::c_int;
use drone_micropython_raw::{EBADF, EMFILE};
#[derive(Clone, Copy)]
pub struct Fd(c_int);
pub struct FdTable<T> {
files: Vec<Option<T>>,
holes: Vec<u16>,
}
impl Fd {
pub unsafe fn new(fd: c_int) -> Self {
Fd(fd)
}
pub fn to_c_int(self) -> c_int {
self.0
}
}
#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
impl<T> FdTable<T> {
pub fn new() -> Self {
let files = Vec::new();
let holes = Vec::new();
FdTable { files, holes }
}
pub fn insert(&mut self, file: T) -> Result<Fd, c_int> {
if let Some(fd) = self.holes.pop() {
self.files[fd as usize] = Some(file);
return Ok(Fd(c_int::from(fd)));
} else {
self.files.push(Some(file));
let fd = self.files.len() - 1;
if fd <= u16::max_value() as usize {
return Ok(Fd(fd as c_int));
}
}
Err(EMFILE as i32)
}
pub fn remove(&mut self, fd: Fd) -> Result<T, c_int> {
if (fd.0 as usize) < self.files.len() - 1 {
if let Some(file) = self.files[fd.0 as usize].take() {
self.holes.push(fd.0 as u16);
return Ok(file);
}
} else if fd.0 as usize == self.files.len() - 1 {
if let Some(file) = self.files.remove(fd.0 as usize) {
return Ok(file);
}
}
Err(EBADF as i32)
}
pub fn get(&self, fd: Fd) -> Result<&T, c_int> {
if let Some(Some(file)) = self.files.get(fd.0 as usize) {
return Ok(file);
}
Err(EBADF as i32)
}
pub fn get_mut(&mut self, fd: Fd) -> Result<&mut T, c_int> {
if let Some(Some(file)) = self.files.get_mut(fd.0 as usize) {
return Ok(file);
}
Err(EBADF as i32)
}
}