drone-micropython-core 0.1.1

MicroPython for Drone.
use drone_core::ffi::c_int;
use drone_micropython_raw::{EBADF, EMFILE};

/// File descriptor.
#[derive(Clone, Copy)]
pub struct Fd(c_int);

/// File descriptor table.
pub struct FdTable<T> {
  files: Vec<Option<T>>,
  holes: Vec<u16>,
}

impl Fd {
  /// Creates a new `Fd`.
  ///
  /// # Safety
  ///
  /// `fd` must be represent a valid file descriptor.
  pub unsafe fn new(fd: c_int) -> Self {
    Fd(fd)
  }

  /// Returns the integer representation of the file descriptor for use in FFI.
  pub fn to_c_int(self) -> c_int {
    self.0
  }
}

#[cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
impl<T> FdTable<T> {
  /// Creates a new empty `FdTable`.
  pub fn new() -> Self {
    let files = Vec::new();
    let holes = Vec::new();
    FdTable { files, holes }
  }

  /// Inserts a `file` into the table and returns its descriptor.
  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)
  }

  /// Removes and returns the file referred to by the descriptor `fd`.
  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)
  }

  /// Returns a reference to the file referred to by the descriptor `fd`.
  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)
  }

  /// Returns a mutable reference to the file referred to by the descriptor
  /// `fd`.
  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)
  }
}