diskit 0.1.5

Utilities for intercepting disk requests.
Documentation
//! Trait to intercept requests.
//!
//! For more information see the [trait level documentation](Diskit).

use std::{
    io::{Error, SeekFrom},
    path::{Path, PathBuf},
};

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

/// Trait to intercept requests.
///
/// This trait handles the interception of disk requests.  If you're
/// not implementing your own diskit you should mostly use the methods
/// provided by the [`DiskitExt`](crate::diskit_extend::DiskitExt),
/// [`io::Read`](std::io::Read) and [`io::Write`](std::io::Write)
/// traits.
///
/// Many methods correspond directly to the normal ones from
/// [stdlib](std) and should behave mostly the same, see therefore
/// their documentation for the precise intended behavior.
pub trait Diskit: Clone + Default + 'static
{
    /// Changes the current working directory
    ///
    /// This sets the path relative to which relative paths are
    /// resolved.  Notice that this function of course can also get a
    /// relative path.
    ///
    /// It depends on the used diskit what path is the initial current
    /// working directory.
    ///
    /// This function corresponds to [`std::env::set_current_dir`].
    fn set_pwd_inner(&self, path: &Path) -> Result<(), Error>;

    /// Retrieves the current working directory
    ///
    /// This gets the path relative to which relative paths are
    /// resolved.
    ///
    /// It depends on the used diskit what path is the initial current
    /// working directory
    ///
    /// This function corresponds to [`std::env::current_dir`].
    fn get_pwd(&self) -> Result<PathBuf, Error>;

    /// Opens an exisitent file
    ///
    /// This function corresponds to [`std::fs::File::open`].
    fn open_inner(&self, path: &Path) -> Result<File<Self>, Error>;

    /// Creates a new file or truncates it
    ///
    /// This function corresponds to [`std::fs::File::create`].
    fn create_inner(&self, path: &Path) -> Result<File<Self>, Error>;

    /// Opens a file with custom options
    ///
    /// This function corresponds to [`std::fs::OpenOptions::open`].
    fn open_with_options_inner(
        &self,
        path: &Path,
        options: OpenOptions,
    ) -> Result<File<Self>, Error>;

    /// Reads as much as possible into the provided buffer
    ///
    /// This function corresponds to [`std::io::Read::read`].
    fn read_inner(&self, file: &FileInner, buf: &mut [u8]) -> Result<usize, Error>;

    /// Reads the complete file into the provided buffer
    ///
    /// This function corresponds to [`std::io::Read::read_to_end`].
    fn read_to_end_inner(&self, file: &mut FileInner, buf: &mut Vec<u8>) -> Result<usize, Error>;

    /// Reads the complete file into the provided string
    ///
    /// This function corresponds to
    /// [`std::io::Read::read_to_string`].
    fn read_to_string_inner(&self, file: &mut FileInner, buf: &mut String) -> Result<usize, Error>;

    /// Writes as much as possible from the provided buffer
    ///
    /// This function corresponds to [`std::io::Write::write`].
    fn write_inner(&self, file: &mut FileInner, buf: &[u8]) -> Result<usize, Error>;

    /// Writes the complete provided buufer into the file
    ///
    /// This function corresponds to [`std::io::Write::write_all`].
    fn write_all_inner(&self, file: &mut FileInner, buf: &[u8]) -> Result<(), Error>;

    /// Flushes all writes of the file
    ///
    /// This function corresponds to [`std::io::Write::flush`].
    fn flush_inner(&self, file: &mut FileInner) -> Result<(), Error>;

    /// Retrieves the metadata of the file
    ///
    /// This function corresponds to [`std::fs::File::metadata`].
    fn metadata_inner(&self, file: &FileInner) -> Result<Metadata, Error>;

    /// Repositions the file's cursor
    ///
    /// This function corresponds to [`std::io::Seek::seek`].
    fn seek_inner(&self, file: &mut FileInner, pos: SeekFrom) -> Result<u64, Error>;

    /// Creates a directory
    ///
    /// This function corresponds to [`std::fs::create_dir`].
    fn create_dir_inner(&self, path: &Path) -> Result<(), Error>;

    /// Creates a directory and all above if necessary
    ///
    /// This function corresponds to [`std::fs::create_dir_all`].
    fn create_dir_all_inner(&self, path: &Path) -> Result<(), Error>;

    /// Closes the file
    ///
    /// This function manually closes the file.  If this is not done
    /// the file will be automatically closed on [drop](Drop),
    /// printing any error to `stderr`.  The behavior of the
    /// [stdlib](std) is to quietly discard the error.
    ///
    /// This function is not directly supported in the stdlib as far
    /// as I know.  The best correspondence would be
    /// [`std::mem::drop`].
    fn close_inner(&self, file: FileInner) -> Result<(), Error>;

    /// Creates a [`Walkdir`](crate::walkdir::WalkDir) from a path
    ///
    /// This function corresponds to [`walkdir::WalkDir::new`].
    fn walkdir_inner(&self, path: &Path) -> WalkDir<Self>;

    /// Converts a walkdir builder to an iterator
    ///
    /// This function is used to provide the [`IntoIterator`]
    /// implementation of [`WalkDir`](crate::walkdir::WalkDir) and
    /// corresponds therefore to
    /// [`std::iter::IntoIterator::into_iter`].
    // This is a false positive, because the value that gets
    // "`into`-ed" is not `self`, but `walkdir` and that is actually
    // taken by value.
    #[allow(clippy::wrong_self_convention)]
    fn into_walkdir_iterator(&self, walkdir: WalkDir<Self>) -> WalkdirIterator<Self>;

    /// Gets the next file in a [`WalkDir`](crate::walkdir::WalkDir)
    ///
    /// This function is used to provide the [`Iterator`]
    /// implementation of
    /// [`WalkDirIterator`](crate::walkdir::WalkdirIterator)and
    /// corresponds therefore to [`std::iter::Iterator::next`].
    fn walkdir_next_inner(
        &self,
        inner: &mut WalkdirIteratorInner,
    ) -> Option<Result<DirEntry, Error>>;

    /// Moves a file or directory in the the trash
    ///
    /// This function moves files and directories to the trash, but
    /// since the [`Diskit`] trait does not provide any way to restore
    /// files this can be implemented by deleting the file if there is
    /// no other way to observe the difference (that means that
    /// [`StdDiskit`](crate::StdDiskit) actually moves it in the trash
    /// since there are many ways to see whether it did that or not,
    /// while [`VirtualDiskit`](crate::VirtualDiskit) doesn't since
    /// you can't access these files anymore anyway).
    ///
    /// This function is only available if the feature **trash** is
    /// activated.
    ///
    /// This function corresponds to [`trash::delete`].
    #[cfg(feature = "trash")]
    fn trash_delete_inner(&self, path: &Path) -> Result<(), trash::Error>;
}