From cf9e1c825860f96c89f35480428a589d591522fa Mon Sep 17 00:00:00 2001 From: Joey de Waal Date: Tue, 1 Jul 2025 22:02:05 +0200 Subject: [PATCH 1/3] implement Encode, Decode, Type for Arc and Arc<[u8]> (and Rc equivalents) --- sqlx-core/src/encode.rs | 14 ++++++++++++++ sqlx-mysql/src/types/bytes.rs | 17 ++++++----------- sqlx-mysql/src/types/str.rs | 27 +++++++-------------------- sqlx-postgres/src/types/bytes.rs | 17 ++++++----------- sqlx-postgres/src/types/str.rs | 29 ++++++++--------------------- sqlx-sqlite/src/types/bytes.rs | 28 ++++++++++++++++++++++++++++ sqlx-sqlite/src/types/str.rs | 28 ++++++++++++++++++++++++++++ tests/mysql/types.rs | 4 ++++ tests/postgres/types.rs | 4 ++++ tests/sqlite/types.rs | 4 ++++ 10 files changed, 109 insertions(+), 63 deletions(-) diff --git a/sqlx-core/src/encode.rs b/sqlx-core/src/encode.rs index 1a149b6e87..ba9a1d40c9 100644 --- a/sqlx-core/src/encode.rs +++ b/sqlx-core/src/encode.rs @@ -200,3 +200,17 @@ where <&T as Encode>::size_hint(&self.as_ref()) } } + +#[macro_export] +macro_rules! forward_encode_impl { + ($for_type:ty, $forward_to:ty, $db:ident) => { + impl<'q> Encode<'q, $db> for $for_type { + fn encode_by_ref( + &self, + buf: &mut <$db as sqlx_core::database::Database>::ArgumentBuffer<'q>, + ) -> Result { + <$forward_to as Encode<$db>>::encode(self.as_ref(), buf) + } + } + }; +} diff --git a/sqlx-mysql/src/types/bytes.rs b/sqlx-mysql/src/types/bytes.rs index 023a8ee87a..649fb9dc0a 100644 --- a/sqlx-mysql/src/types/bytes.rs +++ b/sqlx-mysql/src/types/bytes.rs @@ -1,4 +1,6 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -42,12 +44,6 @@ impl<'r> Decode<'r, MySql> for &'r [u8] { } } -impl Encode<'_, MySql> for Box<[u8]> { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&[u8] as Encode>::encode(self.as_ref(), buf) - } -} - impl Type for Vec { fn type_info() -> MySqlTypeInfo { <[u8] as Type>::type_info() @@ -70,8 +66,7 @@ impl Decode<'_, MySql> for Vec { } } -impl Encode<'_, MySql> for Cow<'_, [u8]> { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&[u8] as Encode>::encode(self.as_ref(), buf) - } -} +forward_encode_impl!(Arc<[u8]>, &[u8], MySql); +forward_encode_impl!(Rc<[u8]>, &[u8], MySql); +forward_encode_impl!(Box<[u8]>, &[u8], MySql); +forward_encode_impl!(Cow<'_, [u8]>, &[u8], MySql); diff --git a/sqlx-mysql/src/types/str.rs b/sqlx-mysql/src/types/str.rs index 4e2730577a..3a306fec45 100644 --- a/sqlx-mysql/src/types/str.rs +++ b/sqlx-mysql/src/types/str.rs @@ -1,4 +1,6 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -47,12 +49,6 @@ impl<'r> Decode<'r, MySql> for &'r str { } } -impl Encode<'_, MySql> for Box { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - impl Type for String { fn type_info() -> MySqlTypeInfo { >::type_info() @@ -63,23 +59,14 @@ impl Type for String { } } -impl Encode<'_, MySql> for String { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - impl Decode<'_, MySql> for String { fn decode(value: MySqlValueRef<'_>) -> Result { <&str as Decode>::decode(value).map(ToOwned::to_owned) } } -impl Encode<'_, MySql> for Cow<'_, str> { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - match self { - Cow::Borrowed(str) => <&str as Encode>::encode(*str, buf), - Cow::Owned(str) => <&str as Encode>::encode(&**str, buf), - } - } -} +forward_encode_impl!(Arc, &str, MySql); +forward_encode_impl!(Rc, &str, MySql); +forward_encode_impl!(Cow<'_, str>, &str, MySql); +forward_encode_impl!(Box, &str, MySql); +forward_encode_impl!(String, &str, MySql); diff --git a/sqlx-postgres/src/types/bytes.rs b/sqlx-postgres/src/types/bytes.rs index 17b7ce9a3f..16cbc14a07 100644 --- a/sqlx-postgres/src/types/bytes.rs +++ b/sqlx-postgres/src/types/bytes.rs @@ -1,4 +1,6 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -44,12 +46,6 @@ impl Encode<'_, Postgres> for &'_ [u8] { } } -impl Encode<'_, Postgres> for Box<[u8]> { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&[u8] as Encode>::encode(self.as_ref(), buf) - } -} - impl Encode<'_, Postgres> for Vec { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { <&[u8] as Encode>::encode(self, buf) @@ -104,8 +100,7 @@ impl Decode<'_, Postgres> for [u8; N] { } } -impl Encode<'_, Postgres> for Cow<'_, [u8]> { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&[u8] as Encode>::encode(self.as_ref(), buf) - } -} +forward_encode_impl!(Arc<[u8]>, &[u8], Postgres); +forward_encode_impl!(Rc<[u8]>, &[u8], Postgres); +forward_encode_impl!(Box<[u8]>, &[u8], Postgres); +forward_encode_impl!(Cow<'_, [u8]>, &[u8], Postgres); diff --git a/sqlx-postgres/src/types/str.rs b/sqlx-postgres/src/types/str.rs index 8b9c33ef47..8ab0a37af9 100644 --- a/sqlx-postgres/src/types/str.rs +++ b/sqlx-postgres/src/types/str.rs @@ -5,6 +5,8 @@ use crate::types::array_compatible; use crate::types::Type; use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres}; use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; impl Type for str { fn type_info() -> PgTypeInfo { @@ -82,27 +84,6 @@ impl Encode<'_, Postgres> for &'_ str { } } -impl Encode<'_, Postgres> for Cow<'_, str> { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - match self { - Cow::Borrowed(str) => <&str as Encode>::encode(*str, buf), - Cow::Owned(str) => <&str as Encode>::encode(&**str, buf), - } - } -} - -impl Encode<'_, Postgres> for Box { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - -impl Encode<'_, Postgres> for String { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - impl<'r> Decode<'r, Postgres> for &'r str { fn decode(value: PgValueRef<'r>) -> Result { value.as_str() @@ -114,3 +95,9 @@ impl Decode<'_, Postgres> for String { Ok(value.as_str()?.to_owned()) } } + +forward_encode_impl!(Arc, &str, Postgres); +forward_encode_impl!(Rc, &str, Postgres); +forward_encode_impl!(Cow<'_, str>, &str, Postgres); +forward_encode_impl!(Box, &str, Postgres); +forward_encode_impl!(String, &str, Postgres); diff --git a/sqlx-sqlite/src/types/bytes.rs b/sqlx-sqlite/src/types/bytes.rs index 48dffe0ae5..0218b34e78 100644 --- a/sqlx-sqlite/src/types/bytes.rs +++ b/sqlx-sqlite/src/types/bytes.rs @@ -1,4 +1,6 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -102,3 +104,29 @@ impl<'q> Encode<'q, Sqlite> for Cow<'q, [u8]> { Ok(IsNull::No) } } + +impl<'q> Encode<'q, Sqlite> for Arc<[u8]> { + fn encode(self, args: &mut Vec>) -> Result { + as Encode<'_, Sqlite>>::encode(self.to_vec(), args) + } + + fn encode_by_ref( + &self, + args: &mut Vec>, + ) -> Result { + >::encode(self.clone(), args) + } +} + +impl<'q> Encode<'q, Sqlite> for Rc<[u8]> { + fn encode(self, args: &mut Vec>) -> Result { + as Encode<'_, Sqlite>>::encode(self.to_vec(), args) + } + + fn encode_by_ref( + &self, + args: &mut Vec>, + ) -> Result { + >::encode(self.clone(), args) + } +} diff --git a/sqlx-sqlite/src/types/str.rs b/sqlx-sqlite/src/types/str.rs index 6c51fa1aff..3af7610095 100644 --- a/sqlx-sqlite/src/types/str.rs +++ b/sqlx-sqlite/src/types/str.rs @@ -1,4 +1,6 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -94,3 +96,29 @@ impl<'q> Encode<'q, Sqlite> for Cow<'q, str> { Ok(IsNull::No) } } + +impl<'q> Encode<'q, Sqlite> for Arc { + fn encode(self, args: &mut Vec>) -> Result { + >::encode(self.to_string(), args) + } + + fn encode_by_ref( + &self, + args: &mut Vec>, + ) -> Result { + >::encode(self.clone(), args) + } +} + +impl<'q> Encode<'q, Sqlite> for Rc { + fn encode(self, args: &mut Vec>) -> Result { + >::encode(self.to_string(), args) + } + + fn encode_by_ref( + &self, + args: &mut Vec>, + ) -> Result { + >::encode(self.clone(), args) + } +} diff --git a/tests/mysql/types.rs b/tests/mysql/types.rs index df46cdfd8a..9686d41721 100644 --- a/tests/mysql/types.rs +++ b/tests/mysql/types.rs @@ -310,9 +310,13 @@ test_type!(test_rc>(MySql, "1" == Rc::new(1i32))); test_type!(test_box_str>(MySql, "'John'" == Box::::from("John"))); test_type!(test_cow_str>(MySql, "'Phil'" == Cow::<'static, str>::from("Phil"))); +test_type!(test_arc_str>(MySql, "'1234'" == Arc::::from("1234"))); +test_type!(test_rc_str>(MySql, "'5678'" == Rc::::from("5678"))); test_prepared_type!(test_box_slice>(MySql, "X'01020304'" == Box::<[u8]>::from([1,2,3,4]))); test_prepared_type!(test_cow_slice>(MySql, "X'01020304'" == Cow::<'static, [u8]>::from(&[1,2,3,4]))); +test_prepared_type!(test_arc_slice>(MySql, "X'01020304'" == Arc::<[u8]>::from([1,2,3,4]))); +test_prepared_type!(test_rc_slice>(MySql, "X'01020304'" == Rc::<[u8]>::from([1,2,3,4]))); #[sqlx_macros::test] async fn test_bits() -> anyhow::Result<()> { diff --git a/tests/postgres/types.rs b/tests/postgres/types.rs index 569fe585e1..8a9288ba75 100644 --- a/tests/postgres/types.rs +++ b/tests/postgres/types.rs @@ -704,9 +704,13 @@ test_type!(test_rc>(Postgres, "1::INT4" == Rc::new(1i32))); test_type!(test_box_str>(Postgres, "'John'::TEXT" == Box::::from("John"))); test_type!(test_cow_str>(Postgres, "'Phil'::TEXT" == Cow::<'static, str>::from("Phil"))); +test_type!(test_arc_str>(Postgres, "'1234'::TEXT" == Arc::::from("1234"))); +test_type!(test_rc_str>(Postgres, "'5678'::TEXT" == Rc::::from("5678"))); test_prepared_type!(test_box_slice>(Postgres, "'\\x01020304'::BYTEA" == Box::<[u8]>::from([1,2,3,4]))); test_prepared_type!(test_cow_slice>(Postgres, "'\\x01020304'::BYTEA" == Cow::<'static, [u8]>::from(&[1,2,3,4]))); +test_prepared_type!(test_arc_slice>(Postgres, "'\\x01020304'::BYTEA" == Arc::<[u8]>::from([1,2,3,4]))); +test_prepared_type!(test_rc_slice>(Postgres, "'\\x01020304'::BYTEA" == Rc::<[u8]>::from([1,2,3,4]))); #[sqlx_macros::test] async fn test_text_adapter() -> anyhow::Result<()> { diff --git a/tests/sqlite/types.rs b/tests/sqlite/types.rs index de949d5259..302ad54a61 100644 --- a/tests/sqlite/types.rs +++ b/tests/sqlite/types.rs @@ -219,9 +219,13 @@ test_type!(test_rc>(Sqlite, "1" == Rc::new(1i32))); test_type!(test_box_str>(Sqlite, "'John'" == Box::::from("John"))); test_type!(test_cow_str>(Sqlite, "'Phil'" == Cow::<'static, str>::from("Phil"))); +test_type!(test_arc_str>(Sqlite, "'1234'" == Arc::::from("1234"))); +test_type!(test_rc_str>(Sqlite, "'5678'" == Rc::::from("5678"))); test_type!(test_box_slice>(Sqlite, "X'01020304'" == Box::<[u8]>::from([1,2,3,4]))); test_type!(test_cow_slice>(Sqlite, "X'01020304'" == Cow::<'static, [u8]>::from(&[1,2,3,4]))); +test_type!(test_arc_slice>(Sqlite, "X'01020304'" == Arc::<[u8]>::from([1,2,3,4]))); +test_type!(test_rc_slice>(Sqlite, "X'01020304'" == Rc::<[u8]>::from([1,2,3,4]))); #[sqlx_macros::test] async fn test_text_adapter() -> anyhow::Result<()> { From adf4e0e5aea149c90188247f4159214278f3cbc3 Mon Sep 17 00:00:00 2001 From: Joey de Waal Date: Wed, 2 Jul 2025 11:28:18 +0200 Subject: [PATCH 2/3] sqlx-sqlite: Remove clone in Encode impl --- sqlx-sqlite/src/types/bytes.rs | 4 ++-- sqlx-sqlite/src/types/str.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sqlx-sqlite/src/types/bytes.rs b/sqlx-sqlite/src/types/bytes.rs index 0218b34e78..0e0d49f380 100644 --- a/sqlx-sqlite/src/types/bytes.rs +++ b/sqlx-sqlite/src/types/bytes.rs @@ -114,7 +114,7 @@ impl<'q> Encode<'q, Sqlite> for Arc<[u8]> { &self, args: &mut Vec>, ) -> Result { - >::encode(self.clone(), args) + as Encode<'_, Sqlite>>::encode(self.to_vec(), args) } } @@ -127,6 +127,6 @@ impl<'q> Encode<'q, Sqlite> for Rc<[u8]> { &self, args: &mut Vec>, ) -> Result { - >::encode(self.clone(), args) + as Encode<'_, Sqlite>>::encode(self.to_vec(), args) } } diff --git a/sqlx-sqlite/src/types/str.rs b/sqlx-sqlite/src/types/str.rs index 3af7610095..dfaddfe333 100644 --- a/sqlx-sqlite/src/types/str.rs +++ b/sqlx-sqlite/src/types/str.rs @@ -106,7 +106,7 @@ impl<'q> Encode<'q, Sqlite> for Arc { &self, args: &mut Vec>, ) -> Result { - >::encode(self.clone(), args) + >::encode(self.to_string(), args) } } @@ -119,6 +119,6 @@ impl<'q> Encode<'q, Sqlite> for Rc { &self, args: &mut Vec>, ) -> Result { - >::encode(self.clone(), args) + >::encode(self.to_string(), args) } } From 9b2ba4962e778fdc576469163bcd4ef3d5e2f469 Mon Sep 17 00:00:00 2001 From: Joey de Waal Date: Wed, 2 Jul 2025 14:39:53 +0200 Subject: [PATCH 3/3] sqlx-sqlite: Remove unnecessary impls --- sqlx-sqlite/src/types/bytes.rs | 8 -------- sqlx-sqlite/src/types/str.rs | 8 -------- 2 files changed, 16 deletions(-) diff --git a/sqlx-sqlite/src/types/bytes.rs b/sqlx-sqlite/src/types/bytes.rs index 0e0d49f380..af625579e0 100644 --- a/sqlx-sqlite/src/types/bytes.rs +++ b/sqlx-sqlite/src/types/bytes.rs @@ -106,10 +106,6 @@ impl<'q> Encode<'q, Sqlite> for Cow<'q, [u8]> { } impl<'q> Encode<'q, Sqlite> for Arc<[u8]> { - fn encode(self, args: &mut Vec>) -> Result { - as Encode<'_, Sqlite>>::encode(self.to_vec(), args) - } - fn encode_by_ref( &self, args: &mut Vec>, @@ -119,10 +115,6 @@ impl<'q> Encode<'q, Sqlite> for Arc<[u8]> { } impl<'q> Encode<'q, Sqlite> for Rc<[u8]> { - fn encode(self, args: &mut Vec>) -> Result { - as Encode<'_, Sqlite>>::encode(self.to_vec(), args) - } - fn encode_by_ref( &self, args: &mut Vec>, diff --git a/sqlx-sqlite/src/types/str.rs b/sqlx-sqlite/src/types/str.rs index dfaddfe333..8acd0d8798 100644 --- a/sqlx-sqlite/src/types/str.rs +++ b/sqlx-sqlite/src/types/str.rs @@ -98,10 +98,6 @@ impl<'q> Encode<'q, Sqlite> for Cow<'q, str> { } impl<'q> Encode<'q, Sqlite> for Arc { - fn encode(self, args: &mut Vec>) -> Result { - >::encode(self.to_string(), args) - } - fn encode_by_ref( &self, args: &mut Vec>, @@ -111,10 +107,6 @@ impl<'q> Encode<'q, Sqlite> for Arc { } impl<'q> Encode<'q, Sqlite> for Rc { - fn encode(self, args: &mut Vec>) -> Result { - >::encode(self.to_string(), args) - } - fn encode_by_ref( &self, args: &mut Vec>,