From daf78839200553a237b429e1b138498127a8c538 Mon Sep 17 00:00:00 2001 From: H2CO3 Date: Mon, 26 Aug 2024 18:28:47 +0200 Subject: [PATCH 1/3] `impl FromSql` for various heap-allocated string and blob slices --- src/types/from_sql.rs | 89 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/types/from_sql.rs b/src/types/from_sql.rs index 381bb97..bbbfad9 100644 --- a/src/types/from_sql.rs +++ b/src/types/from_sql.rs @@ -1,5 +1,6 @@ use super::{Value, ValueRef}; use std::error::Error; +use std::borrow::Cow; use std::fmt; /// Enum listing possible errors from [`FromSql`] trait. @@ -204,6 +205,27 @@ impl FromSql for Vec { } } +impl FromSql for Box<[u8]> { + #[inline] + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + value.as_blob().map(Box::<[u8]>::from) + } +} + +impl FromSql for std::rc::Rc<[u8]> { + #[inline] + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + value.as_blob().map(std::rc::Rc::<[u8]>::from) + } +} + +impl FromSql for std::sync::Arc<[u8]> { + #[inline] + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + value.as_blob().map(std::sync::Arc::<[u8]>::from) + } +} + impl FromSql for [u8; N] { #[inline] fn column_result(value: ValueRef<'_>) -> FromSqlResult { @@ -245,6 +267,17 @@ impl FromSql for Option { } } +impl FromSql for Cow<'_, T> +where + T: ToOwned, + T::Owned: FromSql, +{ + #[inline] + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + ::column_result(value).map(Cow::Owned) + } +} + impl FromSql for Value { #[inline] fn column_result(value: ValueRef<'_>) -> FromSqlResult { @@ -254,6 +287,9 @@ impl FromSql for Value { #[cfg(test)] mod test { + use std::borrow::Cow; + use std::rc::Rc; + use std::sync::Arc; use super::FromSql; use crate::{Connection, Error, Result}; @@ -362,4 +398,57 @@ mod test { Ok(()) } + + #[test] + fn test_cow() -> Result<()> { + let db = Connection::open_in_memory()?; + + assert_eq!( + db.query_row("SELECT 'this is a string'", [], |r| r.get::<_, Cow<'_, str>>(0)), + Ok(Cow::Borrowed("this is a string")), + ); + assert_eq!( + db.query_row("SELECT x'09ab20fdee87'", [], |r| r.get::<_, Cow<'_, [u8]>>(0)), + Ok(Cow::Owned(vec![0x09, 0xab, 0x20, 0xfd, 0xee, 0x87])), + ); + assert_eq!( + db.query_row("SELECT 24.5", [], |r| r.get::<_, Cow<'_, f32>>(0)), + Ok(Cow::Borrowed(&24.5)), + ); + + Ok(()) + } + + #[test] + fn test_heap_slice() -> Result<()> { + let db = Connection::open_in_memory()?; + + assert_eq!( + db.query_row("SELECT 'Some string slice!'", [], |r| r.get::<_, Rc>(0)), + Ok(Rc::from("Some string slice!")), + ); + assert_eq!( + db.query_row("SELECT x'012366779988fedc'", [], |r| r.get::<_, Rc<[u8]>>(0)), + Ok(Rc::from(b"\x01\x23\x66\x77\x99\x88\xfe\xdc".as_slice())), + ); + + assert_eq!( + db.query_row( + "SELECT x'6120737472696e672043414e206265206120626c6f62'", + [], + |r| r.get::<_, Box<[u8]>>(0) + ), + Ok(b"a string CAN be a blob".to_vec().into_boxed_slice()), + ); + assert_eq!( + db.query_row("SELECT 'This is inside an Arc.'", [], |r| r.get::<_, Arc>(0)), + Ok(Arc::from("This is inside an Arc.")), + ); + assert_eq!( + db.query_row("SELECT x'afd374'", [], |r| r.get::<_, Arc<[u8]>>(0)), + Ok(Arc::from(b"\xaf\xd3\x74".as_slice())), + ); + + Ok(()) + } } From 12fbdfa5b18f7cf4b185d002aa2ede3b8fede2ab Mon Sep 17 00:00:00 2001 From: H2CO3 Date: Mon, 26 Aug 2024 19:43:04 +0200 Subject: [PATCH 2/3] Cater to `rustfmt` --- src/types/from_sql.rs | 48 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/types/from_sql.rs b/src/types/from_sql.rs index bbbfad9..063c252 100644 --- a/src/types/from_sql.rs +++ b/src/types/from_sql.rs @@ -1,6 +1,6 @@ use super::{Value, ValueRef}; -use std::error::Error; use std::borrow::Cow; +use std::error::Error; use std::fmt; /// Enum listing possible errors from [`FromSql`] trait. @@ -287,11 +287,11 @@ impl FromSql for Value { #[cfg(test)] mod test { + use super::FromSql; + use crate::{Connection, Error, Result}; use std::borrow::Cow; use std::rc::Rc; use std::sync::Arc; - use super::FromSql; - use crate::{Connection, Error, Result}; #[test] fn test_integral_ranges() -> Result<()> { @@ -404,15 +404,27 @@ mod test { let db = Connection::open_in_memory()?; assert_eq!( - db.query_row("SELECT 'this is a string'", [], |r| r.get::<_, Cow<'_, str>>(0)), + db.query_row( + "SELECT 'this is a string'", + [], + |r| r.get::<_, Cow<'_, str>>(0), + ), Ok(Cow::Borrowed("this is a string")), ); assert_eq!( - db.query_row("SELECT x'09ab20fdee87'", [], |r| r.get::<_, Cow<'_, [u8]>>(0)), + db.query_row( + "SELECT x'09ab20fdee87'", + [], + |r| r.get::<_, Cow<'_, [u8]>>(0), + ), Ok(Cow::Owned(vec![0x09, 0xab, 0x20, 0xfd, 0xee, 0x87])), ); assert_eq!( - db.query_row("SELECT 24.5", [], |r| r.get::<_, Cow<'_, f32>>(0)), + db.query_row( + "SELECT 24.5", + [], + |r| r.get::<_, Cow<'_, f32>>(0), + ), Ok(Cow::Borrowed(&24.5)), ); @@ -424,11 +436,19 @@ mod test { let db = Connection::open_in_memory()?; assert_eq!( - db.query_row("SELECT 'Some string slice!'", [], |r| r.get::<_, Rc>(0)), + db.query_row( + "SELECT 'Some string slice!'", + [], + |r| r.get::<_, Rc>(0), + ), Ok(Rc::from("Some string slice!")), ); assert_eq!( - db.query_row("SELECT x'012366779988fedc'", [], |r| r.get::<_, Rc<[u8]>>(0)), + db.query_row( + "SELECT x'012366779988fedc'", + [], + |r| r.get::<_, Rc<[u8]>>(0), + ), Ok(Rc::from(b"\x01\x23\x66\x77\x99\x88\xfe\xdc".as_slice())), ); @@ -441,11 +461,19 @@ mod test { Ok(b"a string CAN be a blob".to_vec().into_boxed_slice()), ); assert_eq!( - db.query_row("SELECT 'This is inside an Arc.'", [], |r| r.get::<_, Arc>(0)), + db.query_row( + "SELECT 'This is inside an Arc.'", + [], + |r| r.get::<_, Arc>(0), + ), Ok(Arc::from("This is inside an Arc.")), ); assert_eq!( - db.query_row("SELECT x'afd374'", [], |r| r.get::<_, Arc<[u8]>>(0)), + db.query_row( + "SELECT x'afd374'", + [], + |r| r.get::<_, Arc<[u8]>>(0), + ), Ok(Arc::from(b"\xaf\xd3\x74".as_slice())), ); From af1befed41bb3ea307b3ce4671a62b7acb854e7b Mon Sep 17 00:00:00 2001 From: H2CO3 Date: Tue, 27 Aug 2024 19:59:43 +0200 Subject: [PATCH 3/3] Applied `cargo fmt` --- src/types/from_sql.rs | 47 +++++++++++-------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/src/types/from_sql.rs b/src/types/from_sql.rs index 063c252..11abc62 100644 --- a/src/types/from_sql.rs +++ b/src/types/from_sql.rs @@ -404,27 +404,17 @@ mod test { let db = Connection::open_in_memory()?; assert_eq!( - db.query_row( - "SELECT 'this is a string'", - [], - |r| r.get::<_, Cow<'_, str>>(0), - ), + db.query_row("SELECT 'this is a string'", [], |r| r + .get::<_, Cow<'_, str>>(0)), Ok(Cow::Borrowed("this is a string")), ); assert_eq!( - db.query_row( - "SELECT x'09ab20fdee87'", - [], - |r| r.get::<_, Cow<'_, [u8]>>(0), - ), + db.query_row("SELECT x'09ab20fdee87'", [], |r| r + .get::<_, Cow<'_, [u8]>>(0)), Ok(Cow::Owned(vec![0x09, 0xab, 0x20, 0xfd, 0xee, 0x87])), ); assert_eq!( - db.query_row( - "SELECT 24.5", - [], - |r| r.get::<_, Cow<'_, f32>>(0), - ), + db.query_row("SELECT 24.5", [], |r| r.get::<_, Cow<'_, f32>>(0),), Ok(Cow::Borrowed(&24.5)), ); @@ -436,19 +426,13 @@ mod test { let db = Connection::open_in_memory()?; assert_eq!( - db.query_row( - "SELECT 'Some string slice!'", - [], - |r| r.get::<_, Rc>(0), - ), + db.query_row("SELECT 'Some string slice!'", [], |r| r + .get::<_, Rc>(0)), Ok(Rc::from("Some string slice!")), ); assert_eq!( - db.query_row( - "SELECT x'012366779988fedc'", - [], - |r| r.get::<_, Rc<[u8]>>(0), - ), + db.query_row("SELECT x'012366779988fedc'", [], |r| r + .get::<_, Rc<[u8]>>(0)), Ok(Rc::from(b"\x01\x23\x66\x77\x99\x88\xfe\xdc".as_slice())), ); @@ -461,19 +445,12 @@ mod test { Ok(b"a string CAN be a blob".to_vec().into_boxed_slice()), ); assert_eq!( - db.query_row( - "SELECT 'This is inside an Arc.'", - [], - |r| r.get::<_, Arc>(0), - ), + db.query_row("SELECT 'This is inside an Arc.'", [], |r| r + .get::<_, Arc>(0)), Ok(Arc::from("This is inside an Arc.")), ); assert_eq!( - db.query_row( - "SELECT x'afd374'", - [], - |r| r.get::<_, Arc<[u8]>>(0), - ), + db.query_row("SELECT x'afd374'", [], |r| r.get::<_, Arc<[u8]>>(0),), Ok(Arc::from(b"\xaf\xd3\x74".as_slice())), );