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