use std::io::{Error, ErrorKind, Cursor, SeekFrom, Read, Write, Seek};
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub enum FileError {
Permissions,
IOError(Error),
}
impl From<Error> for FileError {
fn from(err: Error) -> FileError {
FileError::IOError(err)
}
}
pub trait FileHandle {
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: Arc<Mutex<Cursor<Vec<u8>>>>,
pub readable: bool,
pub writable: bool,
pub seekable: 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 h = self.content.lock().unwrap();
let mut written = 0;
loop {
match h.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); }
self.content.lock().unwrap().write_all(buf)?;
Ok(())
}
fn seek(&mut self, pos: SeekFrom) -> Result<u64, FileError> {
if !self.seekable { return Err(FileError::Permissions); }
Ok(self.content.lock().unwrap().seek(pos)?)
}
}