1use core::fmt;
2
3#[derive(Clone, Debug)]
5pub struct Error {
6 pub code: ErrorCode,
8 pub extended: Option<i32>,
10 pub message: Option<String>,
12}
13
14pub type Result<T> = core::result::Result<T, Error>;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub enum ErrorCode {
20 Ok,
22 Error,
24 Internal,
26 Perm,
28 Abort,
30 Busy,
32 Locked,
34 NoMem,
36 ReadOnly,
38 Interrupt,
40 IoErr,
42 Corrupt,
44 NotFound,
46 Full,
48 CantOpen,
50 Protocol,
52 Empty,
54 Schema,
56 TooBig,
58 Constraint,
60 Mismatch,
62 Misuse,
64 NoLfs,
66 Auth,
68 Format,
70 Range,
72 NotADb,
74 Notice,
76 Warning,
78 Row,
80 Done,
82 FeatureUnavailable,
84 Unknown(i32),
86}
87
88impl ErrorCode {
89 pub const fn from_code(code: i32) -> ErrorCode {
91 let primary = code & 0xff;
92 match primary {
93 0 => ErrorCode::Ok,
94 1 => ErrorCode::Error,
95 2 => ErrorCode::Internal,
96 3 => ErrorCode::Perm,
97 4 => ErrorCode::Abort,
98 5 => ErrorCode::Busy,
99 6 => ErrorCode::Locked,
100 7 => ErrorCode::NoMem,
101 8 => ErrorCode::ReadOnly,
102 9 => ErrorCode::Interrupt,
103 10 => ErrorCode::IoErr,
104 11 => ErrorCode::Corrupt,
105 12 => ErrorCode::NotFound,
106 13 => ErrorCode::Full,
107 14 => ErrorCode::CantOpen,
108 15 => ErrorCode::Protocol,
109 16 => ErrorCode::Empty,
110 17 => ErrorCode::Schema,
111 18 => ErrorCode::TooBig,
112 19 => ErrorCode::Constraint,
113 20 => ErrorCode::Mismatch,
114 21 => ErrorCode::Misuse,
115 22 => ErrorCode::NoLfs,
116 23 => ErrorCode::Auth,
117 24 => ErrorCode::Format,
118 25 => ErrorCode::Range,
119 26 => ErrorCode::NotADb,
120 27 => ErrorCode::Notice,
121 28 => ErrorCode::Warning,
122 100 => ErrorCode::Row,
123 101 => ErrorCode::Done,
124 _ => ErrorCode::Unknown(code),
125 }
126 }
127
128 pub const fn code(self) -> Option<i32> {
130 match self {
131 ErrorCode::Ok => Some(0),
132 ErrorCode::Error => Some(1),
133 ErrorCode::Internal => Some(2),
134 ErrorCode::Perm => Some(3),
135 ErrorCode::Abort => Some(4),
136 ErrorCode::Busy => Some(5),
137 ErrorCode::Locked => Some(6),
138 ErrorCode::NoMem => Some(7),
139 ErrorCode::ReadOnly => Some(8),
140 ErrorCode::Interrupt => Some(9),
141 ErrorCode::IoErr => Some(10),
142 ErrorCode::Corrupt => Some(11),
143 ErrorCode::NotFound => Some(12),
144 ErrorCode::Full => Some(13),
145 ErrorCode::CantOpen => Some(14),
146 ErrorCode::Protocol => Some(15),
147 ErrorCode::Empty => Some(16),
148 ErrorCode::Schema => Some(17),
149 ErrorCode::TooBig => Some(18),
150 ErrorCode::Constraint => Some(19),
151 ErrorCode::Mismatch => Some(20),
152 ErrorCode::Misuse => Some(21),
153 ErrorCode::NoLfs => Some(22),
154 ErrorCode::Auth => Some(23),
155 ErrorCode::Format => Some(24),
156 ErrorCode::Range => Some(25),
157 ErrorCode::NotADb => Some(26),
158 ErrorCode::Notice => Some(27),
159 ErrorCode::Warning => Some(28),
160 ErrorCode::Row => Some(100),
161 ErrorCode::Done => Some(101),
162 ErrorCode::FeatureUnavailable => None,
163 ErrorCode::Unknown(code) => Some(code),
164 }
165 }
166}
167
168impl Error {
169 pub fn new(code: ErrorCode) -> Self {
171 Self {
172 code,
173 extended: None,
174 message: None,
175 }
176 }
177
178 pub fn with_message(code: ErrorCode, message: impl Into<String>) -> Self {
180 Self {
181 code,
182 extended: None,
183 message: Some(message.into()),
184 }
185 }
186
187 pub fn from_code(code: i32, message: Option<String>, extended: Option<i32>) -> Self {
189 Self {
190 code: ErrorCode::from_code(code),
191 extended,
192 message,
193 }
194 }
195
196 pub fn feature_unavailable(msg: &'static str) -> Self {
198 Self {
199 code: ErrorCode::FeatureUnavailable,
200 extended: None,
201 message: Some(msg.into()),
202 }
203 }
204}
205
206impl fmt::Display for Error {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 match (self.code, &self.message) {
209 (_, Some(msg)) => write!(f, "{}", msg),
210 (ErrorCode::Unknown(code), None) => write!(f, "sqlite error code {}", code),
211 (ErrorCode::FeatureUnavailable, None) => write!(f, "feature unavailable"),
212 (code, None) => write!(f, "sqlite error {:?}", code),
213 }
214 }
215}
216
217impl std::error::Error for Error {}
218
219#[cfg(test)]
220mod tests {
221 use super::{Error, ErrorCode};
222
223 #[test]
224 fn error_code_mapping() {
225 assert_eq!(ErrorCode::from_code(0), ErrorCode::Ok);
226 assert_eq!(ErrorCode::from_code(19), ErrorCode::Constraint);
227 assert_eq!(ErrorCode::from_code((8 << 8) | 19), ErrorCode::Constraint);
229 assert_eq!(ErrorCode::from_code(14), ErrorCode::CantOpen);
230 assert_eq!(ErrorCode::from_code(999), ErrorCode::Unknown(999));
231 }
232
233 #[test]
234 fn feature_unavailable_message() {
235 let err = Error::feature_unavailable("missing");
236 assert_eq!(err.code, ErrorCode::FeatureUnavailable);
237 assert_eq!(err.message.as_deref(), Some("missing"));
238 }
239}