use libc::c_int;
use std::error::Error as StdError;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::{
fmt,
result,
str,
};
use ffi;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
KeyExist,
NotFound,
PageNotFound,
Corrupted,
Panic,
VersionMismatch,
Invalid,
MapFull,
DbsFull,
ReadersFull,
TlsFull,
TxnFull,
CursorFull,
PageFull,
MapResized,
Incompatible,
BadRslot,
BadTxn,
BadValSize,
BadDbi,
Other(c_int),
}
impl Error {
pub fn from_err_code(err_code: c_int) -> Error {
match err_code {
ffi::MDB_KEYEXIST => Error::KeyExist,
ffi::MDB_NOTFOUND => Error::NotFound,
ffi::MDB_PAGE_NOTFOUND => Error::PageNotFound,
ffi::MDB_CORRUPTED => Error::Corrupted,
ffi::MDB_PANIC => Error::Panic,
ffi::MDB_VERSION_MISMATCH => Error::VersionMismatch,
ffi::MDB_INVALID => Error::Invalid,
ffi::MDB_MAP_FULL => Error::MapFull,
ffi::MDB_DBS_FULL => Error::DbsFull,
ffi::MDB_READERS_FULL => Error::ReadersFull,
ffi::MDB_TLS_FULL => Error::TlsFull,
ffi::MDB_TXN_FULL => Error::TxnFull,
ffi::MDB_CURSOR_FULL => Error::CursorFull,
ffi::MDB_PAGE_FULL => Error::PageFull,
ffi::MDB_MAP_RESIZED => Error::MapResized,
ffi::MDB_INCOMPATIBLE => Error::Incompatible,
ffi::MDB_BAD_RSLOT => Error::BadRslot,
ffi::MDB_BAD_TXN => Error::BadTxn,
ffi::MDB_BAD_VALSIZE => Error::BadValSize,
ffi::MDB_BAD_DBI => Error::BadDbi,
other => Error::Other(other),
}
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn to_err_code(&self) -> c_int {
match *self {
Error::KeyExist => ffi::MDB_KEYEXIST,
Error::NotFound => ffi::MDB_NOTFOUND,
Error::PageNotFound => ffi::MDB_PAGE_NOTFOUND,
Error::Corrupted => ffi::MDB_CORRUPTED,
Error::Panic => ffi::MDB_PANIC,
Error::VersionMismatch => ffi::MDB_VERSION_MISMATCH,
Error::Invalid => ffi::MDB_INVALID,
Error::MapFull => ffi::MDB_MAP_FULL,
Error::DbsFull => ffi::MDB_DBS_FULL,
Error::ReadersFull => ffi::MDB_READERS_FULL,
Error::TlsFull => ffi::MDB_TLS_FULL,
Error::TxnFull => ffi::MDB_TXN_FULL,
Error::CursorFull => ffi::MDB_CURSOR_FULL,
Error::PageFull => ffi::MDB_PAGE_FULL,
Error::MapResized => ffi::MDB_MAP_RESIZED,
Error::Incompatible => ffi::MDB_INCOMPATIBLE,
Error::BadRslot => ffi::MDB_BAD_RSLOT,
Error::BadTxn => ffi::MDB_BAD_TXN,
Error::BadValSize => ffi::MDB_BAD_VALSIZE,
Error::BadDbi => ffi::MDB_BAD_DBI,
Error::Other(err_code) => err_code,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{}", self.description())
}
}
impl StdError for Error {
fn description(&self) -> &str {
unsafe {
let err: *const c_char = ffi::mdb_strerror(self.to_err_code()) as *const c_char;
str::from_utf8_unchecked(CStr::from_ptr(err).to_bytes())
}
}
}
pub type Result<T> = result::Result<T, Error>;
pub fn lmdb_result(err_code: c_int) -> Result<()> {
if err_code == ffi::MDB_SUCCESS {
Ok(())
} else {
Err(Error::from_err_code(err_code))
}
}
#[cfg(test)]
mod test {
use std::error::Error as StdError;
use super::*;
#[test]
fn test_description() {
assert_eq!("Permission denied", Error::from_err_code(13).description());
assert_eq!("MDB_NOTFOUND: No matching key/data pair found", Error::NotFound.description());
}
}