use std::error::Error as StdError;
use std::ffi::{CStr, NulError};
use std::fmt;
use std::result;
use libc::c_int;
use ffi;
use ffi2;
pub const KEYEXIST: c_int = ffi::MDB_KEYEXIST;
pub const NOTFOUND: c_int = ffi::MDB_NOTFOUND;
pub const PAGE_NOTFOUND: c_int = ffi::MDB_PAGE_NOTFOUND;
pub const CORRUPTED: c_int = ffi::MDB_CORRUPTED;
pub const PANIC: c_int = ffi::MDB_PANIC;
pub const VERSION_MISMATCH: c_int = ffi::MDB_VERSION_MISMATCH;
pub const INVALID: c_int = ffi::MDB_INVALID;
pub const MAP_FULL: c_int = ffi::MDB_MAP_FULL;
pub const DBS_FULL: c_int = ffi::MDB_DBS_FULL;
pub const READERS_FULL: c_int = ffi::MDB_READERS_FULL;
pub const TLS_FULL: c_int = ffi::MDB_TLS_FULL;
pub const TXN_FULL: c_int = ffi::MDB_TXN_FULL;
pub const CURSOR_FULL: c_int = ffi::MDB_CURSOR_FULL;
pub const PAGE_FULL: c_int = ffi::MDB_PAGE_FULL;
pub const MAP_RESIZED: c_int = ffi::MDB_MAP_RESIZED;
pub const INCOMPATIBLE: c_int = ffi::MDB_INCOMPATIBLE;
pub const BAD_RSLOT: c_int = ffi::MDB_BAD_RSLOT;
pub const BAD_TXN: c_int = ffi::MDB_BAD_TXN;
pub const BAD_VALSIZE: c_int = ffi::MDB_BAD_VALSIZE;
pub const BAD_DBI: c_int = ffi2::MDB_BAD_DBI;
#[derive(Clone,PartialEq,Eq,Hash)]
pub enum Error {
Code(c_int),
NulStr,
Reopened,
Mismatch,
ValRejected(String),
#[doc(hidden)]
_NonExhaustive
}
pub type Result<T> = result::Result<T, Error>;
impl Error {
fn strerror(&self) -> &'static str {
match *self {
Error::NulStr => "NUL byte in path",
Error::Reopened => "Attempt to reopen database",
Error::Mismatch =>
"Items from different env/database used together",
Error::ValRejected(..) =>
"Value conversion failed",
Error::_NonExhaustive => "Error::_NonExhaustive",
Error::Code(code) => unsafe {
let raw = ffi::mdb_strerror(code);
if raw.is_null() {
"(null)"
} else {
CStr::from_ptr(raw).to_str().unwrap_or("(unknown)")
}
},
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
match *self {
Error::NulStr =>
write!(f, "Error::NulStr"),
Error::Reopened =>
write!(f, "Error::Reopened"),
Error::Mismatch =>
write!(f, "Error::Mismatch"),
Error::ValRejected(ref why) =>
write!(f, "Error::ValRejected({:?})", why),
Error::Code(code) =>
write!(f, "Error::Code({}, '{}')", code, self.strerror()),
Error::_NonExhaustive =>
write!(f, "Error::_NonExhaustive"),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
match *self {
Error::ValRejected(ref why) =>
write!(f, "Value conversion failed: {}", why),
_ => write!(f, "{}", self.strerror()),
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
self.strerror()
}
}
impl From<NulError> for Error {
fn from(_: NulError) -> Self {
Error::NulStr
}
}
pub trait LmdbResultExt {
#[allow(missing_docs)]
type Inner;
fn to_opt(self) -> Result<Option<Self::Inner>>;
fn ignore_exists(self, inner: Self::Inner) -> Self;
}
impl<T> LmdbResultExt for Result<T> {
type Inner = T;
fn to_opt(self) -> Result<Option<T>> {
match self {
Ok(val) => Ok(Some(val)),
Err(Error::Code(code)) if NOTFOUND == code => Ok(None),
Err(error) => Err(error),
}
}
fn ignore_exists(self, inner: T) -> Self {
match self {
Ok(val) => Ok(val),
Err(Error::Code(code)) if KEYEXIST == code => Ok(inner),
Err(error) => Err(error),
}
}
}