1use libc::c_int;
2use std::{ffi::CStr, fmt, result, str};
3
4#[derive(Debug)]
6pub enum Error {
7 KeyExist,
8 NotFound,
9 NoData,
10 PageNotFound,
11 Corrupted,
12 Panic,
13 VersionMismatch,
14 Invalid,
15 MapFull,
16 DbsFull,
17 ReadersFull,
18 TxnFull,
19 CursorFull,
20 PageFull,
21 UnableExtendMapsize,
22 Incompatible,
23 BadRslot,
24 BadTxn,
25 BadValSize,
26 BadDbi,
27 Problem,
28 Busy,
29 Multival,
30 WannaRecovery,
31 KeyMismatch,
32 InvalidValue,
33 Access,
34 TooLarge,
35 DecodeError(Box<dyn std::error::Error + Send + Sync + 'static>),
36 Other(c_int),
37}
38
39impl Error {
40 pub fn from_err_code(err_code: c_int) -> Error {
42 match err_code {
43 ffi::MDBX_KEYEXIST => Error::KeyExist,
44 ffi::MDBX_NOTFOUND => Error::NotFound,
45 ffi::MDBX_ENODATA => Error::NoData,
46 ffi::MDBX_PAGE_NOTFOUND => Error::PageNotFound,
47 ffi::MDBX_CORRUPTED => Error::Corrupted,
48 ffi::MDBX_PANIC => Error::Panic,
49 ffi::MDBX_VERSION_MISMATCH => Error::VersionMismatch,
50 ffi::MDBX_INVALID => Error::Invalid,
51 ffi::MDBX_MAP_FULL => Error::MapFull,
52 ffi::MDBX_DBS_FULL => Error::DbsFull,
53 ffi::MDBX_READERS_FULL => Error::ReadersFull,
54 ffi::MDBX_TXN_FULL => Error::TxnFull,
55 ffi::MDBX_CURSOR_FULL => Error::CursorFull,
56 ffi::MDBX_PAGE_FULL => Error::PageFull,
57 ffi::MDBX_UNABLE_EXTEND_MAPSIZE => Error::UnableExtendMapsize,
58 ffi::MDBX_INCOMPATIBLE => Error::Incompatible,
59 ffi::MDBX_BAD_RSLOT => Error::BadRslot,
60 ffi::MDBX_BAD_TXN => Error::BadTxn,
61 ffi::MDBX_BAD_VALSIZE => Error::BadValSize,
62 ffi::MDBX_BAD_DBI => Error::BadDbi,
63 ffi::MDBX_PROBLEM => Error::Problem,
64 ffi::MDBX_BUSY => Error::Busy,
65 ffi::MDBX_EMULTIVAL => Error::Multival,
66 ffi::MDBX_WANNA_RECOVERY => Error::WannaRecovery,
67 ffi::MDBX_EKEYMISMATCH => Error::KeyMismatch,
68 ffi::MDBX_EINVAL => Error::InvalidValue,
69 ffi::MDBX_EACCESS => Error::Access,
70 ffi::MDBX_TOO_LARGE => Error::TooLarge,
71 other => Error::Other(other),
72 }
73 }
74
75 fn to_err_code(&self) -> c_int {
77 match self {
78 Error::KeyExist => ffi::MDBX_KEYEXIST,
79 Error::NotFound => ffi::MDBX_NOTFOUND,
80 Error::NoData => ffi::MDBX_ENODATA,
81 Error::PageNotFound => ffi::MDBX_PAGE_NOTFOUND,
82 Error::Corrupted => ffi::MDBX_CORRUPTED,
83 Error::Panic => ffi::MDBX_PANIC,
84 Error::VersionMismatch => ffi::MDBX_VERSION_MISMATCH,
85 Error::Invalid => ffi::MDBX_INVALID,
86 Error::MapFull => ffi::MDBX_MAP_FULL,
87 Error::DbsFull => ffi::MDBX_DBS_FULL,
88 Error::ReadersFull => ffi::MDBX_READERS_FULL,
89 Error::TxnFull => ffi::MDBX_TXN_FULL,
90 Error::CursorFull => ffi::MDBX_CURSOR_FULL,
91 Error::PageFull => ffi::MDBX_PAGE_FULL,
92 Error::UnableExtendMapsize => ffi::MDBX_UNABLE_EXTEND_MAPSIZE,
93 Error::Incompatible => ffi::MDBX_INCOMPATIBLE,
94 Error::BadRslot => ffi::MDBX_BAD_RSLOT,
95 Error::BadTxn => ffi::MDBX_BAD_TXN,
96 Error::BadValSize => ffi::MDBX_BAD_VALSIZE,
97 Error::BadDbi => ffi::MDBX_BAD_DBI,
98 Error::Problem => ffi::MDBX_PROBLEM,
99 Error::Busy => ffi::MDBX_BUSY,
100 Error::Multival => ffi::MDBX_EMULTIVAL,
101 Error::WannaRecovery => ffi::MDBX_WANNA_RECOVERY,
102 Error::KeyMismatch => ffi::MDBX_EKEYMISMATCH,
103 Error::InvalidValue => ffi::MDBX_EINVAL,
104 Error::Access => ffi::MDBX_EACCESS,
105 Error::TooLarge => ffi::MDBX_TOO_LARGE,
106 Error::Other(err_code) => *err_code,
107 _ => unreachable!(),
108 }
109 }
110}
111
112impl fmt::Display for Error {
113 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
114 match self {
115 Error::DecodeError(reason) => write!(fmt, "{reason}"),
116 other => {
117 write!(fmt, "{}", unsafe {
118 let err = ffi::mdbx_strerror(other.to_err_code());
119 str::from_utf8_unchecked(CStr::from_ptr(err).to_bytes())
120 })
121 }
122 }
123 }
124}
125
126impl std::error::Error for Error {}
127
128pub type Result<T> = result::Result<T, Error>;
130
131pub fn mdbx_result(err_code: c_int) -> Result<bool> {
132 match err_code {
133 ffi::MDBX_SUCCESS => Ok(false),
134 ffi::MDBX_RESULT_TRUE => Ok(true),
135 other => Err(Error::from_err_code(other)),
136 }
137}
138
139#[macro_export]
140macro_rules! mdbx_try_optional {
141 ($expr:expr) => {{
142 match $expr {
143 Err(Error::NotFound | Error::NoData) => return Ok(None),
144 Err(e) => return Err(e),
145 Ok(v) => v,
146 }
147 }};
148}
149
150#[cfg(test)]
151mod test {
152 use super::*;
153
154 #[test]
155 fn test_description() {
156 #[cfg(not(windows))]
157 assert_eq!("Permission denied", Error::from_err_code(13).to_string());
158
159 assert_eq!(
160 "MDBX_INVALID: File is not an MDBX file",
161 Error::Invalid.to_string()
162 );
163 }
164}