1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use std::convert::From;
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io;
use std::result;
use std::sync;

use snap;

/// StatusCode describes various failure modes of database operations.
#[derive(Clone, Debug, PartialEq)]
#[allow(dead_code)]
pub enum StatusCode {
    OK,

    AlreadyExists,
    Corruption,
    CompressionError,
    IOError,
    InvalidArgument,
    InvalidData,
    LockError,
    NotFound,
    NotSupported,
    PermissionDenied,
    Unknown,
}

/// Status encapsulates a `StatusCode` and an error message. It can be displayed, and also
/// implements `Error`.
#[derive(Clone, Debug, PartialEq)]
pub struct Status {
    pub code: StatusCode,
    pub err: String,
}

impl Default for Status {
    fn default() -> Status {
        Status {
            code: StatusCode::OK,
            err: String::new(),
        }
    }
}

impl Display for Status {
    fn fmt(&self, fmt: &mut Formatter) -> result::Result<(), fmt::Error> {
        fmt.write_str(self.description())
    }
}

impl Error for Status {
    fn description(&self) -> &str {
        &self.err
    }
}

impl Status {
    pub fn new(code: StatusCode, msg: &str) -> Status {
        let err;
        if msg.is_empty() {
            err = format!("{:?}", code)
        } else {
            err = format!("{:?}: {}", code, msg);
        }
        return Status {
            code: code,
            err: err,
        };
    }
}

/// LevelDB's result type
pub type Result<T> = result::Result<T, Status>;

/// err returns a new Status wrapped in a Result.
pub fn err<T>(code: StatusCode, msg: &str) -> Result<T> {
    Err(Status::new(code, msg))
}

impl From<io::Error> for Status {
    fn from(e: io::Error) -> Status {
        let c = match e.kind() {
            io::ErrorKind::NotFound => StatusCode::NotFound,
            io::ErrorKind::InvalidData => StatusCode::Corruption,
            io::ErrorKind::InvalidInput => StatusCode::InvalidArgument,
            io::ErrorKind::PermissionDenied => StatusCode::PermissionDenied,
            _ => StatusCode::IOError,
        };

        Status::new(c, e.description())
    }
}

impl<T> From<sync::PoisonError<T>> for Status {
    fn from(_: sync::PoisonError<T>) -> Status {
        Status::new(StatusCode::LockError, "lock poisoned")
    }
}

impl From<snap::Error> for Status {
    fn from(e: snap::Error) -> Status {
        Status {
            code: StatusCode::CompressionError,
            err: e.description().to_string(),
        }
    }
}