add_ed/io/local_io/
error.rs

1use std::io::ErrorKind;
2
3/// Error type for [`LocalIO`]
4#[derive(Debug)]
5pub enum LocalIOError {
6  /// Empty path given, which is invalid
7  NoPath,
8  /// Permission denied when performing current operation on path.
9  #[allow(missing_docs)]
10  FilePermissionDenied{path: String},
11  /// Path not found. May be failing to read file at path, or the directory to
12  /// create a file in doesn't exist.
13  #[allow(missing_docs)]
14  FileNotFound{path: String},
15  /// More general failure to perform file operation on path, as std::io::Error
16  /// doesn't report all the details in a reasonably accessible way.
17  #[allow(missing_docs)]
18  FileIOFailed{path: String, error: std::io::Error},
19  /// The child thread running the shell command couldn't be created.
20  ChildCreationFailed(std::io::Error),
21  /// The child thread running the shell command failed to begin execution.
22  ChildFailedToStart(std::io::Error),
23  /// The child thread running a shell command returned a non-zero integer
24  /// (Shells run with `-c` will return this if given command wasn't found)
25  ChildReturnedError(i32),
26  /// The child thread running a shell command was killed by a signal
27  ChildKilledBySignal,
28  /// Error occured in the child thread handling piping
29  ChildPipingError,
30   /// Failed to convert data read from file or command into UTF8
31  BadUtf8(std::string::FromUtf8Error),
32}
33impl LocalIOError {
34  pub(super) fn file_error(path: &str, error: std::io::Error) -> Self {
35    let path = path.to_owned();
36    match error.kind() {
37      ErrorKind::PermissionDenied => Self::FilePermissionDenied{path},
38      ErrorKind::NotFound => Self::FileNotFound{path},
39      _ => Self::FileIOFailed{path, error},
40    }
41  }
42  pub(super) fn child_return_res(ret: Option<i32>) -> Self {
43    match ret {
44      Some(retval) => Self::ChildReturnedError(retval),
45      None => Self::ChildKilledBySignal,
46    }
47  }
48}
49
50impl std::error::Error for LocalIOError {}
51impl crate::error::IOErrorTrait for LocalIOError {}
52
53impl std::fmt::Display for LocalIOError {
54  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
55    match self {
56      Self::NoPath => { write!(f,
57        "Path must not be empty when performing file interactions."
58      )},
59      Self::FilePermissionDenied{path} => { write!(f,
60        "Permission denied, could not open file `{}`",
61        path,
62      )},
63      Self::FileNotFound{path} => { write!(f,
64        "Not found, could not open file `{}`",
65        path,
66      )},
67      Self::FileIOFailed{path, error} => { write!(f,
68        "Unknown error, could not open file `{}`.\nUnderlying error: {}",
69        path,
70        error,
71      )},
72      Self::ChildCreationFailed(e) => { write!(f,
73        "Failed to create shell process.\nUnderlying error: {}",
74        e,
75      )},
76      Self::ChildFailedToStart(e) => { write!(f,
77        "Failed to start shell process.\nUnderlying error: {}",
78        e,
79      )},
80      Self::ChildReturnedError(ret) => { write!(f,
81        "Shell process returned non-success result: {}\n{}",
82        ret,
83        "OBS! This is the result when a shell couldn't find a command."
84      )},
85      Self::ChildKilledBySignal => { write!(f,
86        "Shell process was killed by a signal.",
87      )},
88      Self::ChildPipingError => { write!(f,
89        "Error while piping data.",
90      )},
91      Self::BadUtf8(e) => { write!(f,
92        "Bad UTF-8 in read data.\nUnderlying error: {}",
93        e,
94      )},
95    }
96  }
97}
98
99impl std::cmp::PartialEq for LocalIOError {
100  fn eq(&self, other: &Self) -> bool {
101    use LocalIOError::*;
102    match (self, other) {
103      (FilePermissionDenied{path: a},FilePermissionDenied{path: b}) => a == b,
104      (FileNotFound{path: a},FileNotFound{path: b}) => a == b,
105      (ChildReturnedError(a),ChildReturnedError(b)) => a == b,
106      (ChildKilledBySignal,ChildKilledBySignal) => true,
107      (ChildPipingError,ChildPipingError) => true,
108      (BadUtf8(a),BadUtf8(b)) => a == b,
109      // std::io::Error doesn't implement PartialEq, so we check the ErrorKind
110      (FileIOFailed{path: a, error: b},FileIOFailed{path: c, error: d}) =>
111        a == c && b.kind() == d.kind()
112      ,
113      (ChildCreationFailed(a),ChildCreationFailed(b)) => a.kind() == b.kind(),
114      (ChildFailedToStart(a),ChildFailedToStart(b)) => a.kind() == b.kind(),
115      _ => false,
116    }
117  }
118}