1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Low-level single-directory scan API.
//!
//! This module is the crate's **lazy-loading entry point**. Use it when
//! a GUI's directory tree widget needs one folder's direct children at a
//! time, rather than a full recursive walk — see [`scan_dir`] and
//! [`scan_dir_with_options`].
//!
//! For recursive traversals, use [`crate::Swdir::walk`] instead.
use fs;
use Path;
use crateDirEntry;
use crateScanError;
use crate;
/// Scan a single directory non-recursively and return its direct entries,
/// in the order the OS's `readdir` yields them.
///
/// This is the low-level counterpart to [`crate::Swdir::walk`]: it scans
/// exactly one level of `path` and hands back a `Vec<DirEntry>`. It
/// exists for GUI / lazy-loading use cases — for example, an iced tree
/// view that expands one node at a time, fetching only what the user
/// actually opens.
///
/// This function intentionally does *no* ordering. If the GUI wants a
/// predictable display order (dirs first, then files, alphabetically),
/// call [`scan_dir_with_options`] instead.
///
/// # Properties
///
/// * **Non-recursive.** Subdirectories are listed but not descended into.
/// * **No filtering, no sorting.** Callers decide how to order/filter;
/// order of the returned `Vec` is whatever the OS's `readdir` returns.
/// * **No parallelism.** A single directory listing is I/O-bound; the
/// rayon overhead is not justified here.
/// * **No async.** Callers wanting off-thread execution should wrap this
/// with `std::thread::spawn` (or a runtime's blocking pool). Keeping
/// this sync means the crate stays runtime-independent.
/// * **Atomic.** Returns `Err` on the first I/O failure — either from
/// `read_dir` itself or from reading an entry's file type. Partial
/// results are not produced.
///
/// # Errors
///
/// Returns [`ScanError::Io`] wrapping the original [`std::io::Error`]
/// together with the offending [`std::path::PathBuf`]. Notable cases:
///
/// * `path` does not exist → `NotFound`
/// * `path` is a file, not a directory → `NotADirectory` (on Unix)
/// * permission denied reading the directory → `PermissionDenied`
/// * permission denied on a child's metadata → `PermissionDenied`
///
/// Empty directories are *not* errors; they return `Ok(Vec::new())`, so
/// callers can cleanly distinguish "nothing here" from "couldn't look".
///
/// # Thread-safety
///
/// The returned `Vec<DirEntry>` is `'static + Send`, safe to move to
/// another thread.
///
/// # Example
///
/// ```no_run
/// use std::path::Path;
/// use swdir::scan_dir;
///
/// let entries = scan_dir(Path::new("."))?;
/// for entry in &entries {
/// println!("{} (dir = {})", entry.path().display(), entry.is_dir());
/// }
/// # Ok::<(), swdir::ScanError>(())
/// ```
///
/// # Example — iced lazy loading
///
/// ```ignore
/// use std::path::PathBuf;
/// use iced::Task;
/// use swdir::{DirEntry, ScanError, scan_dir};
///
/// # enum Message { Loaded(Result<Vec<DirEntry>, ScanError>) }
/// fn load(path: PathBuf) -> Task<Message> {
/// Task::perform(
/// async move {
/// // Delegate the blocking call to a worker thread so the
/// // iced runtime keeps ticking.
/// std::thread::spawn(move || scan_dir(&path))
/// .join()
/// .expect("scan_dir panicked (should not happen)")
/// },
/// Message::Loaded,
/// )
/// }
/// ```
/// Scan a single directory non-recursively and return its direct entries,
/// ordered per [`ScanOptions::sort_order`].
///
/// Same contract as [`scan_dir`] for everything except ordering. GUI
/// callers should prefer this entry point: the default
/// [`ScanOptions::default()`] yields [`SortOrder::NameAscDirsFirst`],
/// the layout most tree widgets expect.
///
/// Sorting happens after the directory has been fully read, so it
/// introduces **no extra syscalls** on top of `scan_dir` — only a
/// single in-memory `Vec::sort_by` pass.
///
/// # Example
///
/// ```no_run
/// use std::path::Path;
/// use swdir::{ScanOptions, SortOrder, scan_dir_with_options};
///
/// let opts = ScanOptions::new(SortOrder::NameAscDirsFirst);
/// let entries = scan_dir_with_options(Path::new("."), &opts)?;
/// # Ok::<(), swdir::ScanError>(())
/// ```
/// The shared read-entries body. Pulled out so the two public entry
/// points don't drift in their I/O handling.