drone-fatfs 0.2.3

Bindings to ChaN's FatFs.
use cmd::{Cmd, CmdKind};
use core::mem::uninitialized;
use drone_core::ffi::CStr;
use drone_core::fs::OpenOptions;
use drone_fatfs_raw::{
  FA_CREATE_ALWAYS, FA_CREATE_NEW, FA_OPEN_ALWAYS, FA_OPEN_APPEND, FA_READ,
  FA_WRITE, FIL,
};
use fat_sess::{FatSess, FatSessError, FatSessRes};
use file_sess::FileSess;
use futures::prelude::*;

/// FatFs file object.
pub struct File {
  fil: Box<FIL>,
}

unsafe impl Send for File {}

impl File {
  pub(crate) unsafe fn new_uninitialized() -> Self {
    let fil = Box::new(uninitialized());
    Self { fil }
  }

  pub(crate) fn as_raw_mut(&mut self) -> *mut FIL {
    self.fil.as_mut()
  }

  /// Creates a file session.
  pub fn sess<'sess, T: FatSessRes>(
    &'sess mut self,
    fat_sess: &'sess mut FatSess<T>,
  ) -> FileSess<T> {
    FileSess::new(self, fat_sess)
  }
}

/// Options and flags which can be used to configure how a file is opened.
pub struct FileOptions<'sess, T: FatSessRes> {
  fat_sess: &'sess mut FatSess<T>,
  mode: u8,
}

impl<'sess, T: FatSessRes> FileOptions<'sess, T> {
  pub(crate) fn new(fat_sess: &'sess mut FatSess<T>) -> Self {
    Self { fat_sess, mode: 0 }
  }

  /// Opens a file at `path` with the options specified by `self`.
  pub fn open(
    self,
    path: &'sess CStr,
  ) -> impl Future<Item = File, Error = FatSessError<T::Error>> + 'sess {
    let Self { fat_sess, mode } = self;
    unsafe { fat_sess.cmd(Cmd(CmdKind::Open(path, mode)), |res| res.open) }
  }
}

impl<'sess, T: FatSessRes> OpenOptions for FileOptions<'sess, T> {
  fn read(mut self, read: bool) -> Self {
    if read {
      self.mode |= FA_READ as u8;
    } else {
      self.mode &= !(FA_READ as u8);
    }
    self
  }

  fn write(mut self, write: bool) -> Self {
    if write {
      self.mode |= FA_WRITE as u8;
    } else {
      self.mode &= !(FA_WRITE as u8);
    }
    self
  }

  fn append(mut self, append: bool) -> Self {
    if append {
      self.mode |= FA_OPEN_APPEND as u8;
    } else {
      self.mode &= !(FA_OPEN_APPEND as u8);
    }
    self
  }

  fn truncate(mut self, truncate: bool) -> Self {
    if truncate {
      self.mode |= FA_CREATE_ALWAYS as u8;
    } else {
      self.mode &= !(FA_CREATE_ALWAYS as u8);
    }
    self
  }

  fn create(mut self, create: bool) -> Self {
    if create {
      self.mode |= FA_OPEN_ALWAYS as u8;
    } else {
      self.mode &= !(FA_OPEN_ALWAYS as u8);
    }
    self
  }

  fn create_new(mut self, create_new: bool) -> Self {
    if create_new {
      self.mode |= FA_CREATE_NEW as u8;
    } else {
      self.mode &= !(FA_CREATE_NEW as u8);
    }
    self
  }
}