ex-cli 1.20.0

Command line tool to find, filter, sort and list files.
Documentation
use crate::error::{MyError, MyResult};
use crate::fs::entry::Entry;
use crate::fs::flags::FileFlags;
use crate::fs::system::{System, EXEC_MASK};
use std::collections::HashSet;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum ExecKind {
    None,
    User,
    Other,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum FileKind {
    File(ExecKind),
    Dir,
    Link(bool), // (true for resolved link)
    Other,
}

impl FileKind {
    fn from_char(ch: char) -> Option<Vec<Self>> {
        match ch {
            'f' => Some(vec![
                Self::File(ExecKind::None),
                Self::File(ExecKind::User),
                Self::File(ExecKind::Other),
            ]),
            'e' => Some(vec![
                Self::File(ExecKind::User),
                Self::File(ExecKind::Other),
            ]),
            'd' => Some(vec![
                Self::Dir,
            ]),
            'l' => Some(vec![
                Self::Link(false),
                Self::Link(true),
            ]),
            _ => None,
        }
    }

    pub fn from_entry<S: System>(system: &S, entry: &dyn Entry) -> Self {
        match entry.file_flags() {
            FileFlags::File => Self::parse_file(system, entry),
            FileFlags::Dir => Self::Dir,
            FileFlags::Link => Self::Link(true),
            FileFlags::Other => Self::Other,
        }
    }

    #[cfg(unix)]
    fn parse_file<S: System>(system: &S, entry: &dyn Entry) -> Self {
        if (entry.file_mode() & system.get_mask(entry.owner_uid(), entry.owner_gid())) != 0 {
            Self::File(ExecKind::User)
        } else if (entry.file_mode() & EXEC_MASK) != 0 {
            Self::File(ExecKind::Other)
        } else {
            Self::File(ExecKind::None)
        }
    }

    #[cfg(not(unix))]
    fn parse_file<S: System>(_system: &S, entry: &dyn Entry) -> Self {
        if (entry.file_mode() & EXEC_MASK) != 0 {
            Self::File(ExecKind::User)
        } else {
            Self::File(ExecKind::None)
        }
    }

    pub fn dir_offset(&self) -> usize {
        if *self == Self::Dir { 1 } else { 0 }
    }
}

#[derive(Clone)]
pub struct FileSet {
    pub inner: HashSet<FileKind>,
}

impl FileSet {
    pub fn from_str(value: &str) -> MyResult<Self> {
        let mut inner = HashSet::new();
        for ch in value.chars() {
            if let Some(items) = FileKind::from_char(ch) {
                inner.extend(items);
            } else {
                return Err(MyError::create_clap("type", ch));
            }
        }
        let results = Self { inner };
        Ok(results)
    }
}