fast_fs/models/
cls_file_list.rs

1// <FILE>crates/fast-fs/src/models/cls_file_list.rs</FILE> - <DESC>FileList struct</DESC>
2// <VERS>VERSION: 0.2.0 - 2025-12-07T16:58:06Z</VERS>
3// <WCTX>Renamed from files.rs</WCTX>
4// <CLOG>Moved to models/cls_file_list.rs</CLOG>
5
6//! Versioned file list with deferred sorting
7use crate::models::cls_file_entry::FileEntry;
8use crate::models::cls_sort_by::SortBy;
9use std::ops::{Deref, DerefMut};
10/// A versioned file list with deferred sorting
11#[derive(Debug, Default)]
12pub struct FileList {
13    items: Vec<FileEntry>,
14    hidden: Vec<FileEntry>,
15    /// Incremented on every modification
16    revision: u64,
17    /// Last sorted revision
18    version: u64,
19    sort_by: SortBy,
20    show_hidden: bool,
21}
22impl Deref for FileList {
23    type Target = Vec<FileEntry>;
24    fn deref(&self) -> &Self::Target {
25        &self.items
26    }
27}
28impl DerefMut for FileList {
29    fn deref_mut(&mut self) -> &mut Self::Target {
30        self.revision += 1;
31        &mut self.items
32    }
33}
34impl FileList {
35    /// Create a new empty file list
36    pub fn new() -> Self {
37        Self::default()
38    }
39    /// Create a file list from entries
40    pub fn from_entries(entries: Vec<FileEntry>) -> Self {
41        let mut list = Self::new();
42        list.update_full(entries);
43        list
44    }
45    /// Replace all entries
46    pub fn update_full(&mut self, entries: Vec<FileEntry>) {
47        self.revision += 1;
48        if self.show_hidden {
49            self.items = entries;
50            self.hidden.clear();
51        } else {
52            let (hidden, visible): (Vec<_>, Vec<_>) =
53                entries.into_iter().partition(|e| e.is_hidden);
54            self.items = visible;
55            self.hidden = hidden;
56        }
57    }
58    /// Add entries to the list
59    pub fn push_batch(&mut self, entries: Vec<FileEntry>) {
60        self.revision += 1;
61        if self.show_hidden {
62            self.items.extend(entries);
63        } else {
64            for entry in entries {
65                if entry.is_hidden {
66                    self.hidden.push(entry);
67                } else {
68                    self.items.push(entry);
69                }
70            }
71        }
72    }
73    /// Check if sorting is needed and perform it
74    pub fn catchup(&mut self) -> bool {
75        if self.version == self.revision {
76            return false;
77        }
78        self.version = self.revision;
79        self.sort_items();
80        true
81    }
82    /// Set the sort order
83    pub fn set_sort(&mut self, sort_by: SortBy) {
84        if self.sort_by != sort_by {
85            self.sort_by = sort_by;
86            self.revision += 1;
87        }
88    }
89    /// Toggle hidden file visibility
90    pub fn set_show_hidden(&mut self, show: bool) {
91        if self.show_hidden == show {
92            return;
93        }
94        self.show_hidden = show;
95        self.revision += 1;
96        if show {
97            self.items.append(&mut self.hidden);
98        } else {
99            let items = std::mem::take(&mut self.items);
100            let (hidden, visible): (Vec<_>, Vec<_>) = items.into_iter().partition(|e| e.is_hidden);
101            self.items = visible;
102            self.hidden = hidden;
103        }
104    }
105    /// Get the current revision number (incremented on each mutation)
106    pub fn revision(&self) -> u64 {
107        self.revision
108    }
109
110    /// Check if the list needs sorting (deferred sort pending)
111    pub fn needs_sort(&self) -> bool {
112        self.version != self.revision
113    }
114
115    /// Get the current sort order
116    pub fn sort_by(&self) -> SortBy {
117        self.sort_by
118    }
119
120    /// Get the count of hidden files (not in visible list)
121    pub fn hidden_count(&self) -> usize {
122        self.hidden.len()
123    }
124    fn sort_items(&mut self) {
125        match self.sort_by {
126            SortBy::Name => {
127                self.items
128                    .sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
129            }
130            SortBy::NameDesc => {
131                self.items
132                    .sort_by(|a, b| b.name.to_lowercase().cmp(&a.name.to_lowercase()));
133            }
134            SortBy::Size => {
135                self.items.sort_by_key(|e| e.size);
136            }
137            SortBy::SizeDesc => {
138                self.items.sort_by(|a, b| b.size.cmp(&a.size));
139            }
140            SortBy::Modified => {
141                self.items.sort_by_key(|e| e.modified);
142            }
143            SortBy::ModifiedDesc => {
144                self.items.sort_by(|a, b| b.modified.cmp(&a.modified));
145            }
146            SortBy::Extension => {
147                self.items.sort_by(|a, b| {
148                    let ext_cmp = a.extension().cmp(&b.extension());
149                    if ext_cmp == std::cmp::Ordering::Equal {
150                        a.name.to_lowercase().cmp(&b.name.to_lowercase())
151                    } else {
152                        ext_cmp
153                    }
154                });
155            }
156            SortBy::DirsFirst => {
157                self.items.sort_by(|a, b| match (a.is_dir, b.is_dir) {
158                    (true, false) => std::cmp::Ordering::Less,
159                    (false, true) => std::cmp::Ordering::Greater,
160                    _ => a.name.to_lowercase().cmp(&b.name.to_lowercase()),
161                });
162            }
163        }
164    }
165}
166
167// <FILE>crates/fast-fs/src/models/cls_file_list.rs</FILE> - <DESC>FileList struct</DESC>
168// <VERS>END OF VERSION: 0.2.0 - 2025-12-07T16:58:06Z</VERS>