diskit 0.1.5

Utilities for intercepting disk requests.
Documentation
//! Transparent replica of [`DirEntry`](walkdir::DirEntry)
//!
//! For more information see the [struct level documentation](DirEntry).

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

use walkdir::DirEntryExt;

use crate::metadata::{FileType, Metadata};

/// Transparent replica of [`DirEntry`](walkdir::DirEntry)
///
/// The [`WalkdirIterator`](crate::walkdir::WalkdirIterator) doen't
/// return file handles, but values of this type.  You can get the
/// path with [`DirEntry::path`] and use that to open it as a proper
/// file.
// See lib.rs for justification.
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct DirEntry
{
    pub path: PathBuf,
    pub metadata: Metadata,
    pub follow_link: bool,
    pub depth: usize,
    pub ino: u64,
}

impl DirEntry
{
    /// Returns a reference to the path
    ///
    /// This function returns a reference to the path with which you
    /// can open the underlying file properly (but remember that it
    /// could be directory).  Use [`DirEntry::into_path`] if you don't need your
    /// [`DirEntry`] anymore and need a (owned) [`PathBuf`].
    #[must_use]
    pub fn path(&self) -> &Path
    {
        &self.path
    }

    /// Returns the path
    ///
    /// This function extracts the path of the file with which you can
    /// open the underlying file properly (but remember that it could
    /// be directory).  Use [`DirEntry::path`] if you still need your
    /// [`DirEntry`].
    // This nursery lint sometimes has trouble recognizing that some
    // types have (non-costs) destructors.  This problem is already
    // well known.
    #[allow(clippy::missing_const_for_fn)]
    #[must_use]
    pub fn into_path(self) -> PathBuf
    {
        self.path
    }

    /// Checks whether file is a symlink
    ///
    /// This function returns whether the opened file is a symlink or
    /// not.  Please notice that not all of the predefined diskits
    /// support symlinks (namely
    /// [`VirtualDiskit`](crate::VirtualDiskit)).
    #[must_use]
    pub fn path_is_symlink(&self) -> bool
    {
        self.metadata.file_type.is_symlink() || self.follow_link
    }

    /// Returns the metadata of the file
    ///
    /// This function returns a copy of the metadata of the file.  See
    /// [`Metadata`](crate::metadata::Metadata) for more information.
    #[must_use]
    pub const fn metadata(&self) -> Metadata
    {
        self.metadata
    }

    /// Returns the file type of the file
    ///
    /// This function returns the file type of the file.  See
    /// [`FileType`](crate::metadata::FileType) for more information.
    #[must_use]
    pub const fn file_type(&self) -> FileType
    {
        self.metadata.file_type
    }

    /// Returns the final component of the file's path
    ///
    /// This function returns the final component of the file's path,
    /// if there is one.  For more information see
    /// [`Path::file_name`].  This function returns the full path when
    /// [`Path::file_name`] would return [`None`].
    #[must_use]
    pub fn file_name(&self) -> &OsStr
    {
        self.path.file_name().unwrap_or(self.path.as_os_str())
    }

    /// Returns the depth at which the file was found
    ///
    /// This function returns the depth at which the file was found.
    /// For more information see [`walkdir::DirEntry::depth`].
    #[must_use]
    pub const fn depth(&self) -> usize
    {
        self.depth
    }
}

pub(crate) struct WorkaroundResult<T, E>
{
    pub inner: Result<T, E>,
}

impl From<::walkdir::DirEntry> for WorkaroundResult<DirEntry, Error>
{
    fn from(walkdir: ::walkdir::DirEntry) -> Self
    {
        let metadata = match walkdir.metadata()
        {
            Ok(metadata) => metadata.into(),
            Err(err) =>
            {
                return Self {
                    inner: Err(err.into()),
                }
            }
        };

        Ok(DirEntry {
            path: walkdir.path().to_owned(),
            metadata,
            // Isn't entirely correct, but it don't know how to fix.
            // TODO: Fix
            follow_link: walkdir.path_is_symlink(),
            depth: walkdir.depth(),
            ino: walkdir.ino(),
        })
        .into()
    }
}

impl<T, E> From<Result<T, E>> for WorkaroundResult<T, E>
{
    fn from(inner: Result<T, E>) -> Self
    {
        Self { inner }
    }
}

impl<T, E> From<WorkaroundResult<T, E>> for Result<T, E>
{
    fn from(val: WorkaroundResult<T, E>) -> Self
    {
        val.inner
    }
}

impl<T, E> WorkaroundResult<T, E>
{
    // This nursery lint sometimes has trouble recognizing that some
    // types have (non-costs) destructors.
    #[allow(clippy::missing_const_for_fn)]
    pub fn deworkaround(self) -> Result<T, E>
    {
        self.inner
    }
}