1use libc::c_int;
2use std::error::Error as StdError;
3use std::ffi::CStr;
4use std::os::raw::c_char;
5use std::{
6 fmt,
7 result,
8 str,
9};
10
11use ffi;
12
13#[derive(Debug, Eq, PartialEq, Copy, Clone)]
15pub enum Error {
16 KeyExist,
18 NotFound,
20 PageNotFound,
22 Corrupted,
24 Panic,
26 VersionMismatch,
28 Invalid,
30 MapFull,
32 DbsFull,
34 ReadersFull,
36 TlsFull,
38 TxnFull,
40 CursorFull,
42 PageFull,
44 MapResized,
46 Incompatible,
48 BadRslot,
50 BadTxn,
52 BadValSize,
54 BadDbi,
56 Other(c_int),
58}
59
60impl Error {
61 pub fn from_err_code(err_code: c_int) -> Error {
63 match err_code {
64 ffi::MDB_KEYEXIST => Error::KeyExist,
65 ffi::MDB_NOTFOUND => Error::NotFound,
66 ffi::MDB_PAGE_NOTFOUND => Error::PageNotFound,
67 ffi::MDB_CORRUPTED => Error::Corrupted,
68 ffi::MDB_PANIC => Error::Panic,
69 ffi::MDB_VERSION_MISMATCH => Error::VersionMismatch,
70 ffi::MDB_INVALID => Error::Invalid,
71 ffi::MDB_MAP_FULL => Error::MapFull,
72 ffi::MDB_DBS_FULL => Error::DbsFull,
73 ffi::MDB_READERS_FULL => Error::ReadersFull,
74 ffi::MDB_TLS_FULL => Error::TlsFull,
75 ffi::MDB_TXN_FULL => Error::TxnFull,
76 ffi::MDB_CURSOR_FULL => Error::CursorFull,
77 ffi::MDB_PAGE_FULL => Error::PageFull,
78 ffi::MDB_MAP_RESIZED => Error::MapResized,
79 ffi::MDB_INCOMPATIBLE => Error::Incompatible,
80 ffi::MDB_BAD_RSLOT => Error::BadRslot,
81 ffi::MDB_BAD_TXN => Error::BadTxn,
82 ffi::MDB_BAD_VALSIZE => Error::BadValSize,
83 ffi::MDB_BAD_DBI => Error::BadDbi,
84 other => Error::Other(other),
85 }
86 }
87
88 #[allow(clippy::trivially_copy_pass_by_ref)]
90 pub fn to_err_code(&self) -> c_int {
91 match *self {
92 Error::KeyExist => ffi::MDB_KEYEXIST,
93 Error::NotFound => ffi::MDB_NOTFOUND,
94 Error::PageNotFound => ffi::MDB_PAGE_NOTFOUND,
95 Error::Corrupted => ffi::MDB_CORRUPTED,
96 Error::Panic => ffi::MDB_PANIC,
97 Error::VersionMismatch => ffi::MDB_VERSION_MISMATCH,
98 Error::Invalid => ffi::MDB_INVALID,
99 Error::MapFull => ffi::MDB_MAP_FULL,
100 Error::DbsFull => ffi::MDB_DBS_FULL,
101 Error::ReadersFull => ffi::MDB_READERS_FULL,
102 Error::TlsFull => ffi::MDB_TLS_FULL,
103 Error::TxnFull => ffi::MDB_TXN_FULL,
104 Error::CursorFull => ffi::MDB_CURSOR_FULL,
105 Error::PageFull => ffi::MDB_PAGE_FULL,
106 Error::MapResized => ffi::MDB_MAP_RESIZED,
107 Error::Incompatible => ffi::MDB_INCOMPATIBLE,
108 Error::BadRslot => ffi::MDB_BAD_RSLOT,
109 Error::BadTxn => ffi::MDB_BAD_TXN,
110 Error::BadValSize => ffi::MDB_BAD_VALSIZE,
111 Error::BadDbi => ffi::MDB_BAD_DBI,
112 Error::Other(err_code) => err_code,
113 }
114 }
115}
116
117impl fmt::Display for Error {
118 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
119 write!(fmt, "{}", self.description())
120 }
121}
122
123impl StdError for Error {
124 fn description(&self) -> &str {
125 unsafe {
126 let err: *const c_char = ffi::mdb_strerror(self.to_err_code()) as *const c_char;
128 str::from_utf8_unchecked(CStr::from_ptr(err).to_bytes())
129 }
130 }
131}
132
133pub type Result<T> = result::Result<T, Error>;
135
136pub fn lmdb_result(err_code: c_int) -> Result<()> {
137 if err_code == ffi::MDB_SUCCESS {
138 Ok(())
139 } else {
140 Err(Error::from_err_code(err_code))
141 }
142}
143
144#[cfg(test)]
145mod test {
146
147 use std::error::Error as StdError;
148
149 use super::*;
150
151 #[test]
152 fn test_description() {
153 assert_eq!("Permission denied", Error::from_err_code(13).description());
154 assert_eq!("MDB_NOTFOUND: No matching key/data pair found", Error::NotFound.description());
155 }
156}