diskit 0.1.5

Utilities for intercepting disk requests.
Documentation
//! [Stdlib](std) passthrough diskit
//!
//! For more information see the [struct level documentation](StdDiskit).

use std::{
    env::{current_dir, set_current_dir},
    fs::{self, create_dir, create_dir_all},
    io::{Error, Read, Seek, SeekFrom, Write},
    path::{Path, PathBuf},
};

use crate::{
    dir_entry::{DirEntry, WorkaroundResult},
    file::{File, FileInner},
    metadata::Metadata,
    open_options::OpenOptions,
    walkdir::{WalkDir, WalkdirIterator, WalkdirIteratorInner},
    Diskit,
};

/// [Stdlib](std) passthrough diskit
///
/// This diskit passes all requests directly to the corresponding
/// standard functions through.  This is useful if you normally want
/// to access the disk (then you can use this diskit), but sometimes
/// redirect your requests somewhere else (then you should use the
/// appropriate other diskit), or as a last element in a diskit chain
/// (like in [`LogDiskit<StdDiskit>`](crate::LogDiskit)).
///
/// Thanks to special optimizations of this library this diskit is
/// (nearly) overhead-free.
#[derive(Debug, Clone, Copy)]
pub struct StdDiskit;

impl Default for StdDiskit
{
    fn default() -> Self
    {
        Self
    }
}

impl Diskit for StdDiskit
{
    fn set_pwd_inner(&self, path: &Path) -> Result<(), Error>
    {
        set_current_dir(path)
    }

    fn get_pwd(&self) -> Result<PathBuf, Error>
    {
        current_dir()
    }

    fn open_inner(&self, path: &Path) -> Result<File<Self>, Error>
    {
        Ok(File {
            inner: FileInner {
                file: Some(fs::File::open(path)?),
                val: 0,
            },
            diskit: *self,
        })
    }

    fn create_inner(&self, path: &Path) -> Result<File<Self>, Error>
    {
        Ok(File {
            inner: FileInner {
                file: Some(fs::File::create(path)?),
                val: 0,
            },
            diskit: *self,
        })
    }

    fn open_with_options_inner(
        &self,
        path: &Path,
        options: OpenOptions,
    ) -> Result<File<Self>, Error>
    {
        Ok(File {
            inner: FileInner {
                file: Some(Into::<fs::OpenOptions>::into(options).open(path)?),
                val: 0,
            },
            diskit: *self,
        })
    }

    fn read_inner(&self, file: &FileInner, buf: &mut [u8]) -> Result<usize, Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .read(buf)
    }

    fn read_to_end_inner(&self, file: &mut FileInner, buf: &mut Vec<u8>) -> Result<usize, Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .read_to_end(buf)
    }

    fn read_to_string_inner(&self, file: &mut FileInner, buf: &mut String) -> Result<usize, Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .read_to_string(buf)
    }

    fn write_inner(&self, file: &mut FileInner, buf: &[u8]) -> Result<usize, Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .write(buf)
    }

    fn write_all_inner(&self, file: &mut FileInner, buf: &[u8]) -> Result<(), Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .write_all(buf)
    }

    fn flush_inner(&self, file: &mut FileInner) -> Result<(), Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .flush()
    }

    fn metadata_inner(&self, file: &FileInner) -> Result<Metadata, Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .metadata()
            .map(Into::into)
    }

    fn seek_inner(&self, file: &mut FileInner, pos: SeekFrom) -> Result<u64, Error>
    {
        file.file
            .as_ref()
            .expect("StdDiskit's Files are never None")
            .seek(pos)
    }

    fn create_dir_inner(&self, path: &Path) -> Result<(), Error>
    {
        create_dir(path)
    }

    fn create_dir_all_inner(&self, path: &Path) -> Result<(), Error>
    {
        create_dir_all(path)
    }

    fn close_inner(&self, _: FileInner) -> Result<(), Error>
    {
        Ok(())
    }

    fn walkdir_inner(&self, path: &Path) -> WalkDir<Self>
    {
        WalkDir::new_default(*self, path.to_owned())
    }

    fn walkdir_next_inner(
        &self,
        inner: &mut WalkdirIteratorInner,
    ) -> Option<Result<DirEntry, Error>>
    {
        inner
            .walkdir
            .as_mut()
            .expect("StdDiskit's Walkdirs are never None")
            .next()
            .map(|x| {
                x.map_err(Into::into).and_then(|y| {
                    // I know that it looks awful.  TODO: Fix
                    <_ as Into<WorkaroundResult<_, _>>>::into(y).deworkaround()
                })
            })
    }

    fn into_walkdir_iterator(&self, walkdir: WalkDir<Self>) -> WalkdirIterator<Self>
    {
        WalkdirIterator {
            inner: Ok((
                WalkdirIteratorInner {
                    walkdir: Some(walkdir.to_original().into_iter()),
                    val: 0,
                    original: walkdir.options,
                },
                walkdir.diskit,
            )),
        }
    }

    #[cfg(feature = "trash")]
    fn trash_delete_inner(&self, path: &Path) -> Result<(), trash::Error>
    {
        trash::delete(path)
    }
}