summaryrefslogblamecommitdiff
path: root/src/entry.rs
blob: b59ced5636ea6da3954c8b84ad5962b76d6450ee (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
                               
             








                              
                                                                          
                          
                                                                           
                      
                                                                         
                               
 
            
                                                                  
                                 




                                                                       



                                                          
                                                                                          

                                           
                                                                 













                                                                  



                                                                         







                                                                                     
                                          

                                        
                                               
     
                                                                            
     
                                                      







                                                                               
use std::path::{Path, PathBuf};
use crate::*;

#[derive(PartialEq)]
pub enum EntryType {
    File,
    Directory,
}

pub struct Entry {
    pub entry_type: EntryType,
    pub is_symlink: bool,
    /// The final segment of the file path, including any file extensions.
    pub name: String,
    pub extension: String,
    /// The canonical file path, with intermediate symbolic links resolved.
    pub path: PathBuf,
    /// The file path as originally presented to the [Entry] constructor.
    pub original_path: PathBuf,
}

impl Entry {
    pub fn from_path(path: impl AsRef<Path>) -> ReadResult<Self> {
        let path = path.as_ref();
        macro_rules! raise {
            ($err:expr) => { io_result_to_read_result($err, path)? }; }

        let metadata = raise!(path.metadata());
        let canonical_path = raise!(std::fs::canonicalize(path));
        let canonical_metadata = raise!(canonical_path.metadata());
        let entry_type = if canonical_metadata.is_file() {
            EntryType::File
        } else if canonical_metadata.is_dir() {
            EntryType::Directory
        } else {
            unreachable!("Canonical metadata must describe either a file or a directory");
        };

        let name = match path.file_name() {
            Some(os_str) => os_str.to_string_lossy().to_string(),
            None => path.to_string_lossy().to_string(),
        };
        let extension = match path.extension() {
            Some(extension) => extension.to_string_lossy().into(),
            None => String::default(),
        };
        Ok(Entry {
            entry_type,
            name,
            extension,
            path: canonical_path,
            original_path: path.to_path_buf(),
            is_symlink: metadata.is_symlink(),
        })
    }

    pub fn parent(&self) -> Option<Entry> {
        Entry::from_path(self.original_path.parent()?).ok()
    }

    /// Split the filename on the last period, ignoring any period at the
    /// start of the filename. If no extension is found, the extension is empty.
    pub fn split_name(&self) -> (String, String) {
        match self.name.rsplit_once(".") {
            Some(("", _)) | None => (self.name.to_string(), String::new()),
            Some((prefix, extension)) => (prefix.to_string(), extension.to_string()),
        }
    }

    pub fn is_file(&self) -> bool {
        self.entry_type == EntryType::File
    }

    pub fn is_directory(&self) -> bool {
        self.entry_type == EntryType::Directory
    }

    pub fn read_as_bytes(&self) -> ReadResult<Vec<u8>> {
        Ok(io_result_to_read_result(std::fs::read(&self.path), &self.path)?)
    }

    pub fn read_as_utf8(&self) -> ReadResult<String> {
        return Ok(String::from_utf8_lossy(&self.read_as_bytes()?).to_string());
    }
}

impl AsRef<Path> for Entry {
    fn as_ref(&self) -> &Path {
        &self.path
    }
}