use std::{cmp, io, path::PathBuf};
use super::Memfs;
#[derive(Debug, Default)]
pub(crate) struct MemfsFile {
pub(crate) pos: u64, pub(crate) data: Vec<u8>, pub(crate) path: Option<PathBuf>, pub(crate) fs: Option<Memfs>, }
impl MemfsFile {
pub(crate) fn len(&self) -> u64 {
self.data.len() as u64 - self.pos
}
pub(crate) fn sync(&mut self) -> io::Result<()> {
if let Some(ref fs) = self.fs {
if let Some(ref path) = self.path {
let mut guard = fs.write_guard();
if guard.contains_entry(path) {
if let Some(f) = guard.get_file_mut(path) {
f.data.clone_from(&self.data);
}
} else {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!("Target doesn't exist: {}", path.display()),
));
}
}
}
Ok(())
}
}
impl Clone for MemfsFile {
fn clone(&self) -> Self {
Self {
pos: self.pos,
data: self.data.clone(),
path: self.path.clone(),
fs: self.fs.as_ref().map(|x| x.clone()),
}
}
}
impl io::Read for MemfsFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let pos = self.pos as usize;
let len = cmp::min(buf.len(), self.len() as usize);
buf[..len].copy_from_slice(&self.data.as_slice()[pos..pos + len]);
self.pos += len as u64;
Ok(len)
}
}
impl io::Seek for MemfsFile {
fn seek(&mut self, pos: io::SeekFrom) -> std::io::Result<u64> {
match pos {
io::SeekFrom::Start(offset) => self.pos = offset,
io::SeekFrom::Current(offset) => self.pos = (self.pos as i64 + offset) as u64,
io::SeekFrom::End(offset) => self.pos = (self.data.len() as i64 + offset) as u64,
}
Ok(self.pos)
}
}
impl io::Write for MemfsFile {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.data.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.sync()
}
}
impl Drop for MemfsFile {
fn drop(&mut self) {
let _result = self.sync();
self.data.clear();
self.path = None;
self.fs = None;
}
}
#[cfg(test)]
mod tests {
use super::MemfsFile;
use crate::prelude::*;
#[test]
fn test_read_write_seek_len() {
let mut memfile = MemfsFile::default();
assert_eq!(memfile.len(), 0);
memfile.write(b"foobar1, ").unwrap();
assert_eq!(memfile.data, b"foobar1, ");
assert_eq!(memfile.len(), 9);
write!(memfile, "foobar2, ").unwrap();
assert_eq!(memfile.len(), 18);
assert_eq!(memfile.data, b"foobar1, foobar2, ");
memfile.write(b"foobar3").unwrap();
assert_eq!(memfile.len(), 25);
assert_eq!(memfile.data, b"foobar1, foobar2, foobar3");
let mut buf = [0; 1];
memfile.read(&mut buf).unwrap();
assert_eq!(memfile.len(), 24);
assert_eq!(&buf, b"f");
memfile.seek(SeekFrom::Start(0)).unwrap();
assert_eq!(memfile.len(), 25);
let mut buf = [0; 9];
memfile.read(&mut buf).unwrap();
assert_eq!(memfile.len(), 16);
assert_eq!(&buf, b"foobar1, ");
let mut buf = Vec::new();
memfile.read_to_end(&mut buf).unwrap();
assert_eq!(memfile.len(), 0);
assert_eq!(&buf, b"foobar2, foobar3");
let mut buf = String::new();
memfile.rewind().unwrap();
assert_eq!(memfile.len(), 25);
memfile.read_to_string(&mut buf).unwrap();
assert_eq!(memfile.len(), 0);
assert_eq!(buf, "foobar1, foobar2, foobar3".to_string());
}
}