Skip to main content

sqlite_provider/
error.rs

1use core::fmt;
2
3/// Error returned by sqlite-provider operations.
4#[derive(Clone, Debug)]
5pub struct Error {
6    pub code: ErrorCode,
7    pub extended: Option<i32>,
8    pub message: Option<String>,
9}
10
11/// Result alias used across the crate.
12pub type Result<T> = core::result::Result<T, Error>;
13
14/// SQLite result codes plus crate-specific conditions.
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub enum ErrorCode {
17    Ok,
18    Error,
19    Abort,
20    Busy,
21    NoMem,
22    Interrupt,
23    NotFound,
24    CantOpen,
25    Misuse,
26    Row,
27    Done,
28    FeatureUnavailable,
29    Unknown(i32),
30}
31
32impl ErrorCode {
33    pub const fn from_code(code: i32) -> ErrorCode {
34        match code {
35            0 => ErrorCode::Ok,
36            1 => ErrorCode::Error,
37            4 => ErrorCode::Abort,
38            5 => ErrorCode::Busy,
39            7 => ErrorCode::NoMem,
40            9 => ErrorCode::Interrupt,
41            12 => ErrorCode::NotFound,
42            14 => ErrorCode::CantOpen,
43            21 => ErrorCode::Misuse,
44            100 => ErrorCode::Row,
45            101 => ErrorCode::Done,
46            other => ErrorCode::Unknown(other),
47        }
48    }
49
50    pub const fn code(self) -> Option<i32> {
51        match self {
52            ErrorCode::Ok => Some(0),
53            ErrorCode::Error => Some(1),
54            ErrorCode::Abort => Some(4),
55            ErrorCode::Busy => Some(5),
56            ErrorCode::NoMem => Some(7),
57            ErrorCode::Interrupt => Some(9),
58            ErrorCode::NotFound => Some(12),
59            ErrorCode::CantOpen => Some(14),
60            ErrorCode::Misuse => Some(21),
61            ErrorCode::Row => Some(100),
62            ErrorCode::Done => Some(101),
63            ErrorCode::FeatureUnavailable => None,
64            ErrorCode::Unknown(code) => Some(code),
65        }
66    }
67}
68
69impl Error {
70    pub fn new(code: ErrorCode) -> Self {
71        Self { code, extended: None, message: None }
72    }
73
74    pub fn with_message(code: ErrorCode, message: impl Into<String>) -> Self {
75        Self { code, extended: None, message: Some(message.into()) }
76    }
77
78    pub fn from_code(code: i32, message: Option<String>, extended: Option<i32>) -> Self {
79        Self { code: ErrorCode::from_code(code), extended, message }
80    }
81
82    pub fn feature_unavailable(msg: &'static str) -> Self {
83        Self { code: ErrorCode::FeatureUnavailable, extended: None, message: Some(msg.into()) }
84    }
85}
86
87impl fmt::Display for Error {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match (self.code, &self.message) {
90            (_, Some(msg)) => write!(f, "{}", msg),
91            (ErrorCode::Unknown(code), None) => write!(f, "sqlite error code {}", code),
92            (ErrorCode::FeatureUnavailable, None) => write!(f, "feature unavailable"),
93            (code, None) => write!(f, "sqlite error {:?}", code),
94        }
95    }
96}
97
98impl std::error::Error for Error {}
99
100#[cfg(test)]
101mod tests {
102    use super::{Error, ErrorCode};
103
104    #[test]
105    fn error_code_mapping() {
106        assert_eq!(ErrorCode::from_code(0), ErrorCode::Ok);
107        assert_eq!(ErrorCode::from_code(14), ErrorCode::CantOpen);
108        assert_eq!(ErrorCode::from_code(999), ErrorCode::Unknown(999));
109    }
110
111    #[test]
112    fn feature_unavailable_message() {
113        let err = Error::feature_unavailable("missing");
114        assert_eq!(err.code, ErrorCode::FeatureUnavailable);
115        assert_eq!(err.message.as_deref(), Some("missing"));
116    }
117}