Skip to main content

unqlite/
error.rs

1use std::error;
2use std::fmt;
3use std::result;
4use crate::vars::*;
5
6/// Custom `Result` type.
7pub type Result<T> = result::Result<T, Error>;
8
9/// Custom `Error` type.
10#[derive(Debug)]
11pub enum Error {
12    /// UnQLite error code map
13    Custom(Custom),
14    /// Any kind of other errors
15    Other(Box<dyn error::Error>),
16}
17
18unsafe impl Send for Error {}
19unsafe impl Sync for Error {}
20
21impl From<Custom> for Error {
22    fn from(err: Custom) -> Error {
23        Error::Custom(err)
24    }
25}
26
27impl From<::std::ffi::NulError> for Error {
28    fn from(err: ::std::ffi::NulError) -> Error {
29        Error::Other(Box::new(err))
30    }
31}
32
33impl fmt::Display for Error {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        match *self {
36            Error::Custom(ref c) => write!(f, "Custom error: {}", c),
37            Error::Other(ref e) => write!(f, "Other error: {}", e),
38        }
39    }
40}
41
42#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct Custom {
44    kind: ErrorKind,
45    raw: i32,
46}
47
48/// Error kinds from unqlite official documents.
49#[allow(non_camel_case_types)]
50#[derive(Clone, Debug, PartialEq, Eq)]
51pub enum ErrorKind {
52    /// Successful result
53    OK = 0,
54    /// Out of memory
55    NOMEM,
56    /// Another thread have released this instance
57    ABORT,
58    /// IO error
59    IOERR,
60    /// Corrupt pointer
61    CORRUPT,
62    /// Forbidden Operation
63    LOCKED,
64    /// The database file is locked
65    BUSY,
66    /// Operation done, not an error
67    DONE,
68    /// Permission error
69    PERM,
70    /// Method not implemented
71    NOTIMPLEMENTED,
72    /// No such record
73    NOTFOUND,
74    /// No such method
75    NOOP,
76    /// Invalid parameter
77    INVALID,
78    /// End Of Input
79    EOF,
80    /// Unknown configuration option
81    UNKNOWN,
82    /// Database limit reached
83    LIMIT,
84    /// Record exists
85    EXISTS,
86    /// Empty record
87    EMPTY,
88    /// Compilation error
89    COMPILE_ERR,
90    /// Virtual machine error
91    VM_ERR,
92    /// Full database unlikely
93    FULL,
94    /// Unable to open the database file
95    CANTOPEN,
96    /// Read only Key/Value storage engine
97    READ_ONLY,
98    /// Locking protocol error
99    LOCKERR,
100    #[doc(hidden)]
101    __Nonexhaustive,
102}
103
104impl From<i32> for ErrorKind {
105    fn from(code: i32) -> ErrorKind {
106        match code {
107            UNQLITE_OK => ErrorKind::OK,
108            UNQLITE_NOMEM => ErrorKind::NOMEM,
109            UNQLITE_ABORT => ErrorKind::ABORT,
110            UNQLITE_IOERR => ErrorKind::IOERR,
111            UNQLITE_CORRUPT => ErrorKind::CORRUPT,
112            UNQLITE_LOCKED => ErrorKind::LOCKED,
113            UNQLITE_BUSY => ErrorKind::BUSY,
114            UNQLITE_DONE => ErrorKind::DONE,
115            UNQLITE_PERM => ErrorKind::PERM,
116            UNQLITE_NOTIMPLEMENTED => ErrorKind::NOTIMPLEMENTED,
117            UNQLITE_NOTFOUND => ErrorKind::NOTFOUND,
118            UNQLITE_NOOP => ErrorKind::NOOP,
119            UNQLITE_INVALID => ErrorKind::INVALID,
120            UNQLITE_EOF => ErrorKind::EOF,
121            UNQLITE_UNKNOWN => ErrorKind::UNKNOWN,
122            UNQLITE_LIMIT => ErrorKind::LIMIT,
123            UNQLITE_EXISTS => ErrorKind::EXISTS,
124            UNQLITE_EMPTY => ErrorKind::EMPTY,
125            UNQLITE_COMPILE_ERR => ErrorKind::COMPILE_ERR,
126            UNQLITE_VM_ERR => ErrorKind::VM_ERR,
127            UNQLITE_FULL => ErrorKind::FULL,
128            UNQLITE_CANTOPEN => ErrorKind::CANTOPEN,
129            UNQLITE_READ_ONLY => ErrorKind::READ_ONLY,
130            UNQLITE_LOCKERR => ErrorKind::LOCKERR,
131            _ => ErrorKind::__Nonexhaustive,
132        }
133    }
134}
135
136/// A wrap trait for unqlite FFI error code to Rust-y `Result`.
137///
138/// To populate better visual style, we add a `Wrap` trait to original
139/// unqlite return value. The `Wrap` trait has only one method `drop` -
140/// which is used to wrap the unqlite return value to Rust `Result`.
141/// So the FFI-related methods should just use `.wrap()` like this:
142///
143/// ```ignore
144/// unsafe {
145///     unqlite_open(...).wrap()  // Now it is Result<(), Error>
146/// }
147/// ```
148///
149/// This should be nice for functional programming style.
150pub(crate) trait Wrap {
151    fn wrap(self) -> Result<()>;
152}
153
154impl Wrap for i32 {
155    fn wrap(self) -> Result<()> {
156        Custom::from_raw(self)
157    }
158}
159
160impl Custom {
161    pub fn from_raw(result: i32) -> Result<()> {
162        let kind = ErrorKind::from(result);
163        match kind {
164            ErrorKind::OK => Ok(()),
165            _ => Err(Custom {
166                kind: kind,
167                raw: result,
168            }
169            .into()),
170        }
171    }
172
173    pub fn error(&self) -> &str {
174        match self.kind {
175            ErrorKind::NOMEM => "Out of memory",
176            ErrorKind::ABORT => "Another thread have released this instance",
177            ErrorKind::IOERR => "IO error",
178            ErrorKind::CORRUPT => "Corrupt pointer",
179            ErrorKind::LOCKED => "Forbidden Operation",
180            ErrorKind::BUSY => "The database file is locked",
181            ErrorKind::DONE => "Operation done",
182            ErrorKind::PERM => "Permission error",
183            ErrorKind::NOTIMPLEMENTED => {
184                "Method not implemented by the underlying Key/Value storage engine"
185            }
186            ErrorKind::NOTFOUND => "No such record",
187            ErrorKind::NOOP => "No such method",
188            ErrorKind::INVALID => "Invalid parameter",
189            ErrorKind::EOF => "End Of Input",
190            ErrorKind::UNKNOWN => "Unknown configuration option",
191            ErrorKind::LIMIT => "Database limit reached",
192            ErrorKind::EXISTS => "Record exists",
193            ErrorKind::EMPTY => "Empty record",
194            ErrorKind::COMPILE_ERR => "Compilation error",
195            ErrorKind::VM_ERR => " Virtual machine error",
196            ErrorKind::FULL => "Full database (unlikely)",
197            ErrorKind::CANTOPEN => "Unable to open the database file",
198            ErrorKind::READ_ONLY => "Read only Key/Value storage engine",
199            ErrorKind::LOCKERR => "Locking protocol error",
200            ErrorKind::OK => unreachable!(),
201            ErrorKind::__Nonexhaustive => unreachable!(),
202        }
203    }
204}
205
206impl error::Error for Custom {
207    fn description(&self) -> &str {
208        self.error()
209    }
210}
211
212impl fmt::Display for Custom {
213    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214        write!(f, "Custom error: {}", self.error())
215    }
216}