1use std::convert::From;
2use std::error::Error;
3use std::fmt::{self, Display, Formatter};
4use std::io;
5use std::result;
6use std::sync;
7
8#[derive(Clone, Debug, PartialEq)]
10#[allow(dead_code)]
11pub enum StatusCode {
12 OK,
13
14 AlreadyExists,
15 Corruption,
16 CompressionError,
17 IOError,
18 InvalidArgument,
19 InvalidData,
20 LockError,
21 NotFound,
22 NotSupported,
23 PermissionDenied,
24 AsyncError,
25 Unknown,
26 #[cfg(feature = "fs")]
27 Errno(errno::Errno),
28}
29
30#[derive(Clone, Debug, PartialEq)]
33pub struct Status {
34 pub code: StatusCode,
35 pub err: String,
36}
37
38impl Default for Status {
39 fn default() -> Status {
40 Status {
41 code: StatusCode::OK,
42 err: String::new(),
43 }
44 }
45}
46
47impl Display for Status {
48 fn fmt(&self, fmt: &mut Formatter) -> result::Result<(), fmt::Error> {
49 fmt.write_str(&self.err)
50 }
51}
52
53impl Error for Status {
54 fn description(&self) -> &str {
55 &self.err
56 }
57}
58
59impl Status {
60 pub fn new(code: StatusCode, msg: &str) -> Status {
61 let err = match msg.is_empty() {
62 true => format!("{:?}", code),
63 false => format!("{:?}: {}", code, msg),
64 };
65 Status { code, err }
66 }
67 pub fn annotate<S: AsRef<str>>(self, msg: S) -> Status {
68 Status {
69 code: self.code,
70 err: format!("{}: {}", msg.as_ref(), self.err),
71 }
72 }
73}
74
75pub type Result<T> = result::Result<T, Status>;
77
78pub fn err<T>(code: StatusCode, msg: &str) -> Result<T> {
80 Err(Status::new(code, msg))
81}
82
83impl From<io::Error> for Status {
84 fn from(e: io::Error) -> Status {
85 let c = match e.kind() {
86 io::ErrorKind::NotFound => StatusCode::NotFound,
87 io::ErrorKind::InvalidData => StatusCode::Corruption,
88 io::ErrorKind::InvalidInput => StatusCode::InvalidArgument,
89 io::ErrorKind::PermissionDenied => StatusCode::PermissionDenied,
90 _ => StatusCode::IOError,
91 };
92
93 Status::new(c, &e.to_string())
94 }
95}
96
97impl<T> From<sync::PoisonError<T>> for Status {
98 fn from(_: sync::PoisonError<T>) -> Status {
99 Status::new(StatusCode::LockError, "lock poisoned")
100 }
101}
102
103impl From<snap::Error> for Status {
104 fn from(e: snap::Error) -> Status {
105 Status {
106 code: StatusCode::CompressionError,
107 err: e.to_string(),
108 }
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::{Status, StatusCode};
115 #[test]
116 fn test_status_to_string() {
117 let s = Status::new(StatusCode::InvalidData, "Invalid data!");
118 assert_eq!("InvalidData: Invalid data!", s.to_string());
119 }
120}