1use std::error::Error;
10use std::fmt;
11
12pub type Result<T> = std::result::Result<T, StatusCode>;
14
15const UNKNOWN_ERROR: i32 = -2147483647 - 1;
16
17#[derive(Default, Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
22#[non_exhaustive]
23pub enum StatusCode {
24 #[default]
26 Ok,
27 Unknown,
29 NoMemory,
31 InvalidOperation,
33 BadValue,
35 BadType,
37 NameNotFound,
39 PermissionDenied,
41 NoInit,
43 AlreadyExists,
45 DeadObject,
47 FailedTransaction,
49 UnknownTransaction,
51 BadIndex,
53 FdsNotAllowed,
55 UnexpectedNull,
57 NotEnoughData,
59 WouldBlock,
61 TimedOut,
63 BadFd,
65 Errno(i32),
67 ServiceSpecific(i32),
69}
70
71impl Error for StatusCode {}
72
73impl fmt::Display for StatusCode {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 match self {
76 StatusCode::Ok => write!(f, "Ok"),
77 StatusCode::Unknown => write!(f, "Unknown"),
78 StatusCode::NoMemory => write!(f, "NoMemory"),
79 StatusCode::InvalidOperation => write!(f, "InvalidOperation"),
80 StatusCode::BadValue => write!(f, "BadValue"),
81 StatusCode::BadType => write!(f, "BadType"),
82 StatusCode::NameNotFound => write!(f, "NameNotFound"),
83 StatusCode::PermissionDenied => write!(f, "PermissionDenied"),
84 StatusCode::NoInit => write!(f, "NoInit"),
85 StatusCode::AlreadyExists => write!(f, "AlreadyExists"),
86 StatusCode::DeadObject => write!(f, "DeadObject"),
87 StatusCode::FailedTransaction => write!(f, "FailedTransaction"),
88 StatusCode::UnknownTransaction => write!(f, "UnknownTransaction"),
89 StatusCode::BadIndex => write!(f, "BadIndex"),
90 StatusCode::FdsNotAllowed => write!(f, "FdsNotAllowed"),
91 StatusCode::UnexpectedNull => write!(f, "UnexpectedNull"),
92 StatusCode::NotEnoughData => write!(f, "NotEnoughData"),
93 StatusCode::WouldBlock => write!(f, "WouldBlock"),
94 StatusCode::TimedOut => write!(f, "TimedOut"),
95 StatusCode::BadFd => write!(f, "BadFd"),
96 StatusCode::Errno(errno) => write!(f, "Errno({errno})"),
97 StatusCode::ServiceSpecific(v) => write!(f, "ServiceSpecific({v})"),
98 }
99 }
100}
101
102impl From<StatusCode> for i32 {
103 fn from(code: StatusCode) -> Self {
104 match code {
105 StatusCode::Ok => 0,
106 StatusCode::Unknown => UNKNOWN_ERROR as _,
107 StatusCode::NoMemory => -(rustix::io::Errno::NOMEM.raw_os_error()),
108 StatusCode::InvalidOperation => -(rustix::io::Errno::NOSYS.raw_os_error()),
109 StatusCode::BadValue => -(rustix::io::Errno::INVAL.raw_os_error()),
110 StatusCode::BadType => UNKNOWN_ERROR + 1,
111 StatusCode::NameNotFound => -(rustix::io::Errno::NOENT.raw_os_error()),
112 StatusCode::PermissionDenied => -(rustix::io::Errno::PERM.raw_os_error()),
113 StatusCode::NoInit => -(rustix::io::Errno::NODEV.raw_os_error()),
114 StatusCode::AlreadyExists => -(rustix::io::Errno::EXIST.raw_os_error()),
115 StatusCode::DeadObject => -(rustix::io::Errno::PIPE.raw_os_error()),
116 StatusCode::FailedTransaction => UNKNOWN_ERROR + 2,
117 StatusCode::UnknownTransaction => -(rustix::io::Errno::BADMSG.raw_os_error()),
118 StatusCode::BadIndex => -(rustix::io::Errno::OVERFLOW.raw_os_error()),
119 StatusCode::FdsNotAllowed => UNKNOWN_ERROR + 7,
120 StatusCode::UnexpectedNull => UNKNOWN_ERROR + 8,
121 StatusCode::NotEnoughData => -(rustix::io::Errno::NODATA.raw_os_error()),
122 StatusCode::WouldBlock => -(rustix::io::Errno::WOULDBLOCK.raw_os_error()),
123 StatusCode::TimedOut => -(rustix::io::Errno::TIMEDOUT.raw_os_error()),
124 StatusCode::BadFd => -(rustix::io::Errno::BADF.raw_os_error()),
125 StatusCode::ServiceSpecific(v) => v,
126 StatusCode::Errno(errno) => errno,
127 }
128 }
129}
130
131impl From<i32> for StatusCode {
132 fn from(code: i32) -> Self {
133 match code {
134 code if code == StatusCode::Ok.into() => StatusCode::Ok,
135 code if code == StatusCode::Unknown.into() => StatusCode::Unknown,
136 code if code == StatusCode::NoMemory.into() => StatusCode::NoMemory,
137 code if code == StatusCode::InvalidOperation.into() => StatusCode::InvalidOperation,
138 code if code == StatusCode::BadValue.into() => StatusCode::BadValue,
139 code if code == StatusCode::BadType.into() => StatusCode::BadType,
140 code if code == StatusCode::NameNotFound.into() => StatusCode::NameNotFound,
141 code if code == StatusCode::PermissionDenied.into() => StatusCode::PermissionDenied,
142 code if code == StatusCode::NoInit.into() => StatusCode::NoInit,
143 code if code == StatusCode::AlreadyExists.into() => StatusCode::AlreadyExists,
144 code if code == StatusCode::DeadObject.into() => StatusCode::DeadObject,
145 code if code == StatusCode::FailedTransaction.into() => StatusCode::FailedTransaction,
146 code if code == StatusCode::UnknownTransaction.into() => StatusCode::UnknownTransaction,
147 code if code == StatusCode::BadIndex.into() => StatusCode::BadIndex,
148 code if code == StatusCode::FdsNotAllowed.into() => StatusCode::FdsNotAllowed,
149 code if code == StatusCode::UnexpectedNull.into() => StatusCode::UnexpectedNull,
150 code if code == StatusCode::NotEnoughData.into() => StatusCode::NotEnoughData,
151 code if code == StatusCode::WouldBlock.into() => StatusCode::WouldBlock,
152 code if code == StatusCode::TimedOut.into() => StatusCode::TimedOut,
153 code if code == StatusCode::BadFd.into() => StatusCode::BadFd,
154 code if code < 0 => StatusCode::Errno(code),
155 _ => StatusCode::ServiceSpecific(code),
156 }
157 }
158}
159
160impl From<std::array::TryFromSliceError> for StatusCode {
161 fn from(_: std::array::TryFromSliceError) -> Self {
162 StatusCode::NotEnoughData
163 }
164}
165
166impl From<std::io::Error> for StatusCode {
167 fn from(_: std::io::Error) -> Self {
168 StatusCode::BadFd
169 }
170}
171
172impl From<rustix::io::Errno> for StatusCode {
173 fn from(errno: rustix::io::Errno) -> Self {
174 match errno {
175 rustix::io::Errno::NOMEM => StatusCode::NoMemory,
176 rustix::io::Errno::NOSYS => StatusCode::InvalidOperation,
177 rustix::io::Errno::INVAL => StatusCode::BadValue,
178 rustix::io::Errno::NOENT => StatusCode::NameNotFound,
179 rustix::io::Errno::PERM => StatusCode::PermissionDenied,
180 rustix::io::Errno::NODEV => StatusCode::NoInit,
181 rustix::io::Errno::EXIST => StatusCode::AlreadyExists,
182 rustix::io::Errno::PIPE => StatusCode::DeadObject,
183 rustix::io::Errno::BADMSG => StatusCode::UnknownTransaction,
184 rustix::io::Errno::OVERFLOW => StatusCode::BadIndex,
185 rustix::io::Errno::NODATA => StatusCode::NotEnoughData,
186 rustix::io::Errno::WOULDBLOCK => StatusCode::WouldBlock,
187 rustix::io::Errno::TIMEDOUT => StatusCode::TimedOut,
188 rustix::io::Errno::BADF => StatusCode::BadFd,
189 _ => StatusCode::Errno(-errno.raw_os_error()),
190 }
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197
198 #[test]
199 fn test_status_code() {
200 let code = StatusCode::Ok;
201 assert_eq!(code, StatusCode::from(0));
202 assert_eq!(code, StatusCode::from(Into::<i32>::into(StatusCode::Ok)));
203
204 let code = StatusCode::Unknown;
205 assert_eq!(code, StatusCode::from(UNKNOWN_ERROR));
206 assert_eq!(
207 code,
208 StatusCode::from(Into::<i32>::into(StatusCode::Unknown))
209 );
210
211 let code = StatusCode::NoMemory;
212 assert_eq!(
213 code,
214 StatusCode::from(-(rustix::io::Errno::NOMEM.raw_os_error()))
215 );
216 assert_eq!(
217 code,
218 StatusCode::from(Into::<i32>::into(StatusCode::NoMemory))
219 );
220
221 let code = StatusCode::InvalidOperation;
222 assert_eq!(
223 code,
224 StatusCode::from(-(rustix::io::Errno::NOSYS.raw_os_error()))
225 );
226 assert_eq!(
227 code,
228 StatusCode::from(Into::<i32>::into(StatusCode::InvalidOperation))
229 );
230
231 let code = StatusCode::BadValue;
232 assert_eq!(
233 code,
234 StatusCode::from(-(rustix::io::Errno::INVAL.raw_os_error()))
235 );
236 assert_eq!(
237 code,
238 StatusCode::from(Into::<i32>::into(StatusCode::BadValue))
239 );
240
241 let code = StatusCode::BadType;
242 assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 1));
243 assert_eq!(
244 code,
245 StatusCode::from(Into::<i32>::into(StatusCode::BadType))
246 );
247
248 let code = StatusCode::NameNotFound;
249 assert_eq!(
250 code,
251 StatusCode::from(-(rustix::io::Errno::NOENT.raw_os_error()))
252 );
253 assert_eq!(
254 code,
255 StatusCode::from(Into::<i32>::into(StatusCode::NameNotFound))
256 );
257
258 let code = StatusCode::PermissionDenied;
259 assert_eq!(
260 code,
261 StatusCode::from(-(rustix::io::Errno::PERM.raw_os_error()))
262 );
263 assert_eq!(
264 code,
265 StatusCode::from(Into::<i32>::into(StatusCode::PermissionDenied))
266 );
267
268 let code = StatusCode::NoInit;
269 assert_eq!(
270 code,
271 StatusCode::from(-(rustix::io::Errno::NODEV.raw_os_error()))
272 );
273 assert_eq!(
274 code,
275 StatusCode::from(Into::<i32>::into(StatusCode::NoInit))
276 );
277
278 let code = StatusCode::AlreadyExists;
279 assert_eq!(
280 code,
281 StatusCode::from(-(rustix::io::Errno::EXIST.raw_os_error()))
282 );
283 assert_eq!(
284 code,
285 StatusCode::from(Into::<i32>::into(StatusCode::AlreadyExists))
286 );
287
288 let code = StatusCode::DeadObject;
289 assert_eq!(
290 code,
291 StatusCode::from(-(rustix::io::Errno::PIPE.raw_os_error()))
292 );
293 assert_eq!(
294 code,
295 StatusCode::from(Into::<i32>::into(StatusCode::DeadObject))
296 );
297
298 let code = StatusCode::FailedTransaction;
299 assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 2));
300 assert_eq!(
301 code,
302 StatusCode::from(Into::<i32>::into(StatusCode::FailedTransaction))
303 );
304
305 let code = StatusCode::UnknownTransaction;
306 assert_eq!(
307 code,
308 StatusCode::from(-(rustix::io::Errno::BADMSG.raw_os_error()))
309 );
310 assert_eq!(
311 code,
312 StatusCode::from(Into::<i32>::into(StatusCode::UnknownTransaction))
313 );
314
315 let code = StatusCode::BadIndex;
316 assert_eq!(
317 code,
318 StatusCode::from(-(rustix::io::Errno::OVERFLOW.raw_os_error()))
319 );
320 assert_eq!(
321 code,
322 StatusCode::from(Into::<i32>::into(StatusCode::BadIndex))
323 );
324
325 let code = StatusCode::FdsNotAllowed;
326 assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 7));
327 assert_eq!(
328 code,
329 StatusCode::from(Into::<i32>::into(StatusCode::FdsNotAllowed))
330 );
331
332 let code = StatusCode::UnexpectedNull;
333 assert_eq!(code, StatusCode::from(UNKNOWN_ERROR + 8));
334 assert_eq!(
335 code,
336 StatusCode::from(Into::<i32>::into(StatusCode::UnexpectedNull))
337 );
338
339 let code = StatusCode::NotEnoughData;
340 assert_eq!(
341 code,
342 StatusCode::from(-(rustix::io::Errno::NODATA.raw_os_error()))
343 );
344 assert_eq!(
345 code,
346 StatusCode::from(Into::<i32>::into(StatusCode::NotEnoughData))
347 );
348
349 let code = StatusCode::WouldBlock;
350 assert_eq!(
351 code,
352 StatusCode::from(-(rustix::io::Errno::WOULDBLOCK.raw_os_error()))
353 );
354 assert_eq!(
355 code,
356 StatusCode::from(Into::<i32>::into(StatusCode::WouldBlock))
357 );
358
359 let code = StatusCode::TimedOut;
360 assert_eq!(
361 code,
362 StatusCode::from(-(rustix::io::Errno::TIMEDOUT.raw_os_error()))
363 );
364 assert_eq!(
365 code,
366 StatusCode::from(Into::<i32>::into(StatusCode::TimedOut))
367 );
368
369 let code = StatusCode::BadFd;
370 assert_eq!(
371 code,
372 StatusCode::from(-(rustix::io::Errno::BADF.raw_os_error()))
373 );
374 assert_eq!(code, StatusCode::from(Into::<i32>::into(StatusCode::BadFd)));
375
376 let code = StatusCode::ServiceSpecific(1);
377 assert_eq!(code, StatusCode::from(1));
378 assert_eq!(
379 code,
380 StatusCode::from(Into::<i32>::into(StatusCode::ServiceSpecific(1)))
381 );
382
383 let code: StatusCode = StatusCode::Errno(-64);
384 assert_eq!(code, StatusCode::from(-64));
385 assert_eq!(
386 code,
387 StatusCode::from(Into::<i32>::into(StatusCode::Errno(-64)))
388 );
389 }
390
391 #[test]
392 fn test_status_code_from_errno() {
393 let code = StatusCode::from(rustix::io::Errno::NOMEM);
394 assert_eq!(code, StatusCode::NoMemory);
395
396 let code = StatusCode::from(rustix::io::Errno::NOSYS);
397 assert_eq!(code, StatusCode::InvalidOperation);
398
399 let code = StatusCode::from(rustix::io::Errno::INVAL);
400 assert_eq!(code, StatusCode::BadValue);
401
402 let code = StatusCode::from(rustix::io::Errno::NOENT);
403 assert_eq!(code, StatusCode::NameNotFound);
404
405 let code = StatusCode::from(rustix::io::Errno::PERM);
406 assert_eq!(code, StatusCode::PermissionDenied);
407
408 let code = StatusCode::from(rustix::io::Errno::NODEV);
409 assert_eq!(code, StatusCode::NoInit);
410
411 let code = StatusCode::from(rustix::io::Errno::EXIST);
412 assert_eq!(code, StatusCode::AlreadyExists);
413
414 let code = StatusCode::from(rustix::io::Errno::PIPE);
415 assert_eq!(code, StatusCode::DeadObject);
416
417 let code = StatusCode::from(rustix::io::Errno::BADMSG);
418 assert_eq!(code, StatusCode::UnknownTransaction);
419
420 let code = StatusCode::from(rustix::io::Errno::OVERFLOW);
421 assert_eq!(code, StatusCode::BadIndex);
422
423 let code = StatusCode::from(rustix::io::Errno::NODATA);
424 assert_eq!(code, StatusCode::NotEnoughData);
425
426 let code = StatusCode::from(rustix::io::Errno::WOULDBLOCK);
427 assert_eq!(code, StatusCode::WouldBlock);
428
429 let code = StatusCode::from(rustix::io::Errno::TIMEDOUT);
430 assert_eq!(code, StatusCode::TimedOut);
431
432 let code = StatusCode::from(rustix::io::Errno::BADF);
433 assert_eq!(code, StatusCode::BadFd);
434
435 let code = StatusCode::from(rustix::io::Errno::from_raw_os_error(64));
436 assert_eq!(code, StatusCode::Errno(-64));
437 }
438}