1use std::error::Error as StdError;
2use std::ffi::CStr;
3use std::os::raw::c_char;
4use std::{fmt, str};
5
6use libc::c_int;
7use lmdb_master_sys as ffi;
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq)]
11pub enum Error {
12 KeyExist,
17 NotFound,
19 PageNotFound,
21 Corrupted,
23 Panic,
25 VersionMismatch,
27 Invalid,
29 MapFull,
31 DbsFull,
33 ReadersFull,
35 TlsFull,
37 TxnFull,
39 CursorFull,
41 PageFull,
43 MapResized,
45 Incompatible,
51 BadRslot,
53 BadTxn,
55 BadValSize,
65 BadDbi,
67 Problem,
69 Other(c_int),
71}
72
73impl Error {
74 pub fn not_found(&self) -> bool {
76 *self == Error::NotFound
77 }
78
79 pub fn from_err_code(err_code: c_int) -> Error {
81 match err_code {
82 ffi::MDB_KEYEXIST => Error::KeyExist,
83 ffi::MDB_NOTFOUND => Error::NotFound,
84 ffi::MDB_PAGE_NOTFOUND => Error::PageNotFound,
85 ffi::MDB_CORRUPTED => Error::Corrupted,
86 ffi::MDB_PANIC => Error::Panic,
87 ffi::MDB_VERSION_MISMATCH => Error::VersionMismatch,
88 ffi::MDB_INVALID => Error::Invalid,
89 ffi::MDB_MAP_FULL => Error::MapFull,
90 ffi::MDB_DBS_FULL => Error::DbsFull,
91 ffi::MDB_READERS_FULL => Error::ReadersFull,
92 ffi::MDB_TLS_FULL => Error::TlsFull,
93 ffi::MDB_TXN_FULL => Error::TxnFull,
94 ffi::MDB_CURSOR_FULL => Error::CursorFull,
95 ffi::MDB_PAGE_FULL => Error::PageFull,
96 ffi::MDB_MAP_RESIZED => Error::MapResized,
97 ffi::MDB_INCOMPATIBLE => Error::Incompatible,
98 ffi::MDB_BAD_RSLOT => Error::BadRslot,
99 ffi::MDB_BAD_TXN => Error::BadTxn,
100 ffi::MDB_BAD_VALSIZE => Error::BadValSize,
101 ffi::MDB_BAD_DBI => Error::BadDbi,
102 ffi::MDB_PROBLEM => Error::Problem,
103 other => Error::Other(other),
104 }
105 }
106
107 #[allow(clippy::trivially_copy_pass_by_ref)]
109 pub fn to_err_code(&self) -> c_int {
110 match *self {
111 Error::KeyExist => ffi::MDB_KEYEXIST,
112 Error::NotFound => ffi::MDB_NOTFOUND,
113 Error::PageNotFound => ffi::MDB_PAGE_NOTFOUND,
114 Error::Corrupted => ffi::MDB_CORRUPTED,
115 Error::Panic => ffi::MDB_PANIC,
116 Error::VersionMismatch => ffi::MDB_VERSION_MISMATCH,
117 Error::Invalid => ffi::MDB_INVALID,
118 Error::MapFull => ffi::MDB_MAP_FULL,
119 Error::DbsFull => ffi::MDB_DBS_FULL,
120 Error::ReadersFull => ffi::MDB_READERS_FULL,
121 Error::TlsFull => ffi::MDB_TLS_FULL,
122 Error::TxnFull => ffi::MDB_TXN_FULL,
123 Error::CursorFull => ffi::MDB_CURSOR_FULL,
124 Error::PageFull => ffi::MDB_PAGE_FULL,
125 Error::MapResized => ffi::MDB_MAP_RESIZED,
126 Error::Incompatible => ffi::MDB_INCOMPATIBLE,
127 Error::BadRslot => ffi::MDB_BAD_RSLOT,
128 Error::BadTxn => ffi::MDB_BAD_TXN,
129 Error::BadValSize => ffi::MDB_BAD_VALSIZE,
130 Error::BadDbi => ffi::MDB_BAD_DBI,
131 Error::Problem => ffi::MDB_PROBLEM,
132 Error::Other(err_code) => err_code,
133 }
134 }
135}
136
137impl fmt::Display for Error {
138 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
139 let description = unsafe {
140 let err: *const c_char = ffi::mdb_strerror(self.to_err_code()) as *const c_char;
142 str::from_utf8_unchecked(CStr::from_ptr(err).to_bytes())
143 };
144
145 fmt.write_str(description)
146 }
147}
148
149impl StdError for Error {}
150
151pub fn mdb_result(err_code: c_int) -> Result<(), Error> {
152 if err_code == ffi::MDB_SUCCESS {
153 Ok(())
154 } else {
155 Err(Error::from_err_code(err_code))
156 }
157}
158
159#[cfg(test)]
160mod test {
161 use super::*;
162
163 #[test]
164 fn test_description() {
165 assert_eq!("Permission denied", Error::from_err_code(13).to_string());
166 assert_eq!("MDB_NOTFOUND: No matching key/data pair found", Error::NotFound.to_string());
167 }
168}