aboutsummaryrefslogtreecommitdiff
path: root/src/types/from_sql.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/types/from_sql.rs')
-rw-r--r--src/types/from_sql.rs79
1 files changed, 39 insertions, 40 deletions
diff --git a/src/types/from_sql.rs b/src/types/from_sql.rs
index 3fe74b4..7381fdf 100644
--- a/src/types/from_sql.rs
+++ b/src/types/from_sql.rs
@@ -1,8 +1,9 @@
use super::{Value, ValueRef};
+use std::convert::TryInto;
use std::error::Error;
use std::fmt;
-/// Enum listing possible errors from `FromSql` trait.
+/// Enum listing possible errors from [`FromSql`] trait.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromSqlError {
@@ -25,7 +26,7 @@ pub enum FromSqlError {
#[cfg(feature = "uuid")]
InvalidUuidSize(usize),
- /// An error case available for implementors of the `FromSql` trait.
+ /// An error case available for implementors of the [`FromSql`] trait.
Other(Box<dyn Error + Send + Sync + 'static>),
}
@@ -71,48 +72,22 @@ impl Error for FromSqlError {
}
}
-/// Result type for implementors of the `FromSql` trait.
+/// Result type for implementors of the [`FromSql`] trait.
pub type FromSqlResult<T> = Result<T, FromSqlError>;
/// A trait for types that can be created from a SQLite value.
-///
-/// Note that `FromSql` and `ToSql` are defined for most integral types, but
-/// not `u64` or `usize`. This is intentional; SQLite returns integers as
-/// signed 64-bit values, which cannot fully represent the range of these
-/// types. Rusqlite would have to
-/// decide how to handle negative values: return an error or reinterpret as a
-/// very large postive numbers, neither of which
-/// is guaranteed to be correct for everyone. Callers can work around this by
-/// fetching values as i64 and then doing the interpretation themselves or by
-/// defining a newtype and implementing `FromSql`/`ToSql` for it.
pub trait FromSql: Sized {
/// Converts SQLite value into Rust value.
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
}
-impl FromSql for isize {
- fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
- i64::column_result(value).and_then(|i| {
- if i < isize::min_value() as i64 || i > isize::max_value() as i64 {
- Err(FromSqlError::OutOfRange(i))
- } else {
- Ok(i as isize)
- }
- })
- }
-}
-
macro_rules! from_sql_integral(
($t:ident) => (
impl FromSql for $t {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
- i64::column_result(value).and_then(|i| {
- if i < i64::from($t::min_value()) || i > i64::from($t::max_value()) {
- Err(FromSqlError::OutOfRange(i))
- } else {
- Ok(i as $t)
- }
- })
+ let i = i64::column_result(value)?;
+ i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
}
}
)
@@ -121,17 +96,34 @@ macro_rules! from_sql_integral(
from_sql_integral!(i8);
from_sql_integral!(i16);
from_sql_integral!(i32);
+// from_sql_integral!(i64); // Not needed because the native type is i64.
+from_sql_integral!(isize);
from_sql_integral!(u8);
from_sql_integral!(u16);
from_sql_integral!(u32);
+from_sql_integral!(u64);
+from_sql_integral!(usize);
impl FromSql for i64 {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_i64()
}
}
+impl FromSql for f32 {
+ #[inline]
+ fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+ match value {
+ ValueRef::Integer(i) => Ok(i as f32),
+ ValueRef::Real(f) => Ok(f as f32),
+ _ => Err(FromSqlError::InvalidType),
+ }
+ }
+}
+
impl FromSql for f64 {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Integer(i) => Ok(i as f64),
@@ -142,36 +134,42 @@ impl FromSql for f64 {
}
impl FromSql for bool {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
- i64::column_result(value).map(|i| !matches!(i, 0))
+ i64::column_result(value).map(|i| i != 0)
}
}
impl FromSql for String {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(ToString::to_string)
}
}
impl FromSql for Box<str> {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(Into::into)
}
}
impl FromSql for std::rc::Rc<str> {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(Into::into)
}
}
impl FromSql for std::sync::Arc<str> {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_str().map(Into::into)
}
}
impl FromSql for Vec<u8> {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value.as_blob().map(|b| b.to_vec())
}
@@ -179,6 +177,7 @@ impl FromSql for Vec<u8> {
#[cfg(feature = "i128_blob")]
impl FromSql for i128 {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
use byteorder::{BigEndian, ByteOrder};
@@ -194,6 +193,7 @@ impl FromSql for i128 {
#[cfg(feature = "uuid")]
impl FromSql for uuid::Uuid {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
value
.as_blob()
@@ -206,6 +206,7 @@ impl FromSql for uuid::Uuid {
}
impl<T: FromSql> FromSql for Option<T> {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
match value {
ValueRef::Null => Ok(None),
@@ -215,6 +216,7 @@ impl<T: FromSql> FromSql for Option<T> {
}
impl FromSql for Value {
+ #[inline]
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
Ok(value.into())
}
@@ -223,15 +225,11 @@ impl FromSql for Value {
#[cfg(test)]
mod test {
use super::FromSql;
- use crate::{Connection, Error};
-
- fn checked_memory_handle() -> Connection {
- Connection::open_in_memory().unwrap()
- }
+ use crate::{Connection, Error, Result};
#[test]
- fn test_integral_ranges() {
- let db = checked_memory_handle();
+ fn test_integral_ranges() -> Result<()> {
+ let db = Connection::open_in_memory()?;
fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
where
@@ -266,5 +264,6 @@ mod test {
check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
+ Ok(())
}
}