1use std::path::PathBuf;
4use std::time::SystemTime;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[non_exhaustive]
9pub enum EntryKind {
10 File,
12 Directory,
14 Symlink,
16 Other,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct FileEntry {
27 pub path: PathBuf,
29 pub relative_path: Option<PathBuf>,
31 pub kind: EntryKind,
33 pub size: Option<u64>,
35 pub modified: Option<SystemTime>,
37 pub readonly: Option<bool>,
39}
40
41impl FileEntry {
42 pub fn new(path: PathBuf, kind: EntryKind) -> Self {
44 Self {
45 path,
46 relative_path: None,
47 kind,
48 size: None,
49 modified: None,
50 readonly: None,
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
57#[non_exhaustive]
58pub enum SortMode {
59 None,
61 #[default]
63 Path,
64 Name,
66 DirsFirst,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
72#[non_exhaustive]
73pub enum TraversalErrorPolicy {
74 #[default]
76 FailFast,
77 SkipErrors,
79}
80
81pub fn sort_entries(entries: &mut [FileEntry], mode: SortMode) {
83 match mode {
84 SortMode::None => {}
85 SortMode::Path => {
86 entries.sort_by(|a, b| a.path.to_string_lossy().cmp(&b.path.to_string_lossy()));
87 }
88 SortMode::Name => {
89 entries.sort_by(|a, b| {
90 let an = a
91 .path
92 .file_name()
93 .map(|n| n.to_string_lossy())
94 .unwrap_or_default();
95 let bn = b
96 .path
97 .file_name()
98 .map(|n| n.to_string_lossy())
99 .unwrap_or_default();
100 an.cmp(&bn)
101 .then_with(|| a.path.to_string_lossy().cmp(&b.path.to_string_lossy()))
102 });
103 }
104 SortMode::DirsFirst => {
105 entries.sort_by(|a, b| {
106 let ak = kind_rank(a.kind);
107 let bk = kind_rank(b.kind);
108 ak.cmp(&bk)
109 .then_with(|| a.path.to_string_lossy().cmp(&b.path.to_string_lossy()))
110 });
111 }
112 }
113}
114
115fn kind_rank(kind: EntryKind) -> u8 {
116 match kind {
117 EntryKind::Directory => 0,
118 EntryKind::File => 1,
119 EntryKind::Symlink => 2,
120 EntryKind::Other => 3,
121 }
122}