use std::{
io::{Error, ErrorKind, SeekFrom},
path::{Path, PathBuf},
sync::{Arc, Mutex, MutexGuard},
};
use crate::{
dir_entry::DirEntry,
file::{File, FileInner},
metadata::Metadata,
open_options::OpenOptions,
walkdir::{WalkDir, WalkdirIterator, WalkdirIteratorInner},
Diskit,
};
use self::implementation::VirtualDiskitInner;
mod helpers;
mod implementation;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone)]
pub struct VirtualDiskit
{
inner: Arc<Mutex<VirtualDiskitInner>>,
}
impl Default for VirtualDiskit
{
fn default() -> Self
{
Self {
inner: Arc::new(Mutex::new(VirtualDiskitInner::new())),
}
}
}
impl Diskit for VirtualDiskit
{
fn set_pwd_inner(&self, new_pwd: &Path) -> Result<(), Error>
{
let pwd = &mut self.get_inner().pwd;
*pwd = pwd.join(new_pwd);
Ok(())
}
fn get_pwd(&self) -> Result<PathBuf, Error>
{
Ok(self.get_inner().pwd.clone())
}
fn open_inner(&self, path: &Path) -> Result<File<Self>, Error>
{
self.open_with_options_inner(path, OpenOptions::new().read(true))
}
fn create_inner(&self, path: &Path) -> Result<File<Self>, Error>
{
self.open_with_options_inner(
path,
OpenOptions::new().write(true).create(true).truncate(true),
)
}
fn open_with_options_inner(
&self,
path: &Path,
options: OpenOptions,
) -> Result<File<Self>, Error>
{
self.get_inner().open_with_options(path, options, self)
}
fn read_inner(&self, file: &FileInner, buf: &mut [u8]) -> Result<usize, Error>
{
self.get_inner().read(file, buf)
}
fn read_to_end_inner(&self, file: &mut FileInner, buf: &mut Vec<u8>) -> Result<usize, Error>
{
self.get_inner().read_to_end(file, buf)
}
fn read_to_string_inner(&self, file: &mut FileInner, buf: &mut String) -> Result<usize, Error>
{
self.get_inner().read_to_string(file, buf)
}
fn write_inner(&self, file: &mut FileInner, buf: &[u8]) -> Result<usize, Error>
{
self.get_inner().write(file, buf)
}
fn write_all_inner(&self, file: &mut FileInner, buf: &[u8]) -> Result<(), Error>
{
self.get_inner().write_all(file, buf)
}
fn flush_inner(&self, _file: &mut FileInner) -> Result<(), Error>
{
Ok(())
}
fn metadata_inner(&self, file: &FileInner) -> Result<Metadata, Error>
{
self.get_inner().metadata_inner(file)
}
fn seek_inner(&self, file: &mut FileInner, pos: SeekFrom) -> Result<u64, Error>
{
self.get_inner().seek(file, pos)
}
fn create_dir_inner(&self, path: &Path) -> Result<(), Error>
{
self.get_inner().create_dir(path)
}
fn create_dir_all_inner(&self, path: &Path) -> Result<(), Error>
{
self.get_inner().create_dir_all(path)
}
fn close_inner(&self, mut file: FileInner) -> Result<(), Error>
{
self.get_inner().close(&mut file);
Ok(())
}
fn walkdir_inner(&self, path: &Path) -> WalkDir<Self>
{
WalkDir::new_default(self.clone(), path.to_owned())
}
fn into_walkdir_iterator(&self, walkdir: WalkDir<Self>) -> WalkdirIterator<Self>
{
self.get_inner().into_walkdir_iterator(walkdir)
}
fn walkdir_next_inner(
&self,
inner: &mut WalkdirIteratorInner,
) -> Option<Result<DirEntry, Error>>
{
#[allow(clippy::significant_drop_in_scrutinee)]
match self.get_inner().walkdir_next_inner(inner)
{
Some(Err(err)) if err.kind() == ErrorKind::NotFound => None,
x => x,
}
}
#[cfg(feature = "trash")]
fn trash_delete_inner(&self, path: &Path) -> Result<(), trash::Error>
{
self.get_inner()
.trash_delete(path)
.map_err(trash::into_unknown)
}
}
impl VirtualDiskit
{
fn get_inner(&self) -> MutexGuard<'_, VirtualDiskitInner>
{
self.inner.lock().expect("A virtual diskit panicked")
}
}