use crate::finder::Checker; #[cfg(unix)] use std::ffi::CString; use std::fs; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; use std::path::Path; pub struct ExecutableChecker; impl ExecutableChecker { pub fn new() -> ExecutableChecker { ExecutableChecker } } impl Checker for ExecutableChecker { #[cfg(unix)] fn is_valid(&self, path: &Path) -> bool { CString::new(path.as_os_str().as_bytes()) .map(|c| unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 }) .unwrap_or(false) } #[cfg(windows)] fn is_valid(&self, _path: &Path) -> bool { true } } pub struct ExistedChecker; impl ExistedChecker { pub fn new() -> ExistedChecker { ExistedChecker } } impl Checker for ExistedChecker { #[cfg(target_os = "windows")] fn is_valid(&self, path: &Path) -> bool { fs::symlink_metadata(path) .map(|metadata| { let file_type = metadata.file_type(); file_type.is_file() || file_type.is_symlink() }) .unwrap_or(false) } #[cfg(not(target_os = "windows"))] fn is_valid(&self, path: &Path) -> bool { fs::metadata(path) .map(|metadata| metadata.is_file()) .unwrap_or(false) } } pub struct CompositeChecker { checkers: Vec>, } impl CompositeChecker { pub fn new() -> CompositeChecker { CompositeChecker { checkers: Vec::new(), } } pub fn add_checker(mut self, checker: Box) -> CompositeChecker { self.checkers.push(checker); self } } impl Checker for CompositeChecker { fn is_valid(&self, path: &Path) -> bool { self.checkers.iter().all(|checker| checker.is_valid(path)) } }