1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use std::{mem, path::PathBuf};

use crate::FsTree;

/// A filesystem tree recursive enum.
///
/// This enum has a variant for the following file types:
/// 1. `TreeNode::Regular` - A regular file.
/// 2. `TreeNode::Directory` - A folder with a (possible empty) list of children.
/// 3. `TreeNode::Symlink` - A symbolic link that points to another path.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TreeNode {
    /// A regular file.
    Regular,
    /// A directory, might have children `FsTree`s inside.
    Directory(Vec<FsTree>),
    /// Symbolic link, and it's target path.
    ///
    /// The link might be broken, it's not guaranteed that a symlink points to a valid path.
    Symlink(PathBuf),
}

impl TreeNode {
    /// Checks if the TreeNode is the same type as other.
    pub fn is_same_type_as(&self, other: &Self) -> bool {
        mem::discriminant(self) == mem::discriminant(other)
    }

    /// Shorthand for `file.file_type.is_regular()`
    pub fn is_regular(&self) -> bool {
        matches!(self, Self::Regular)
    }

    /// Shorthand for `file.file_type.is_dir()`
    pub fn is_dir(&self) -> bool {
        matches!(self, Self::Directory(_))
    }

    /// Shorthand for `file.file_type.is_symlink()`
    pub fn is_symlink(&self) -> bool {
        matches!(self, Self::Symlink(_))
    }

    /// Displays the file type discriminant str.
    pub fn file_type_display(&self) -> &'static str {
        match self {
            Self::Regular => "regular file",
            Self::Directory(_) => "directory",
            Self::Symlink(_) => "symlink",
        }
    }
}

#[cfg(feature = "libc-file-type")]
impl TreeNode {
    /// Returns the file type equivalent [`libc::mode_t`] value.
    pub fn as_mode_t(&self) -> libc::mode_t {
        match self {
            TreeNode::Regular => libc::S_IFREG,
            TreeNode::Directory(_) => libc::S_IFDIR,
            TreeNode::Symlink(_) => libc::S_IFCHR,
        }
    }
}