drone-micropython-core 0.1.1

MicroPython for Drone.
use drone_core::ffi::{c_char, c_int};
use drone_core::fs::OpenOptions;
use drone_core::io::SeekFrom;
use drone_micropython_raw::{
  mp_import_stat_t, O_APPEND, O_CREAT, O_CREATNEW, O_READ, O_TRUNC, O_WRITE,
};
use io::Fd;

/// MicroPython I/O request.
#[allow(missing_docs)]
pub enum IoReq {
  /// Given a `path` for a file, return a file descriptor, a small, nonnegative
  /// integer for use in subsequent requests.
  Open { path: *const c_char, flags: Flags },
  /// See [`io::Read::read`](drone_core::io::Read::read).
  Read { fd: Fd, buf: *mut [u8] },
  /// See [`io::Write::write`](drone_core::io::Write::write).
  Write { fd: Fd, buf: *const [u8] },
  /// See [`io::Seek::seek`](drone_core::io::Seek::seek).
  Seek { fd: Fd, pos: SeekFrom },
  /// Flush all modified data of the file referred to by the file descriptor
  /// `fd` to the permanent storage device so that all changed information can
  /// be retrieved even after the system crashed or was rebooted.
  Fsync { fd: Fd },
  /// Close a file descriptor, so that it no longer refers to any file and may
  /// be reused.
  Close { fd: Fd },
  /// Return information about a file.
  ImportStat { path: *const c_char },
}

/// MicroPython I/O request response.
pub union IoReqRes {
  pub(in io) open: Result<Fd, c_int>,
  pub(in io) read: Result<usize, c_int>,
  pub(in io) write: Result<usize, c_int>,
  pub(in io) seek: Result<u64, c_int>,
  pub(in io) fsync: Result<(), c_int>,
  pub(in io) close: Result<(), c_int>,
  pub(in io) import_stat: Result<mp_import_stat_t, c_int>,
}

/// Values for the `flags` argument to [`IoReq::Open`](IoReq::Open).
#[derive(Clone, Copy)]
pub struct Flags(c_char);

impl IoReqRes {
  /// Creates a response for [`IoReq::Open`](IoReq::Open).
  ///
  /// # Safety
  ///
  /// The caller must choose an appropriate constructor.
  pub unsafe fn open(open: Result<Fd, c_int>) -> Self {
    Self { open }
  }

  /// Creates a response for [`IoReq::Read`](IoReq::Read).
  ///
  /// # Safety
  ///
  /// The caller must choose an appropriate constructor.
  pub unsafe fn read(read: Result<usize, c_int>) -> Self {
    Self { read }
  }

  /// Creates a response for [`IoReq::Write`](IoReq::Write).
  ///
  /// # Safety
  ///
  /// The caller must choose an appropriate constructor.
  pub unsafe fn write(write: Result<usize, c_int>) -> Self {
    Self { write }
  }

  /// Creates a response for [`IoReq::Seek`](IoReq::Seek).
  ///
  /// # Safety
  ///
  /// The caller must choose appropriate constructor.
  pub unsafe fn seek(seek: Result<u64, c_int>) -> Self {
    Self { seek }
  }

  /// Creates a response for [`IoReq::Fsync`](IoReq::Fsync).
  ///
  /// # Safety
  ///
  /// The caller must choose an appropriate constructor.
  pub unsafe fn fsync(fsync: Result<(), c_int>) -> Self {
    Self { fsync }
  }

  /// Creates a response for [`IoReq::Close`](IoReq::Close).
  ///
  /// # Safety
  ///
  /// The caller must choose an appropriate constructor.
  pub unsafe fn close(close: Result<(), c_int>) -> Self {
    Self { close }
  }

  /// Creates a response for [`IoReq::ImportStat`](IoReq::ImportStat).
  ///
  /// # Safety
  ///
  /// The caller must choose an appropriate constructor.
  pub unsafe fn import_stat(
    import_stat: Result<mp_import_stat_t, c_int>,
  ) -> Self {
    Self { import_stat }
  }
}

impl Flags {
  pub(crate) fn new(flags: c_char) -> Self {
    Flags(flags)
  }

  /// Fills generic [`OpenOptions`](OpenOptions).
  pub fn set_options<T: OpenOptions>(self, options: T) -> T {
    options
      .read((self.0 & O_READ as u8) != 0)
      .write((self.0 & O_WRITE as u8) != 0)
      .append((self.0 & O_APPEND as u8) != 0)
      .truncate((self.0 & O_TRUNC as u8) != 0)
      .create((self.0 & O_CREAT as u8) != 0)
      .create_new((self.0 & O_CREATNEW as u8) != 0)
  }
}