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