mod noop_backend; mod std_backend; use std::io; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; pub use noop_backend::NoopBackend; pub use std_backend::StdBackend; pub trait VfsBackend { fn read(&self, path: &Path) -> io::Result>; fn write(&self, path: &Path, data: &[u8]) -> io::Result<()>; fn read_dir(&self, path: &Path) -> io::Result; fn metadata(&self, path: &Path) -> io::Result; } pub struct DirEntry { path: PathBuf, } impl DirEntry { pub fn path(&self) -> &Path { &self.path } } pub struct ReadDir { inner: Box>>, } impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option { self.inner.next() } } pub struct Metadata { is_file: bool, } impl Metadata { pub fn is_file(&self) -> bool { self.is_file } pub fn is_dir(&self) -> bool { !self.is_file } } struct VfsLock { data: (), backend: Box, } impl VfsLock { pub fn read>(&mut self, path: P) -> io::Result>> { let path = path.as_ref(); let contents = self.backend.read(path)?; Ok(Arc::new(contents)) } pub fn write, C: AsRef<[u8]>>( &mut self, path: P, contents: C, ) -> io::Result<()> { let path = path.as_ref(); let contents = contents.as_ref(); self.backend.write(path, contents) } pub fn read_dir>(&mut self, path: P) -> io::Result { let path = path.as_ref(); self.backend.read_dir(path) } } pub struct Vfs { inner: Mutex, } impl Vfs { pub fn new(backend: B) -> Self { let lock = VfsLock { data: (), backend: Box::new(backend), }; Self { inner: Mutex::new(lock), } } pub fn read>(&self, path: P) -> io::Result>> { let path = path.as_ref(); let mut inner = self.inner.lock().unwrap(); inner.read(path) } pub fn write, C: AsRef<[u8]>>(&self, path: P, contents: C) -> io::Result<()> { let path = path.as_ref(); let contents = contents.as_ref(); let mut inner = self.inner.lock().unwrap(); inner.write(path, contents) } pub fn read_dir>(&self, path: P) -> io::Result { let path = path.as_ref(); let mut inner = self.inner.lock().unwrap(); inner.read_dir(path) } }