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
//! Pluggable executor for blocking directory scans.
//!
//! [`ScanExecutor`] is the seam between the widget and whatever
//! runtime the host application is built on. By default the widget
//! uses [`ThreadExecutor`] (one `std::thread::spawn` per expansion),
//! which is correct but slightly wasteful for apps that already have
//! a blocking-task pool — tokio, smol, rayon, etc. Those apps can
//! implement this trait to route scans through their own pool.
//!
//! # Why a trait, not a feature flag
//!
//! Runtimes vary in their "how do I run blocking work" API, and
//! hard-coding any one of them would shut out the others. A trait
//! lets each application plug in exactly what fits — with zero
//! default dependencies on tokio, smol, or similar.
//!
//! # Example — tokio
//!
//! ```ignore
//! use std::sync::Arc;
//! use std::future::Future;
//! use std::pin::Pin;
//! use std::path::Path;
//! use iced_swdir_tree::{ScanExecutor, DirectoryTree};
//!
//! struct TokioExecutor;
//!
//! impl ScanExecutor for TokioExecutor {
//! fn spawn_blocking(
//! &self,
//! job: Box<dyn FnOnce() -> Result<Vec<swdir::DirEntry>, swdir::ScanError> + Send>,
//! ) -> Pin<Box<dyn Future<Output = Result<Vec<swdir::DirEntry>, swdir::ScanError>> + Send>> {
//! Box::pin(async move {
//! tokio::task::spawn_blocking(job)
//! .await
//! .expect("scan task panicked")
//! })
//! }
//! }
//!
//! let tree = DirectoryTree::new("/".into())
//! .with_executor(Arc::new(TokioExecutor));
//! ```
use Future;
use ;
use Pin;
use Arc;
/// The job passed to a [`ScanExecutor`] — always just "call
/// `swdir::scan_dir` on this path".
///
/// We pre-bake the path into the closure rather than exposing a
/// "scan this path" method on the trait, because trait methods
/// returning boxed futures must take a `'static` closure argument,
/// and smuggling the path via capture is the cleanest way to do that.
///
/// Kept as a type alias so the trait signature reads at a glance.
pub type ScanJob =
;
/// The future that runs a [`ScanJob`] to completion.
///
/// `Send + 'static` because the widget hands this off to
/// `iced::Task::perform`, which requires both.
pub type ScanFuture =
;
/// A pluggable executor for blocking `scan_dir` calls.
///
/// Applications that already manage a blocking-task pool can
/// implement this to route tree expansions through it instead of
/// spinning up a new `std::thread` per scan.
///
/// Implementors should ensure the returned future resolves once the
/// job has actually run — cancelling or losing the job will leave
/// the widget stuck in "loading" forever (`is_loaded` never flips
/// to `true` for the affected directory).
///
/// The widget holds the executor behind an `Arc`, so an impl that
/// owns any shared state should wrap it in an `Arc` internally or
/// store only `Send + Sync` references.
/// Default executor — one `std::thread::spawn` per scan.
///
/// This is what the widget uses if you never call
/// [`DirectoryTree::with_executor`](crate::DirectoryTree::with_executor).
/// It is completely runtime-agnostic: no tokio, no smol, no async.
///
/// Thread-spawn overhead is on the order of tens of microseconds —
/// usually negligible next to the `readdir` syscall the thread is
/// about to do — so this is a reasonable default even for apps
/// that could plug in something fancier.
;
/// Convenience helper: run `path` through `executor` and get a future
/// of the scan result.
///
/// Crate-internal; used by the walker to keep the async plumbing in
/// one place regardless of executor choice.
pub