rusty_leveldb/
error.rs

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/// StatusCode describes various failure modes of database operations.
9#[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/// Status encapsulates a `StatusCode` and an error message. It can be displayed, and also
31/// implements `Error`.
32#[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
75/// LevelDB's result type
76pub type Result<T> = result::Result<T, Status>;
77
78/// err returns a new Status wrapped in a Result.
79pub 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}