Skip to main content

dioxus_swdir_tree_core/
entry.rs

1//! Owned, framework-neutral directory entry produced by a scan.
2//!
3//! [`LoadedEntry`] is the shape stored in the [`crate::TreeCache`] and
4//! carried by [`crate::LoadPayload`]: just the three facts the tree needs
5//! (`path`, `is_dir`, `is_hidden`), fully owned so values are
6//! `Send + 'static` and can cross worker-thread boundaries.
7//!
8//! Hiddenness is decided **once, at scan time**, using the OS-native rule:
9//! dotfile on Unix; the `FILE_ATTRIBUTE_HIDDEN` bit (with the dotfile rule
10//! as fallback) on Windows; dotfile elsewhere. `swdir::DirEntry` caches
11//! `FileType` and `Metadata`, so no extra syscalls are made here.
12
13use std::ffi::OsStr;
14use std::path::PathBuf;
15
16/// One scanned directory entry, reduced to what the tree model needs.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct LoadedEntry {
19    /// Absolute path of the entry.
20    pub path: PathBuf,
21    /// `true` for directories (symlinks are not followed).
22    pub is_dir: bool,
23    /// `true` if the entry is hidden by the host OS's convention.
24    pub is_hidden: bool,
25}
26
27impl LoadedEntry {
28    /// Final path component, for use as a row label. Falls back to an
29    /// empty string if the path somehow lacks a file name.
30    pub fn file_name(&self) -> &OsStr {
31        self.path.file_name().unwrap_or(OsStr::new(""))
32    }
33}
34
35impl From<&swdir::DirEntry> for LoadedEntry {
36    fn from(entry: &swdir::DirEntry) -> Self {
37        Self {
38            path: entry.path().to_path_buf(),
39            is_dir: entry.is_dir(),
40            is_hidden: detect_hidden(entry),
41        }
42    }
43}
44
45/// OS-native hiddenness, computed from data `swdir` already cached.
46fn detect_hidden(entry: &swdir::DirEntry) -> bool {
47    let dotfile = is_dotfile(entry.display_name());
48
49    #[cfg(windows)]
50    {
51        const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2;
52        use std::os::windows::fs::MetadataExt;
53        let attr_hidden = entry
54            .metadata()
55            .map(|m| m.file_attributes() & FILE_ATTRIBUTE_HIDDEN != 0)
56            .unwrap_or(false);
57        attr_hidden || dotfile
58    }
59
60    #[cfg(not(windows))]
61    {
62        dotfile
63    }
64}
65
66/// `true` if the basename starts with an ASCII dot.
67pub(crate) fn is_dotfile(name: &OsStr) -> bool {
68    name.as_encoded_bytes().first() == Some(&b'.')
69}