Skip to content

Commit c80d558

Browse files
committed
feat: implement Encode,Decode for Arc<str>, Arc<[u8]>, Rc<str> and Rc<[u8]>
1 parent 3aa5ec9 commit c80d558

File tree

11 files changed

+171
-141
lines changed

11 files changed

+171
-141
lines changed

sqlx-core/src/decode.rs

-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ macro_rules! impl_decode_for_smartpointer {
8888
where
8989
DB: Database,
9090
T: Decode<'r, DB>,
91-
T: ?Sized,
9291
{
9392
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
9493
Ok(Self::new(T::decode(value)?))

sqlx-core/src/encode.rs

+25
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,28 @@ where
200200
<&T as Encode<DB>>::size_hint(&self.as_ref())
201201
}
202202
}
203+
204+
#[macro_export]
205+
macro_rules! forward_encode_impl {
206+
($for_type:ty, $forward_to:ty, $db:ident) => {
207+
impl<'q> Encode<'q, $db> for $for_type {
208+
fn encode_by_ref(
209+
&self,
210+
buf: &mut <$db as Database>::ArgumentBuffer<'q>,
211+
) -> Result<IsNull, BoxDynError> {
212+
<$forward_to as Encode<$db>>::encode(&**self, buf)
213+
}
214+
}
215+
};
216+
($for_type:ty, $forward_to:ty, $db:ident, $before:expr) => {
217+
impl<'q> Encode<'q, $db> for $for_type {
218+
fn encode_by_ref(
219+
&self,
220+
buf: &mut <$db as Database>::ArgumentBuffer<'q>,
221+
) -> Result<IsNull, BoxDynError> {
222+
let value = $before(self);
223+
<$forward_to as Encode<$db>>::encode(value, buf)
224+
}
225+
}
226+
};
227+
}

sqlx-mysql/src/types/bytes.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use std::borrow::Cow;
2+
use std::rc::Rc;
3+
use std::sync::Arc;
4+
5+
use sqlx_core::database::Database;
6+
17
use crate::decode::Decode;
28
use crate::encode::{Encode, IsNull};
39
use crate::error::BoxDynError;
@@ -40,12 +46,6 @@ impl<'r> Decode<'r, MySql> for &'r [u8] {
4046
}
4147
}
4248

43-
impl Encode<'_, MySql> for Box<[u8]> {
44-
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
45-
<&[u8] as Encode<MySql>>::encode(self.as_ref(), buf)
46-
}
47-
}
48-
4949
impl Type<MySql> for Vec<u8> {
5050
fn type_info() -> MySqlTypeInfo {
5151
<[u8] as Type<MySql>>::type_info()
@@ -67,3 +67,8 @@ impl Decode<'_, MySql> for Vec<u8> {
6767
<&[u8] as Decode<MySql>>::decode(value).map(ToOwned::to_owned)
6868
}
6969
}
70+
71+
forward_encode_impl!(Arc<[u8]>, &[u8], MySql);
72+
forward_encode_impl!(Rc<[u8]>, &[u8], MySql);
73+
forward_encode_impl!(Box<[u8]>, &[u8], MySql);
74+
forward_encode_impl!(Cow<'_, [u8]>, &[u8], MySql);

sqlx-mysql/src/types/str.rs

+9-26
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
use std::borrow::Cow;
2+
use std::rc::Rc;
3+
use std::sync::Arc;
4+
5+
use sqlx_core::database::Database;
26

37
use crate::decode::Decode;
48
use crate::encode::{Encode, IsNull};
@@ -47,12 +51,6 @@ impl<'r> Decode<'r, MySql> for &'r str {
4751
}
4852
}
4953

50-
impl Encode<'_, MySql> for Box<str> {
51-
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
52-
<&str as Encode<MySql>>::encode(&**self, buf)
53-
}
54-
}
55-
5654
impl Type<MySql> for String {
5755
fn type_info() -> MySqlTypeInfo {
5856
<str as Type<MySql>>::type_info()
@@ -63,29 +61,14 @@ impl Type<MySql> for String {
6361
}
6462
}
6563

66-
impl Encode<'_, MySql> for String {
67-
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
68-
<&str as Encode<MySql>>::encode(&**self, buf)
69-
}
70-
}
71-
7264
impl Decode<'_, MySql> for String {
7365
fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {
7466
<&str as Decode<MySql>>::decode(value).map(ToOwned::to_owned)
7567
}
7668
}
7769

78-
impl Encode<'_, MySql> for Cow<'_, str> {
79-
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
80-
match self {
81-
Cow::Borrowed(str) => <&str as Encode<MySql>>::encode(*str, buf),
82-
Cow::Owned(str) => <&str as Encode<MySql>>::encode(&**str, buf),
83-
}
84-
}
85-
}
86-
87-
impl Encode<'_, MySql> for Cow<'_, [u8]> {
88-
fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {
89-
<&[u8] as Encode<MySql>>::encode(self.as_ref(), buf)
90-
}
91-
}
70+
forward_encode_impl!(Arc<str>, &str, MySql);
71+
forward_encode_impl!(Rc<str>, &str, MySql);
72+
forward_encode_impl!(Cow<'_, str>, &str, MySql);
73+
forward_encode_impl!(Box<str>, &str, MySql);
74+
forward_encode_impl!(String, &str, MySql);

sqlx-postgres/src/types/bytes.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use std::borrow::Cow;
2+
use std::rc::Rc;
3+
use std::sync::Arc;
4+
5+
use sqlx_core::database::Database;
6+
17
use crate::decode::Decode;
28
use crate::encode::{Encode, IsNull};
39
use crate::error::BoxDynError;
@@ -42,12 +48,6 @@ impl Encode<'_, Postgres> for &'_ [u8] {
4248
}
4349
}
4450

45-
impl Encode<'_, Postgres> for Box<[u8]> {
46-
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
47-
<&[u8] as Encode<Postgres>>::encode(self.as_ref(), buf)
48-
}
49-
}
50-
5151
impl Encode<'_, Postgres> for Vec<u8> {
5252
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
5353
<&[u8] as Encode<Postgres>>::encode(self, buf)
@@ -101,3 +101,8 @@ impl<const N: usize> Decode<'_, Postgres> for [u8; N] {
101101
Ok(bytes)
102102
}
103103
}
104+
105+
forward_encode_impl!(Arc<[u8]>, &[u8], Postgres);
106+
forward_encode_impl!(Rc<[u8]>, &[u8], Postgres);
107+
forward_encode_impl!(Box<[u8]>, &[u8], Postgres);
108+
forward_encode_impl!(Cow<'_, [u8]>, &[u8], Postgres);

sqlx-postgres/src/types/str.rs

+9-26
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
use sqlx_core::database::Database;
2+
13
use crate::decode::Decode;
24
use crate::encode::{Encode, IsNull};
35
use crate::error::BoxDynError;
46
use crate::types::array_compatible;
57
use crate::types::Type;
68
use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};
79
use std::borrow::Cow;
10+
use std::rc::Rc;
11+
use std::sync::Arc;
812

913
impl Type<Postgres> for str {
1014
fn type_info() -> PgTypeInfo {
@@ -82,18 +86,6 @@ impl Encode<'_, Postgres> for &'_ str {
8286
}
8387
}
8488

85-
impl Encode<'_, Postgres> for Box<str> {
86-
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
87-
<&str as Encode<Postgres>>::encode(&**self, buf)
88-
}
89-
}
90-
91-
impl Encode<'_, Postgres> for String {
92-
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
93-
<&str as Encode<Postgres>>::encode(&**self, buf)
94-
}
95-
}
96-
9789
impl<'r> Decode<'r, Postgres> for &'r str {
9890
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
9991
value.as_str()
@@ -106,17 +98,8 @@ impl Decode<'_, Postgres> for String {
10698
}
10799
}
108100

109-
impl Encode<'_, Postgres> for Cow<'_, str> {
110-
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
111-
match self {
112-
Cow::Borrowed(str) => <&str as Encode<Postgres>>::encode(*str, buf),
113-
Cow::Owned(str) => <&str as Encode<Postgres>>::encode(&**str, buf),
114-
}
115-
}
116-
}
117-
118-
impl Encode<'_, Postgres> for Cow<'_, [u8]> {
119-
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {
120-
<&[u8] as Encode<Postgres>>::encode(self.as_ref(), buf)
121-
}
122-
}
101+
forward_encode_impl!(Arc<str>, &str, Postgres);
102+
forward_encode_impl!(Rc<str>, &str, Postgres);
103+
forward_encode_impl!(Cow<'_, str>, &str, Postgres);
104+
forward_encode_impl!(Box<str>, &str, Postgres);
105+
forward_encode_impl!(String, &str, Postgres);

sqlx-sqlite/src/types/bytes.rs

+9-19
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
use std::borrow::Cow;
2+
use std::rc::Rc;
3+
use std::sync::Arc;
4+
5+
use sqlx_core::database::Database;
26

37
use crate::decode::Decode;
48
use crate::encode::{Encode, IsNull};
@@ -34,25 +38,6 @@ impl<'r> Decode<'r, Sqlite> for &'r [u8] {
3438
}
3539
}
3640

37-
impl Encode<'_, Sqlite> for Box<[u8]> {
38-
fn encode(self, args: &mut Vec<SqliteArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
39-
args.push(SqliteArgumentValue::Blob(Cow::Owned(self.into_vec())));
40-
41-
Ok(IsNull::No)
42-
}
43-
44-
fn encode_by_ref(
45-
&self,
46-
args: &mut Vec<SqliteArgumentValue<'_>>,
47-
) -> Result<IsNull, BoxDynError> {
48-
args.push(SqliteArgumentValue::Blob(Cow::Owned(
49-
self.clone().into_vec(),
50-
)));
51-
52-
Ok(IsNull::No)
53-
}
54-
}
55-
5641
impl Type<Sqlite> for Vec<u8> {
5742
fn type_info() -> SqliteTypeInfo {
5843
<&[u8] as Type<Sqlite>>::type_info()
@@ -85,3 +70,8 @@ impl<'r> Decode<'r, Sqlite> for Vec<u8> {
8570
Ok(value.blob().to_owned())
8671
}
8772
}
73+
74+
forward_encode_impl!(Arc<[u8]>, Vec<u8>, Sqlite, |v: &[u8]| v.to_vec());
75+
forward_encode_impl!(Rc<[u8]>, Vec<u8>, Sqlite, |v: &[u8]| v.to_vec());
76+
forward_encode_impl!(Box<[u8]>, Vec<u8>, Sqlite, |v: &[u8]| v.to_vec());
77+
forward_encode_impl!(Cow<'_, [u8]>, Vec<u8>, Sqlite, |v: &[u8]| v.to_vec());

sqlx-sqlite/src/types/str.rs

+19-57
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
use std::borrow::Cow;
2+
use std::rc::Rc;
3+
use std::sync::Arc;
4+
5+
use sqlx_core::database::Database;
26

37
use crate::decode::Decode;
48
use crate::encode::{Encode, IsNull};
@@ -30,84 +34,42 @@ impl<'r> Decode<'r, Sqlite> for &'r str {
3034
}
3135
}
3236

33-
impl Encode<'_, Sqlite> for Box<str> {
34-
fn encode(self, args: &mut Vec<SqliteArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
35-
args.push(SqliteArgumentValue::Text(Cow::Owned(self.into_string())));
36-
37-
Ok(IsNull::No)
38-
}
39-
40-
fn encode_by_ref(
41-
&self,
42-
args: &mut Vec<SqliteArgumentValue<'_>>,
43-
) -> Result<IsNull, BoxDynError> {
44-
args.push(SqliteArgumentValue::Text(Cow::Owned(
45-
self.clone().into_string(),
46-
)));
47-
48-
Ok(IsNull::No)
49-
}
50-
}
51-
5237
impl Type<Sqlite> for String {
5338
fn type_info() -> SqliteTypeInfo {
5439
<&str as Type<Sqlite>>::type_info()
5540
}
5641
}
5742

58-
impl<'q> Encode<'q, Sqlite> for String {
59-
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
60-
args.push(SqliteArgumentValue::Text(Cow::Owned(self)));
61-
62-
Ok(IsNull::No)
63-
}
64-
65-
fn encode_by_ref(
66-
&self,
67-
args: &mut Vec<SqliteArgumentValue<'q>>,
68-
) -> Result<IsNull, BoxDynError> {
69-
args.push(SqliteArgumentValue::Text(Cow::Owned(self.clone())));
70-
71-
Ok(IsNull::No)
72-
}
73-
}
74-
7543
impl<'r> Decode<'r, Sqlite> for String {
7644
fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
7745
value.text().map(ToOwned::to_owned)
7846
}
7947
}
8048

81-
impl<'q> Encode<'q, Sqlite> for Cow<'q, str> {
82-
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
83-
args.push(SqliteArgumentValue::Text(self));
84-
85-
Ok(IsNull::No)
86-
}
87-
49+
impl<'q> Encode<'q, Sqlite> for String {
8850
fn encode_by_ref(
8951
&self,
9052
args: &mut Vec<SqliteArgumentValue<'q>>,
9153
) -> Result<IsNull, BoxDynError> {
92-
args.push(SqliteArgumentValue::Text(self.clone()));
54+
args.push(SqliteArgumentValue::Text(Cow::Owned(self.clone())));
9355

9456
Ok(IsNull::No)
9557
}
96-
}
9758

98-
impl<'q> Encode<'q, Sqlite> for Cow<'q, [u8]> {
99-
fn encode(self, args: &mut Vec<SqliteArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
100-
args.push(SqliteArgumentValue::Blob(self));
101-
102-
Ok(IsNull::No)
103-
}
104-
105-
fn encode_by_ref(
106-
&self,
107-
args: &mut Vec<SqliteArgumentValue<'q>>,
108-
) -> Result<IsNull, BoxDynError> {
109-
args.push(SqliteArgumentValue::Blob(self.clone()));
59+
fn encode(
60+
self,
61+
buf: &mut <Sqlite as Database>::ArgumentBuffer<'q>,
62+
) -> Result<IsNull, BoxDynError>
63+
where
64+
Self: Sized,
65+
{
66+
buf.push(SqliteArgumentValue::Text(Cow::Owned(self)));
11067

11168
Ok(IsNull::No)
11269
}
11370
}
71+
72+
forward_encode_impl!(Arc<str>, String, Sqlite, |s: &str| s.to_string());
73+
forward_encode_impl!(Rc<str>, String, Sqlite, |s: &str| s.to_string());
74+
forward_encode_impl!(Cow<'_, str>, String, Sqlite, |s: &str| s.to_string());
75+
forward_encode_impl!(Box<str>, String, Sqlite, |s: &str| s.to_string());

tests/mysql/types.rs

+26
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,29 @@ async fn test_str_slice() -> anyhow::Result<()> {
433433
assert!(data.3 == cow_slice);
434434
Ok(())
435435
}
436+
437+
#[sqlx_macros::test]
438+
async fn test_arc_str_slice() -> anyhow::Result<()> {
439+
let mut conn = new::<MySql>().await?;
440+
441+
let arc_str: Arc<str> = "Paul".into();
442+
let arc_slice: Arc<[u8]> = [5, 0].into();
443+
let rc_str: Rc<str> = "George".into();
444+
let rc_slice: Rc<[u8]> = [5, 0].into();
445+
446+
let row = sqlx::query("SELECT ?, ?, ?, ?")
447+
.bind(&arc_str)
448+
.bind(&arc_slice)
449+
.bind(&rc_str)
450+
.bind(&rc_slice)
451+
.fetch_one(&mut conn)
452+
.await?;
453+
454+
let data: (Arc<str>, Arc<[u8]>, Rc<str>, Rc<[u8]>) = FromRow::from_row(&row)?;
455+
456+
assert!(data.0 == arc_str);
457+
assert!(data.1 == arc_slice);
458+
assert!(data.2 == rc_str);
459+
assert!(data.3 == rc_slice);
460+
Ok(())
461+
}

0 commit comments

Comments
 (0)