1use std::error::Error as StdError;
12use std::ffi::{CStr, NulError};
13use std::fmt;
14use std::result;
15use libc::c_int;
16
17use ffi;
18use ffi2;
19
20pub const KEYEXIST: c_int = ffi::MDB_KEYEXIST;
22pub const NOTFOUND: c_int = ffi::MDB_NOTFOUND;
24pub const PAGE_NOTFOUND: c_int = ffi::MDB_PAGE_NOTFOUND;
26pub const CORRUPTED: c_int = ffi::MDB_CORRUPTED;
28pub const PANIC: c_int = ffi::MDB_PANIC;
30pub const VERSION_MISMATCH: c_int = ffi::MDB_VERSION_MISMATCH;
32pub const INVALID: c_int = ffi::MDB_INVALID;
34pub const MAP_FULL: c_int = ffi::MDB_MAP_FULL;
36pub const DBS_FULL: c_int = ffi::MDB_DBS_FULL;
38pub const READERS_FULL: c_int = ffi::MDB_READERS_FULL;
40pub const TLS_FULL: c_int = ffi::MDB_TLS_FULL;
42pub const TXN_FULL: c_int = ffi::MDB_TXN_FULL;
44pub const CURSOR_FULL: c_int = ffi::MDB_CURSOR_FULL;
46pub const PAGE_FULL: c_int = ffi::MDB_PAGE_FULL;
48pub const MAP_RESIZED: c_int = ffi::MDB_MAP_RESIZED;
50pub const INCOMPATIBLE: c_int = ffi::MDB_INCOMPATIBLE;
57pub const BAD_RSLOT: c_int = ffi::MDB_BAD_RSLOT;
59pub const BAD_TXN: c_int = ffi::MDB_BAD_TXN;
61pub const BAD_VALSIZE: c_int = ffi::MDB_BAD_VALSIZE;
63pub const BAD_DBI: c_int = ffi2::MDB_BAD_DBI;
65
66#[derive(Clone,PartialEq,Eq,Hash)]
68pub enum Error {
69 Code(c_int),
74 NulStr,
76 Reopened,
78 Mismatch,
84 ValRejected(String),
86 #[doc(hidden)]
88 _NonExhaustive
89}
90
91pub type Result<T> = result::Result<T, Error>;
93
94impl Error {
95 fn strerror(&self) -> &'static str {
96 match *self {
97 Error::NulStr => "NUL byte in path",
98 Error::Reopened => "Attempt to reopen database",
99 Error::Mismatch =>
100 "Items from different env/database used together",
101 Error::ValRejected(..) =>
102 "Value conversion failed",
103 Error::_NonExhaustive => "Error::_NonExhaustive",
104 Error::Code(code) => unsafe {
105 let raw = ffi::mdb_strerror(code);
106 if raw.is_null() {
107 "(null)"
108 } else {
109 CStr::from_ptr(raw).to_str().unwrap_or("(unknown)")
110 }
111 },
112 }
113 }
114}
115
116impl fmt::Debug for Error {
117 fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
118 match *self {
119 Error::NulStr =>
120 write!(f, "Error::NulStr"),
121 Error::Reopened =>
122 write!(f, "Error::Reopened"),
123 Error::Mismatch =>
124 write!(f, "Error::Mismatch"),
125 Error::ValRejected(ref why) =>
126 write!(f, "Error::ValRejected({:?})", why),
127 Error::Code(code) =>
128 write!(f, "Error::Code({}, '{}')", code, self.strerror()),
129 Error::_NonExhaustive =>
130 write!(f, "Error::_NonExhaustive"),
131 }
132 }
133}
134
135impl fmt::Display for Error {
136 fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
137 match *self {
138 Error::ValRejected(ref why) =>
139 write!(f, "Value conversion failed: {}", why),
140 _ => write!(f, "{}", self.strerror()),
141 }
142 }
143}
144
145impl StdError for Error {
146 fn description(&self) -> &str {
147 self.strerror()
148 }
149}
150
151impl From<NulError> for Error {
152 fn from(_: NulError) -> Self {
153 Error::NulStr
154 }
155}
156
157pub trait LmdbResultExt {
159 #[allow(missing_docs)]
160 type Inner;
161
162 fn to_opt(self) -> Result<Option<Self::Inner>>;
167
168 fn ignore_exists(self, inner: Self::Inner) -> Self;
173}
174
175impl<T> LmdbResultExt for Result<T> {
176 type Inner = T;
177
178 fn to_opt(self) -> Result<Option<T>> {
179 match self {
180 Ok(val) => Ok(Some(val)),
181 Err(Error::Code(code)) if NOTFOUND == code => Ok(None),
182 Err(error) => Err(error),
183 }
184 }
185
186 fn ignore_exists(self, inner: T) -> Self {
187 match self {
188 Ok(val) => Ok(val),
189 Err(Error::Code(code)) if KEYEXIST == code => Ok(inner),
190 Err(error) => Err(error),
191 }
192 }
193}