iced_swdir_tree/directory_tree/error.rs
1//! Crate-level error type.
2//!
3//! We wrap [`std::io::Error`] (via [`swdir::ScanError`]) in our own enum
4//! rather than re-exporting swdir's error so the public API stays
5//! self-contained and future-flexible. In particular, cloning is required
6//! because iced messages are `Clone` — and `std::io::Error` is not
7//! `Clone`, so we carry the [`io::ErrorKind`] and a formatted message
8//! instead of the live error object.
9
10use std::io;
11use std::path::{Path, PathBuf};
12
13/// Everything the widget can fail at.
14///
15/// `Clone` is implemented because iced messages flow across channels
16/// and must be cloneable. The originating [`io::Error`] cannot be
17/// cloned, so we preserve its [`io::ErrorKind`] and its formatted
18/// message instead.
19#[derive(Debug, Clone)]
20pub enum Error {
21 /// An I/O error surfaced while scanning a directory.
22 ///
23 /// `path` is always the path the error refers to (the directory
24 /// being scanned, or a specific child entry).
25 Io {
26 /// Path the error occurred on.
27 path: PathBuf,
28 /// Kind of the underlying [`io::Error`] (e.g. `NotFound`,
29 /// `PermissionDenied`).
30 kind: io::ErrorKind,
31 /// Human-readable rendering of the original I/O error.
32 message: String,
33 },
34}
35
36impl Error {
37 /// Construct an [`Error::Io`] from the pieces of a failed scan.
38 pub(crate) fn io(path: impl Into<PathBuf>, kind: io::ErrorKind, message: String) -> Self {
39 Self::Io {
40 path: path.into(),
41 kind,
42 message,
43 }
44 }
45
46 /// Path associated with this error, if any.
47 pub fn path(&self) -> &Path {
48 match self {
49 Self::Io { path, .. } => path,
50 }
51 }
52
53 /// [`io::ErrorKind`] of the underlying I/O failure.
54 pub fn io_kind(&self) -> io::ErrorKind {
55 match self {
56 Self::Io { kind, .. } => *kind,
57 }
58 }
59
60 /// `true` if the error is a permission-denied failure — the widget
61 /// uses this to gray out the offending directory in the view.
62 pub fn is_permission_denied(&self) -> bool {
63 self.io_kind() == io::ErrorKind::PermissionDenied
64 }
65}
66
67impl std::fmt::Display for Error {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 match self {
70 Self::Io { path, message, .. } => {
71 write!(f, "I/O error at {}: {}", path.display(), message)
72 }
73 }
74 }
75}
76
77impl std::error::Error for Error {}
78
79/// Convert a [`swdir::ScanError`] into our crate error.
80///
81/// Kept private to keep swdir's types out of our public API.
82impl From<&swdir::ScanError> for Error {
83 fn from(e: &swdir::ScanError) -> Self {
84 Self::io(e.path(), e.io_kind(), e.to_string())
85 }
86}