1use super::{Value, ValueRef};
2use std::convert::TryInto;
3use std::error::Error;
4use std::fmt;
5
6#[derive(Debug)]
8#[non_exhaustive]
9pub enum FromSqlError {
10 InvalidType,
13
14 OutOfRange(i64),
17
18 InvalidBlobSize {
21 expected_size: usize,
23 blob_size: usize,
25 },
26
27 Other(Box<dyn Error + Send + Sync + 'static>),
29}
30
31impl PartialEq for FromSqlError {
32 fn eq(&self, other: &FromSqlError) -> bool {
33 match (self, other) {
34 (FromSqlError::InvalidType, FromSqlError::InvalidType) => true,
35 (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
36 (
37 FromSqlError::InvalidBlobSize {
38 expected_size: es1,
39 blob_size: bs1,
40 },
41 FromSqlError::InvalidBlobSize {
42 expected_size: es2,
43 blob_size: bs2,
44 },
45 ) => es1 == es2 && bs1 == bs2,
46 (..) => false,
47 }
48 }
49}
50
51impl fmt::Display for FromSqlError {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match *self {
54 FromSqlError::InvalidType => write!(f, "Invalid type"),
55 FromSqlError::OutOfRange(i) => write!(f, "Value {i} out of range"),
56 FromSqlError::InvalidBlobSize {
57 expected_size,
58 blob_size,
59 } => {
60 write!(
61 f,
62 "Cannot read {expected_size} byte value out of {blob_size} byte blob"
63 )
64 }
65 FromSqlError::Other(ref err) => err.fmt(f),
66 }
67 }
68}
69
70impl Error for FromSqlError {
71 fn source(&self) -> Option<&(dyn Error + 'static)> {
72 if let FromSqlError::Other(ref err) = self {
73 Some(&**err)
74 } else {
75 None
76 }
77 }
78}
79
80pub type FromSqlResult<T> = Result<T, FromSqlError>;
82
83pub trait FromSql: Sized {
85 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
87}
88
89macro_rules! from_sql_integral(
90 ($t:ident) => (
91 impl FromSql for $t {
92 #[inline]
93 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
94 let i = i64::column_result(value)?;
95 i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
96 }
97 }
98 );
99 (non_zero $nz:ty, $z:ty) => (
100 impl FromSql for $nz {
101 #[inline]
102 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
103 let i = <$z>::column_result(value)?;
104 <$nz>::new(i).ok_or(FromSqlError::OutOfRange(0))
105 }
106 }
107 )
108);
109
110from_sql_integral!(i8);
111from_sql_integral!(i16);
112from_sql_integral!(i32);
113from_sql_integral!(isize);
115from_sql_integral!(u8);
116from_sql_integral!(u16);
117from_sql_integral!(u32);
118from_sql_integral!(u64);
119from_sql_integral!(usize);
120
121from_sql_integral!(non_zero std::num::NonZeroIsize, isize);
122from_sql_integral!(non_zero std::num::NonZeroI8, i8);
123from_sql_integral!(non_zero std::num::NonZeroI16, i16);
124from_sql_integral!(non_zero std::num::NonZeroI32, i32);
125from_sql_integral!(non_zero std::num::NonZeroI64, i64);
126#[cfg(feature = "i128_blob")]
127#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
128from_sql_integral!(non_zero std::num::NonZeroI128, i128);
129
130from_sql_integral!(non_zero std::num::NonZeroUsize, usize);
131from_sql_integral!(non_zero std::num::NonZeroU8, u8);
132from_sql_integral!(non_zero std::num::NonZeroU16, u16);
133from_sql_integral!(non_zero std::num::NonZeroU32, u32);
134from_sql_integral!(non_zero std::num::NonZeroU64, u64);
135impl FromSql for i64 {
138 #[inline]
139 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
140 value.as_i64()
141 }
142}
143
144impl FromSql for f32 {
145 #[inline]
146 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
147 match value {
148 ValueRef::Integer(i) => Ok(i as f32),
149 ValueRef::Real(f) => Ok(f as f32),
150 _ => Err(FromSqlError::InvalidType),
151 }
152 }
153}
154
155impl FromSql for f64 {
156 #[inline]
157 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
158 match value {
159 ValueRef::Integer(i) => Ok(i as f64),
160 ValueRef::Real(f) => Ok(f),
161 _ => Err(FromSqlError::InvalidType),
162 }
163 }
164}
165
166impl FromSql for bool {
167 #[inline]
168 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
169 i64::column_result(value).map(|i| i != 0)
170 }
171}
172
173impl FromSql for String {
174 #[inline]
175 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
176 value.as_str().map(ToString::to_string)
177 }
178}
179
180impl FromSql for Box<str> {
181 #[inline]
182 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
183 value.as_str().map(Into::into)
184 }
185}
186
187impl FromSql for std::rc::Rc<str> {
188 #[inline]
189 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
190 value.as_str().map(Into::into)
191 }
192}
193
194impl FromSql for std::sync::Arc<str> {
195 #[inline]
196 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
197 value.as_str().map(Into::into)
198 }
199}
200
201impl FromSql for Vec<u8> {
202 #[inline]
203 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
204 value.as_blob().map(<[u8]>::to_vec)
205 }
206}
207
208impl<const N: usize> FromSql for [u8; N] {
209 #[inline]
210 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
211 let slice = value.as_blob()?;
212 slice.try_into().map_err(|_| FromSqlError::InvalidBlobSize {
213 expected_size: N,
214 blob_size: slice.len(),
215 })
216 }
217}
218
219#[cfg(feature = "i128_blob")]
220#[cfg_attr(docsrs, doc(cfg(feature = "i128_blob")))]
221impl FromSql for i128 {
222 #[inline]
223 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
224 let bytes = <[u8; 16]>::column_result(value)?;
225 Ok(i128::from_be_bytes(bytes) ^ (1_i128 << 127))
226 }
227}
228
229#[cfg(feature = "uuid")]
230#[cfg_attr(docsrs, doc(cfg(feature = "uuid")))]
231impl FromSql for uuid::Uuid {
232 #[inline]
233 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
234 let bytes = <[u8; 16]>::column_result(value)?;
235 Ok(uuid::Uuid::from_u128(u128::from_be_bytes(bytes)))
236 }
237}
238
239impl<T: FromSql> FromSql for Option<T> {
240 #[inline]
241 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
242 match value {
243 ValueRef::Null => Ok(None),
244 _ => FromSql::column_result(value).map(Some),
245 }
246 }
247}
248
249impl FromSql for Value {
250 #[inline]
251 fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
252 Ok(value.into())
253 }
254}
255
256#[cfg(test)]
257mod test {
258 use super::FromSql;
259 use crate::{Connection, Error, Result};
260
261 #[test]
262 fn test_integral_ranges() -> Result<()> {
263 let db = Connection::open_in_memory()?;
264
265 fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
266 where
267 T: Into<i64> + FromSql + std::fmt::Debug,
268 {
269 for n in out_of_range {
270 let err = db
271 .query_row("SELECT ?1", [n], |r| r.get::<_, T>(0))
272 .unwrap_err();
273 match err {
274 Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
275 _ => panic!("unexpected error: {err}"),
276 }
277 }
278 for n in in_range {
279 assert_eq!(
280 *n,
281 db.query_row("SELECT ?1", [n], |r| r.get::<_, T>(0))
282 .unwrap()
283 .into()
284 );
285 }
286 }
287
288 check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
289 check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
290 check_ranges::<i32>(
291 &db,
292 &[-2_147_483_649, 2_147_483_648],
293 &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
294 );
295 check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
296 check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
297 check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
298 Ok(())
299 }
300
301 #[test]
302 fn test_nonzero_ranges() -> Result<()> {
303 let db = Connection::open_in_memory()?;
304
305 macro_rules! check_ranges {
306 ($nz:ty, $out_of_range:expr, $in_range:expr) => {
307 for &n in $out_of_range {
308 assert_eq!(
309 db.query_row("SELECT ?1", [n], |r| r.get::<_, $nz>(0)),
310 Err(Error::IntegralValueOutOfRange(0, n)),
311 "{}",
312 std::any::type_name::<$nz>()
313 );
314 }
315 for &n in $in_range {
316 let non_zero = <$nz>::new(n).unwrap();
317 assert_eq!(
318 Ok(non_zero),
319 db.query_row("SELECT ?1", [non_zero], |r| r.get::<_, $nz>(0))
320 );
321 }
322 };
323 }
324
325 check_ranges!(std::num::NonZeroI8, &[0, -129, 128], &[-128, 1, 127]);
326 check_ranges!(
327 std::num::NonZeroI16,
328 &[0, -32769, 32768],
329 &[-32768, -1, 1, 32767]
330 );
331 check_ranges!(
332 std::num::NonZeroI32,
333 &[0, -2_147_483_649, 2_147_483_648],
334 &[-2_147_483_648, -1, 1, 2_147_483_647]
335 );
336 check_ranges!(
337 std::num::NonZeroI64,
338 &[0],
339 &[-2_147_483_648, -1, 1, 2_147_483_647, i64::MAX, i64::MIN]
340 );
341 check_ranges!(
342 std::num::NonZeroIsize,
343 &[0],
344 &[-2_147_483_648, -1, 1, 2_147_483_647]
345 );
346 check_ranges!(std::num::NonZeroU8, &[0, -2, -1, 256], &[1, 255]);
347 check_ranges!(std::num::NonZeroU16, &[0, -2, -1, 65536], &[1, 65535]);
348 check_ranges!(
349 std::num::NonZeroU32,
350 &[0, -2, -1, 4_294_967_296],
351 &[1, 4_294_967_295]
352 );
353 check_ranges!(
354 std::num::NonZeroU64,
355 &[0, -2, -1, -4_294_967_296],
356 &[1, 4_294_967_295, i64::MAX as u64]
357 );
358 check_ranges!(
359 std::num::NonZeroUsize,
360 &[0, -2, -1, -4_294_967_296],
361 &[1, 4_294_967_295]
362 );
363
364 Ok(())
365 }
366}