rsbinder/
error.rs

1// Copyright 2022 Jeff Kim <hiking90@gmail.com>
2// SPDX-License-Identifier: Apache-2.0
3
4use 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}