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
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
extern crate clipars;

pub mod meta;

use std::error;
use std::fmt;
use std::fs;

/// Error structure
#[derive(Clone, Debug)]
pub struct Error(String);

/// Error implementation
impl Error {
    /// Create Error from any Error
    pub fn new<E>(err: E) -> Self
    where
        E: error::Error,
    {
        Self(err.to_string())
    }

    /// Create Result with Error from any Error
    pub fn from<T, E>(err: E) -> Result<T, Self>
    where
        E: error::Error,
    {
        Err(Self::new(err))
    }

    /// Create Error from &str
    pub fn new_str(err: &str) -> Self {
        Self(err.to_string())
    }

    /// Create Result with Error from &str
    pub fn with_str<T>(err: &str) -> Result<T, Self> {
        Err(Self(err.to_string()))
    }
}

/// std::error::Error implementation for Error
impl error::Error for Error {}

/// Display implementation for Error
impl fmt::Display for Error {
    // fmt implementation
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.0)
    }
}

/// Either file or directory
#[derive(Clone, Debug)]
pub enum FileDir {
    Dir(String, fs::Metadata, Vec<FileDir>),
    File(String, fs::Metadata),
}

// FileDir implementation
impl FileDir {
    /// List all files and directories recursively
    pub fn list_dir(dir: fs::ReadDir) -> Result<Vec<FileDir>, Error> {
        // create buffer
        let mut files = Vec::new();

        // loop through files in directory
        for file_res in dir {
            // get file
            let file: fs::DirEntry = match file_res {
                Ok(file) => file,
                Err(err) => return Error::from(err),
            };

            // get file type
            let file_type = match file.file_type() {
                Ok(file_type) => file_type,
                Err(err) => return Error::from(err),
            };

            // get file path
            let file_path = match file.path().to_str() {
                Some(file_name) => file_name.to_string(),
                None => return Error::with_str("File name does not contain valid UTF-8"),
            };

            // get file metadata
            let metadata = match file.metadata() {
                Ok(metadata) => metadata,
                Err(err) => return Error::from(err),
            };

            // check if is dir
            if file_type.is_dir() {
                // read directory
                let file_dir = match fs::read_dir(file.path()) {
                    Ok(file_dir) => file_dir,
                    Err(err) => return Error::from(err),
                };

                // add other files
                let sub_dir = match Self::list_dir(file_dir) {
                    Ok(sub_dir) => sub_dir,
                    Err(err) => return Error::from(err),
                };

                // add directory to list
                files.push(FileDir::Dir(file_path, metadata, sub_dir));
            } else {
                // add file to list
                files.push(FileDir::File(file_path, metadata));
            }
        }

        // return paths
        Ok(files)
    }
}