qsu/
err.rs

1use std::{fmt, io};
2
3#[derive(Debug)]
4pub enum ArgsError {
5  #[cfg(feature = "clap")]
6  Clap(clap::Error),
7  Msg(String)
8}
9
10/// Indicate failure for server applicatino callbacks.
11#[derive(Debug, Default)]
12pub struct AppErrors<ApEr> {
13  pub init: Option<ApEr>,
14  pub run: Option<ApEr>,
15  pub shutdown: Option<ApEr>
16}
17
18impl<ApEr> AppErrors<ApEr> {
19  pub const fn init_failed(&self) -> bool {
20    self.init.is_some()
21  }
22
23  pub const fn run_failed(&self) -> bool {
24    self.run.is_some()
25  }
26
27  pub const fn shutdown_failed(&self) -> bool {
28    self.shutdown.is_some()
29  }
30}
31
32
33/// Errors that can be returned from functions that call application callbacks.
34#[derive(Debug)]
35#[allow(clippy::module_name_repetitions)]
36pub enum CbErr<ApEr> {
37  /// An qsu library error was generated.
38  Lib(Error),
39
40  /// Application-defined error.
41  ///
42  /// Applications can use this variant to pass application-specific errors
43  /// through the runtime back to itself.
44  App(ApEr),
45
46  /// Returned by [`RunCtx::run()`](crate::rt::RunCtx) to indicate which
47  /// server application callbacks that failed.
48  #[cfg(feature = "rt")]
49  #[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
50  SrvApp(AppErrors<ApEr>)
51}
52
53impl<ApEr: fmt::Debug> std::error::Error for CbErr<ApEr> {}
54
55impl<ApEr> fmt::Display for CbErr<ApEr> {
56  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57    match self {
58      Self::Lib(e) => e.fmt(f),
59      Self::App(_ae) => {
60        // ToDo: Add ApErr: Error bound and forward the call to it
61        write!(f, "Application-defined error")
62      }
63      #[cfg(feature = "rt")]
64      Self::SrvApp(e) => {
65        let mut v = vec![];
66        if e.init.is_some() {
67          v.push("init");
68        }
69        if e.run.is_some() {
70          v.push("run");
71        }
72        if e.shutdown.is_some() {
73          v.push("shutdown");
74        }
75        write!(f, "Server application failed [{}]", v.join(","))
76      }
77    }
78  }
79}
80
81impl<ApEr> CbErr<ApEr> {
82  /// Extract application-specific error.
83  ///
84  /// # Panics
85  /// The error must be [`CbErr::App`] of this method will panic.
86  pub fn unwrap_apperr(self) -> ApEr {
87    let Self::App(ae) = self else {
88      panic!("Not CbErr::App()");
89    };
90    ae
91  }
92}
93
94impl<ApEr> From<Error> for CbErr<ApEr> {
95  fn from(err: Error) -> Self {
96    Self::Lib(err)
97  }
98}
99
100#[cfg(feature = "rocket")]
101impl<ApEr> From<rocket::Error> for CbErr<ApEr> {
102  fn from(err: rocket::Error) -> Self {
103    Self::Lib(Error::Rocket(err.to_string()))
104  }
105}
106
107impl<ApEr> From<std::io::Error> for CbErr<ApEr> {
108  fn from(err: std::io::Error) -> Self {
109    Self::Lib(Error::IO(err.to_string()))
110  }
111}
112
113
114/// Errors that qsu will return to application.
115#[derive(Debug)]
116pub enum Error {
117  ArgP(ArgsError),
118  BadFormat(String),
119  Internal(String),
120  IO(String),
121
122  /// An error related to logging occurred.
123  ///
124  /// This includes both initialization and actual logging.
125  ///
126  /// On Windows errors such as failure to register an event source will be
127  /// treated as this error variant as well.
128  LumberJack(String),
129
130  /// Missing expected data.
131  Missing(String),
132
133  /// Rocket-specific errors.
134  #[cfg(feature = "rocket")]
135  #[cfg_attr(docsrs, doc(cfg(feature = "rocket")))]
136  Rocket(String),
137  SubSystem(String),
138
139  Unsupported
140}
141
142
143#[allow(clippy::needless_pass_by_value)]
144impl Error {
145  pub fn bad_format(s: impl ToString) -> Self {
146    Self::BadFormat(s.to_string())
147  }
148
149  pub fn internal(s: impl ToString) -> Self {
150    Self::Internal(s.to_string())
151  }
152
153  pub fn io(s: impl ToString) -> Self {
154    Self::IO(s.to_string())
155  }
156
157  pub fn lumberjack(s: impl ToString) -> Self {
158    Self::LumberJack(s.to_string())
159  }
160
161  pub fn missing(s: impl ToString) -> Self {
162    Self::Missing(s.to_string())
163  }
164}
165
166
167impl std::error::Error for Error {}
168
169impl fmt::Display for Error {
170  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171    match self {
172      Self::ArgP(s) => {
173        // ToDo: Handle the ArgsError::Clap and ArgsError::Msg differently
174        write!(f, "Argument parser; {s:?}")
175      }
176      Self::BadFormat(s) => write!(f, "Bad format error; {s}"),
177      Self::Internal(s) => write!(f, "Internal error; {s}"),
178      Self::IO(s) => write!(f, "I/O error; {s}"),
179      Self::LumberJack(s) => write!(f, "LumberJack error; {s}"),
180      Self::Missing(s) => write!(f, "Missing data; {s}"),
181      #[cfg(feature = "rocket")]
182      Self::Rocket(s) => write!(f, "Rocket error; {s}"),
183      Self::SubSystem(s) => write!(f, "Service subsystem error; {s}"),
184      Self::Unsupported => {
185        write!(f, "Operation is unsupported [on this platform]")
186      }
187    }
188  }
189}
190
191/*
192#[cfg(feature = "clap")]
193impl From<clap::error::Error> for Error {
194  fn from(err: clap::error::Error) -> Self {
195    Error::ArgP(err.to_string())
196  }
197}
198*/
199
200
201#[cfg(windows)]
202impl From<eventlog::InitError> for Error {
203  /// Map eventlog initialization errors to `Error::LumberJack`.
204  fn from(err: eventlog::InitError) -> Self {
205    Self::LumberJack(err.to_string())
206  }
207}
208
209#[cfg(windows)]
210impl From<eventlog::Error> for Error {
211  /// Map eventlog errors to `Error::LumberJack`.
212  fn from(err: eventlog::Error) -> Self {
213    Self::LumberJack(err.to_string())
214  }
215}
216
217impl From<io::Error> for Error {
218  fn from(err: io::Error) -> Self {
219    Self::IO(err.to_string())
220  }
221}
222
223#[cfg(windows)]
224impl From<registry::key::Error> for Error {
225  fn from(err: registry::key::Error) -> Self {
226    Self::SubSystem(err.to_string())
227  }
228}
229
230#[cfg(feature = "rocket")]
231impl From<rocket::Error> for Error {
232  fn from(err: rocket::Error) -> Self {
233    Self::Rocket(err.to_string())
234  }
235}
236
237#[cfg(feature = "installer")]
238impl From<sidoc::Error> for Error {
239  fn from(err: sidoc::Error) -> Self {
240    Self::Internal(err.to_string())
241  }
242}
243
244#[cfg(windows)]
245impl From<windows_service::Error> for Error {
246  fn from(err: windows_service::Error) -> Self {
247    Self::SubSystem(err.to_string())
248  }
249}
250
251#[cfg(windows)]
252impl<ApEr> From<windows_service::Error> for CbErr<ApEr> {
253  fn from(err: windows_service::Error) -> Self {
254    Self::Lib(Error::SubSystem(err.to_string()))
255  }
256}
257
258
259/*
260impl<ApEr> From<ApEr> for Error<ApEr> {
261  /// Wrap an [`AppErr`] in an [`Error`].
262  fn from(err: ApEr) -> Self {
263    Error::App(err)
264  }
265}
266*/
267
268// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :