Skip to main content

libmdbx/
error.rs

1use libc::c_int;
2use std::{ffi::CStr, fmt, result, str};
3
4/// An MDBX error kind.
5#[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    /// Converts a raw error code to an [Error].
41    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    /// Converts an [Error] to the raw error code.
76    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
128/// An MDBX result.
129pub 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}