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
//! Low-level single-directory scan API.
//!
//! See [`scan_dir`].
use fs;
use Path;
use crateDirEntry;
use crateScanError;
/// Scan a single directory non-recursively and return its direct entries.
///
/// 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 (e.g. iced tree views that expand one
/// node at a time).
///
/// # 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,
/// )
/// }
/// ```