use std::collections::HashSet;
use std::fmt::Debug;
use std::path::Path;
use std::sync::OnceLock;
use super::{FileIcon, FileVersionInfo, Result};
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Priority(pub f32);
impl Default for Priority {
fn default() -> Self {
Self(1.0)
}
}
pub trait FileEntry: Debug + Send + Sync {
fn path(&self) -> &Path;
fn link_path(&self) -> Option<&Path>;
fn icon(&self) -> Result<FileIcon>;
fn version_info(&self) -> Result<FileVersionInfo>;
fn priority(&self) -> Priority;
fn extension(&self) -> Option<&str> {
self.link_path()
.unwrap_or_else(|| self.path())
.extension()
.and_then(|s| s.to_str())
}
fn is_executable(&self) -> bool {
self.extension()
.is_some_and(|e| executable_extensions().contains(e.to_ascii_lowercase().as_str()))
}
fn display_name(&self) -> String {
self.path()
.file_name()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_default()
}
}
fn executable_extensions() -> &'static HashSet<String> {
static EXTS: OnceLock<HashSet<String>> = OnceLock::new();
EXTS.get_or_init(|| {
std::env::var("PATHEXT")
.unwrap_or_default()
.split(';')
.filter_map(|raw| {
let cleaned = raw.trim().trim_start_matches('.').to_ascii_lowercase();
(!cleaned.is_empty()).then_some(cleaned)
})
.collect()
})
}