win_open/error.rs
1/// Enum representing various types of errors that may occur in a shell operation.
2#[derive(Debug, PartialEq)]
3#[allow(non_camel_case_types)] // To allow the use of all-uppercase error kind variants
4pub enum ErrorKind {
5 /// Error indicating that a shell type was not found or recognized.
6 SHELL_NOT_FOUND,
7
8 /// Error indicating that a command execution failed.
9 COMMAND_FAILED,
10
11 /// Error indicating that no valid launcher was found.
12 NO_LAUNCHER,
13
14 /// Error indicating an I/O operation failure.
15 IO,
16}
17
18/// A struct representing an error in shell operations.
19/// It includes the type of the error (`ErrorKind`) and an optional message.
20pub struct Error {
21 kind: ErrorKind, // The type of the error (e.g., I/O, command failure)
22 message: String, // An optional message describing the error
23}
24
25impl PartialEq for Error {
26 /// Compares two `Error` instances for equality based on their kind.
27 ///
28 /// # Parameters
29 /// - `self`: The first `Error` instance.
30 /// - `other`: The second `Error` instance.
31 ///
32 /// # Returns
33 /// `true` if both errors have the same kind, `false` otherwise.
34 fn eq(&self, other: &Self) -> bool {
35 self.kind == other.kind
36 }
37}
38
39impl Eq for Error {} // `Error` instances can be compared for equality using the `==` operator.
40
41impl Error {
42 /// Creates a new `Error` instance with a specified kind and an optional message.
43 /// If the message is empty, it will use an empty message for the error.
44 ///
45 /// # Parameters
46 /// - `kind`: The type of error (e.g., `IO`, `SHELL_NOT_FOUND`).
47 /// - `message`: A message describing the error. This can be an empty string.
48 ///
49 /// # Returns
50 /// A new `Error` instance with the specified error kind and message.
51 pub fn new<T: AsRef<str>>(kind: ErrorKind, message: T) -> Self {
52 let message: &str = message.as_ref();
53 if message.is_empty() {
54 Self::empty_message(kind)
55 } else {
56 Self {
57 kind,
58 message: message.to_string(),
59 }
60 }
61 }
62
63 /// Creates a new `Error` instance with the specified error kind and an empty message.
64 ///
65 /// # Parameters
66 /// - `kind`: The type of error (e.g., `IO`, `SHELL_NOT_FOUND`).
67 ///
68 /// # Returns
69 /// A new `Error` instance with an empty message for the specified error kind.
70 fn empty_message(kind: ErrorKind) -> Self {
71 Self {
72 kind,
73 message: "".to_string(),
74 }
75 }
76
77 /// Retrieves the kind of the error.
78 ///
79 /// # Returns
80 /// A reference to the `ErrorKind` variant that represents the type of error.
81 pub const fn kind(&self) -> &ErrorKind {
82 &self.kind
83 }
84
85 /// Retrieves the error message, if provided.
86 ///
87 /// # Returns
88 /// The error message as a string slice. If no message is provided, an empty string is returned.
89 pub fn message(&self) -> &str {
90 self.message.as_str()
91 }
92}
93
94impl core::fmt::Display for ErrorKind {
95 /// Formats the `ErrorKind` enum into a human-readable string for display purposes.
96 ///
97 /// This is used when the error kind is displayed directly (e.g., in an error message).
98 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
99 match self {
100 ErrorKind::SHELL_NOT_FOUND => {
101 write!(f, "Unrecognized shell type")
102 }
103 ErrorKind::COMMAND_FAILED => {
104 write!(f, "Command failed")
105 }
106 ErrorKind::NO_LAUNCHER => {
107 write!(f, "No launcher worked")
108 }
109 ErrorKind::IO => {
110 write!(f, "IO Error")
111 }
112 }
113 }
114}
115
116impl core::fmt::Debug for Error {
117 /// Formats the `Error` struct for debugging.
118 ///
119 /// This method provides a detailed output of the error kind and the associated message,
120 /// which is useful for debugging purposes.
121 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
122 let mut debug = fmt.debug_struct("Error");
123 debug
124 .field("kind", &self.kind())
125 .field("message", &self.message())
126 .finish()
127 }
128}
129
130impl core::fmt::Display for Error {
131 /// Formats the `Error` struct for user-facing display.
132 ///
133 /// If a message is provided, it includes the message along with the error kind.
134 /// If no message is provided, only the error kind is displayed.
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 if self.message().is_empty() {
137 write!(f, "{}", self.kind)
138 } else {
139 write!(f, "{} ({})", self.kind, self.message)
140 }
141 }
142}
143
144impl From<std::io::Error> for Error {
145 /// Converts a `std::io::Error` into an `Error` with the `IO` error kind and the error message.
146 ///
147 /// This allows for easy conversion from I/O errors (e.g., file or network errors) to our custom `Error` type.
148 ///
149 /// # Parameters
150 /// - `err`: A `std::io::Error` instance that we want to convert.
151 ///
152 /// # Returns
153 /// A new `Error` instance with the `IO` error kind and the I/O error message.
154 fn from(err: std::io::Error) -> Self {
155 Self::new(ErrorKind::IO, err.to_string().as_str())
156 }
157}
158
159impl std::error::Error for Error {} // Implements the standard error trait for compatibility with other error handling mechanisms.
160
161/// A custom `Result` type that returns `Error` in case of failure.
162///
163/// This type is used for handling errors related to shell operations. It wraps the standard `Result` type but replaces the error type with our custom `Error` type.
164pub type Result<T> = core::result::Result<T, Error>;