Skip to content

Commit 7d1f453

Browse files
authored
Merge pull request #1382 from Lorak-mmk/box-arc-str-ser-deser
Serialization and deserialization of Box<str> and Arc<str>
2 parents e732aaa + 4a59e7e commit 7d1f453

File tree

6 files changed

+240
-6
lines changed

6 files changed

+240
-6
lines changed

docs/source/data-types/data-types.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Database types and their Rust equivalents:
1616
* `BigInt` <----> `i64`
1717
* `Float` <----> `f32`
1818
* `Double` <----> `f64`
19-
* `Ascii`, `Text`, `Varchar` <----> `&str`, `String`
19+
* `Ascii`, `Text`, `Varchar` <----> `&str`, `String`, `Box<str>`, `Arc<str>`
2020
* `Counter` <----> `value::Counter`
2121
* `Blob` <----> `Vec<u8>`
2222
* `Inet` <----> `std::net::IpAddr`
@@ -35,6 +35,7 @@ Database types and their Rust equivalents:
3535
* `UDT (User defined type)` <----> Custom user structs with macros
3636
* `Vector` <----> `Vec<T>`
3737

38+
Additionally, `Box` and `Arc` serialization and deserialization is supported for all above types.
3839

3940
```{eval-rst}
4041
.. toctree::

docs/source/data-types/text.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Ascii, Text, Varchar
2-
`Ascii`, `Text` and `Varchar` are represented as `&str` and `String`
2+
`Ascii`, `Text` and `Varchar` are represented as any of: `&str`, `String`, `Box<str>`, `Arc<str>`.
33

44
```rust
55
# extern crate scylla;
@@ -30,4 +30,4 @@ while let Some((text_value,)) = iter.try_next().await? {
3030
}
3131
# Ok(())
3232
# }
33-
```
33+
```

scylla-cql/src/deserialize/value.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,77 @@ impl<'frame, 'metadata> Iterator for UdtIterator<'frame, 'metadata> {
15241524
}
15251525
}
15261526

1527+
// Container implementations
1528+
1529+
impl<'frame, 'metadata, T: DeserializeValue<'frame, 'metadata>> DeserializeValue<'frame, 'metadata>
1530+
for Box<T>
1531+
{
1532+
fn type_check(typ: &ColumnType) -> Result<(), TypeCheckError> {
1533+
T::type_check(typ).map_err(typck_error_replace_rust_name::<Self>)
1534+
}
1535+
1536+
fn deserialize(
1537+
typ: &'metadata ColumnType<'metadata>,
1538+
v: Option<FrameSlice<'frame>>,
1539+
) -> Result<Self, DeserializationError> {
1540+
T::deserialize(typ, v)
1541+
.map(Box::new)
1542+
.map_err(deser_error_replace_rust_name::<Self>)
1543+
}
1544+
}
1545+
1546+
impl<'frame, 'metadata, T: DeserializeValue<'frame, 'metadata>> DeserializeValue<'frame, 'metadata>
1547+
for Arc<T>
1548+
{
1549+
fn type_check(typ: &ColumnType) -> Result<(), TypeCheckError> {
1550+
T::type_check(typ).map_err(typck_error_replace_rust_name::<Self>)
1551+
}
1552+
1553+
fn deserialize(
1554+
typ: &'metadata ColumnType<'metadata>,
1555+
v: Option<FrameSlice<'frame>>,
1556+
) -> Result<Self, DeserializationError> {
1557+
T::deserialize(typ, v)
1558+
.map(Arc::new)
1559+
.map_err(deser_error_replace_rust_name::<Self>)
1560+
}
1561+
}
1562+
1563+
// Special cases for Box<str> and Arc<str>
1564+
// The generic implementations above don't work for str. This is because
1565+
// DeserializeValue is implemented for &str, but not for str. We can't change this:
1566+
// the type for DeserializeValue must be Sized because it is returned from deserialize method.
1567+
1568+
impl<'frame, 'metadata> DeserializeValue<'frame, 'metadata> for Box<str> {
1569+
fn type_check(typ: &ColumnType) -> Result<(), TypeCheckError> {
1570+
<String as DeserializeValue>::type_check(typ).map_err(typck_error_replace_rust_name::<Self>)
1571+
}
1572+
1573+
fn deserialize(
1574+
typ: &'metadata ColumnType<'metadata>,
1575+
v: Option<FrameSlice<'frame>>,
1576+
) -> Result<Self, DeserializationError> {
1577+
String::deserialize(typ, v)
1578+
.map(String::into_boxed_str)
1579+
.map_err(deser_error_replace_rust_name::<Self>)
1580+
}
1581+
}
1582+
1583+
impl<'frame, 'metadata> DeserializeValue<'frame, 'metadata> for Arc<str> {
1584+
fn type_check(typ: &ColumnType) -> Result<(), TypeCheckError> {
1585+
<&str as DeserializeValue>::type_check(typ).map_err(typck_error_replace_rust_name::<Self>)
1586+
}
1587+
1588+
fn deserialize(
1589+
typ: &'metadata ColumnType<'metadata>,
1590+
v: Option<FrameSlice<'frame>>,
1591+
) -> Result<Self, DeserializationError> {
1592+
<&str as DeserializeValue>::deserialize(typ, v)
1593+
.map(Into::<Arc<str>>::into)
1594+
.map_err(deser_error_replace_rust_name::<Self>)
1595+
}
1596+
}
1597+
15271598
// Utilities
15281599

15291600
fn ensure_not_null_frame_slice<'frame, T>(

scylla-cql/src/deserialize/value_tests.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,40 @@ fn test_tuples() {
11571157
);
11581158
}
11591159

1160+
#[test]
1161+
fn test_box() {
1162+
{
1163+
let int = make_bytes(&[0x01, 0x02, 0x03, 0x04]);
1164+
let decoded_int: Box<i32> =
1165+
deserialize::<Box<i32>>(&ColumnType::Native(NativeType::Int), &int).unwrap();
1166+
assert_eq!(*decoded_int, 0x01020304);
1167+
}
1168+
1169+
{
1170+
let text_bytes = make_bytes(b"abcd");
1171+
let decoded_int: Box<str> =
1172+
deserialize::<Box<str>>(&ColumnType::Native(NativeType::Text), &text_bytes).unwrap();
1173+
assert_eq!(&*decoded_int, "abcd");
1174+
}
1175+
}
1176+
1177+
#[test]
1178+
fn test_arc() {
1179+
{
1180+
let int = make_bytes(&[0x01, 0x02, 0x03, 0x04]);
1181+
let decoded_int: Arc<i32> =
1182+
deserialize::<Arc<i32>>(&ColumnType::Native(NativeType::Int), &int).unwrap();
1183+
assert_eq!(*decoded_int, 0x01020304);
1184+
}
1185+
1186+
{
1187+
let text_bytes = make_bytes(b"abcd");
1188+
let decoded_int: Arc<str> =
1189+
deserialize::<Arc<str>>(&ColumnType::Native(NativeType::Text), &text_bytes).unwrap();
1190+
assert_eq!(&*decoded_int, "abcd");
1191+
}
1192+
}
1193+
11601194
pub(crate) fn udt_def_with_fields(
11611195
fields: impl IntoIterator<Item = (impl Into<Cow<'static, str>>, ColumnType<'static>)>,
11621196
) -> ColumnType<'static> {
@@ -2448,6 +2482,108 @@ fn test_null_errors() {
24482482
deserialize::<MaybeEmpty<i32>>(&ser_typ, &bytes).unwrap_err();
24492483
}
24502484

2485+
#[test]
2486+
fn test_box_errors() {
2487+
let v = 123_i32;
2488+
let bytes = serialize(&ColumnType::Native(NativeType::Int), &v);
2489+
2490+
// Incompatible types render type check error.
2491+
assert_type_check_error!(
2492+
&bytes,
2493+
Box<f64>,
2494+
ColumnType::Native(NativeType::Int),
2495+
BuiltinTypeCheckErrorKind::MismatchedType {
2496+
expected: &[ColumnType::Native(NativeType::Double)],
2497+
}
2498+
);
2499+
2500+
// ColumnType is said to be Double (8 bytes expected), but in reality the serialized form has 4 bytes only.
2501+
assert_deser_error!(
2502+
&bytes,
2503+
Box<f64>,
2504+
ColumnType::Native(NativeType::Double),
2505+
BuiltinDeserializationErrorKind::ByteLengthMismatch {
2506+
expected: 8,
2507+
got: 4,
2508+
}
2509+
);
2510+
2511+
// Arc<str> is a special case, let's test it separately
2512+
assert_type_check_error!(
2513+
&bytes,
2514+
Box<str>,
2515+
ColumnType::Native(NativeType::Int),
2516+
BuiltinTypeCheckErrorKind::MismatchedType {
2517+
expected: &[
2518+
ColumnType::Native(NativeType::Ascii),
2519+
ColumnType::Native(NativeType::Text)
2520+
],
2521+
}
2522+
);
2523+
2524+
// -126 is not a valid ASCII nor UTF-8 byte.
2525+
let v = -126_i8;
2526+
let bytes = serialize(&ColumnType::Native(NativeType::TinyInt), &v);
2527+
2528+
assert_deser_error!(
2529+
&bytes,
2530+
Box<str>,
2531+
ColumnType::Native(NativeType::Text),
2532+
BuiltinDeserializationErrorKind::InvalidUtf8(_)
2533+
);
2534+
}
2535+
2536+
#[test]
2537+
fn test_arc_errors() {
2538+
let v = 123_i32;
2539+
let bytes = serialize(&ColumnType::Native(NativeType::Int), &v);
2540+
2541+
// Incompatible types render type check error.
2542+
assert_type_check_error!(
2543+
&bytes,
2544+
Arc<f64>,
2545+
ColumnType::Native(NativeType::Int),
2546+
BuiltinTypeCheckErrorKind::MismatchedType {
2547+
expected: &[ColumnType::Native(NativeType::Double)],
2548+
}
2549+
);
2550+
2551+
// ColumnType is said to be Double (8 bytes expected), but in reality the serialized form has 4 bytes only.
2552+
assert_deser_error!(
2553+
&bytes,
2554+
Arc<f64>,
2555+
ColumnType::Native(NativeType::Double),
2556+
BuiltinDeserializationErrorKind::ByteLengthMismatch {
2557+
expected: 8,
2558+
got: 4,
2559+
}
2560+
);
2561+
2562+
// Arc<str> is a special case, let's test it separately
2563+
assert_type_check_error!(
2564+
&bytes,
2565+
Arc<str>,
2566+
ColumnType::Native(NativeType::Int),
2567+
BuiltinTypeCheckErrorKind::MismatchedType {
2568+
expected: &[
2569+
ColumnType::Native(NativeType::Ascii),
2570+
ColumnType::Native(NativeType::Text)
2571+
],
2572+
}
2573+
);
2574+
2575+
// -126 is not a valid ASCII nor UTF-8 byte.
2576+
let v = -126_i8;
2577+
let bytes = serialize(&ColumnType::Native(NativeType::TinyInt), &v);
2578+
2579+
assert_deser_error!(
2580+
&bytes,
2581+
Arc<str>,
2582+
ColumnType::Native(NativeType::Text),
2583+
BuiltinDeserializationErrorKind::InvalidUtf8(_)
2584+
);
2585+
}
2586+
24512587
#[test]
24522588
fn test_udt_errors() {
24532589
// Loose ordering

scylla-cql/src/serialize/value.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ impl SerializeValue for num_bigint_04::BigInt {
294294
.map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
295295
});
296296
}
297-
impl SerializeValue for &str {
297+
impl SerializeValue for str {
298298
impl_serialize_via_writer!(|me, typ, writer| {
299299
exact_type_check!(typ, Ascii, Text);
300300
writer
@@ -409,6 +409,15 @@ impl<T: SerializeValue + ?Sized> SerializeValue for Box<T> {
409409
T::serialize(&**self, typ, writer).map_err(fix_rust_name_in_err::<Self>)
410410
}
411411
}
412+
impl<T: SerializeValue + ?Sized> SerializeValue for Arc<T> {
413+
fn serialize<'b>(
414+
&self,
415+
typ: &ColumnType,
416+
writer: CellWriter<'b>,
417+
) -> Result<WrittenCellProof<'b>, SerializationError> {
418+
T::serialize(&**self, typ, writer).map_err(fix_rust_name_in_err::<Self>)
419+
}
420+
}
412421
impl<V: SerializeValue, S: BuildHasher + Default> SerializeValue for HashSet<V, S> {
413422
fn serialize<'b>(
414423
&self,
@@ -1066,7 +1075,7 @@ pub struct BuiltinTypeCheckError {
10661075
pub kind: BuiltinTypeCheckErrorKind,
10671076
}
10681077

1069-
fn mk_typck_err<T>(
1078+
fn mk_typck_err<T: ?Sized>(
10701079
got: &ColumnType,
10711080
kind: impl Into<BuiltinTypeCheckErrorKind>,
10721081
) -> SerializationError {
@@ -1099,7 +1108,7 @@ pub struct BuiltinSerializationError {
10991108
pub kind: BuiltinSerializationErrorKind,
11001109
}
11011110

1102-
pub(crate) fn mk_ser_err<T>(
1111+
pub(crate) fn mk_ser_err<T: ?Sized>(
11031112
got: &ColumnType,
11041113
kind: impl Into<BuiltinSerializationErrorKind>,
11051114
) -> SerializationError {

scylla-cql/src/serialize/value_tests.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,14 @@ fn test_box_errors() {
194194
));
195195
}
196196

197+
#[test]
198+
fn test_arc_errors() {
199+
verify_typeck_error_in_wrapper::<Arc<i32>>(Arc::new(123));
200+
verify_custom_error_in_wrapper::<Arc<SerializeWithCustomError>>(Arc::new(
201+
SerializeWithCustomError,
202+
));
203+
}
204+
197205
#[cfg(feature = "bigdecimal-04")]
198206
#[test]
199207
fn test_native_errors_bigdecimal_04() {
@@ -2225,6 +2233,15 @@ fn box_serialization() {
22252233
);
22262234
}
22272235

2236+
#[test]
2237+
fn arc_serialization() {
2238+
let x: Arc<i32> = Arc::new(123);
2239+
assert_eq!(
2240+
do_serialize(x, &ColumnType::Native(NativeType::Int)),
2241+
vec![0, 0, 0, 4, 0, 0, 0, 123]
2242+
);
2243+
}
2244+
22282245
#[test]
22292246
fn vec_set_serialization() {
22302247
let m = vec!["ala", "ma", "kota"];

0 commit comments

Comments
 (0)