use std::io::{Error, ErrorKind, Cursor, SeekFrom, Read, Write, Seek};
#[derive(Debug)]
pub enum FileError {
Permissions,
IOError(Error),
}
impl From<Error> for FileError {
fn from(err: Error) -> FileError {
FileError::IOError(err)
}
}
pub trait FileHandle: Send {
fn is_interactive(&self) -> bool;
fn read(&mut self, buf: &mut [u8]) -> Result<usize, FileError>;
fn write_all(&mut self, buf: &[u8]) -> Result<(), FileError>;
fn seek(&mut self, pos: SeekFrom) -> Result<u64, FileError>;
}
pub struct MemoryFile {
pub content: Cursor<Vec<u8>>,
pub readable: bool,
pub writable: bool,
pub seekable: bool,
pub appendonly: bool,
pub interactive: bool,
}
impl FileHandle for MemoryFile {
fn is_interactive(&self) -> bool { self.interactive }
fn read(&mut self, buf: &mut [u8]) -> Result<usize, FileError> {
if !self.readable { return Err(FileError::Permissions); }
let mut written = 0;
loop {
match self.content.read(&mut buf[written..]) {
Ok(count) => {
written += count;
if written >= buf.len() || count == 0 { return Ok(written); } }
Err(e) => match e.kind() {
ErrorKind::Interrupted => (), _ => return Err(e.into()),
}
}
}
}
fn write_all(&mut self, buf: &[u8]) -> Result<(), FileError> {
if !self.writable { return Err(FileError::Permissions); }
if self.appendonly { self.content.seek(SeekFrom::End(0))?; }
self.content.write_all(buf)?;
Ok(())
}
fn seek(&mut self, pos: SeekFrom) -> Result<u64, FileError> {
if !self.seekable { return Err(FileError::Permissions); }
Ok(self.content.seek(pos)?)
}
}