Skip to content

Commit

Permalink
serialize: add ValueAdapter and ValueListAdapter
Browse files Browse the repository at this point in the history
Add newtype wrappers that implement `SerializeRow`/`SerializeCql` if the
type wrapped over implements `ValueList`/`Value`. It should be useful
when migrating codebases to the new traits gradually so that objects
from the unchanged code which only implement the old trait can be passed
to the code which was already updated to the new traits.
  • Loading branch information
piodul committed Dec 18, 2023
1 parent 99330c8 commit abee437
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 3 deletions.
56 changes: 55 additions & 1 deletion scylla-cql/src/types/serialize/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,34 @@ macro_rules! impl_serialize_row_via_value_list {
};
}

/// Implements [`SerializeRow`] if the type wrapped over implements [`ValueList`].
///
/// See the [`impl_serialize_row_via_value_list`] macro on information about
/// the properties of the [`SerializeRow`] implementation.
pub struct ValueListAdapter<T>(pub T);

impl<T> SerializeRow for ValueListAdapter<T>
where
T: ValueList,
{
#[inline]
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError> {
serialize_legacy_row(&self.0, ctx, writer)
}

#[inline]
fn is_empty(&self) -> bool {
match self.0.serialized() {
Ok(s) => s.is_empty(),
Err(_) => false,
}
}
}

/// Serializes an object implementing [`ValueList`] by using the [`RowWriter`]
/// interface.
///
Expand Down Expand Up @@ -822,11 +850,13 @@ impl<'a> Iterator for SerializedValuesIterator<'a> {

#[cfg(test)]
mod tests {
use std::borrow::Cow;
use std::collections::BTreeMap;

use crate::frame::response::result::{ColumnSpec, ColumnType, TableSpec};
use crate::frame::types::RawValue;
use crate::frame::value::{LegacySerializedValues, MaybeUnset, ValueList};
use crate::frame::value::{LegacySerializedValues, MaybeUnset, SerializedResult, ValueList};
use crate::types::serialize::row::ValueListAdapter;
use crate::types::serialize::{RowWriter, SerializationError};

use super::{
Expand Down Expand Up @@ -973,6 +1003,30 @@ mod tests {
}
}

#[test]
fn test_legacy_wrapper() {
struct Foo;
impl ValueList for Foo {
fn serialized(&self) -> SerializedResult<'_> {
let mut values = LegacySerializedValues::new();
values.add_value(&123i32)?;
values.add_value(&321i32)?;
Ok(Cow::Owned(values))
}
}

let columns = &[
col_spec("a", ColumnType::Int),
col_spec("b", ColumnType::Int),
];
let buf = do_serialize(ValueListAdapter(Foo), columns);
let expected = vec![
0, 0, 0, 4, 0, 0, 0, 123, // First value
0, 0, 0, 4, 0, 0, 1, 65, // Second value
];
assert_eq!(buf, expected);
}

fn get_typeck_err(err: &SerializationError) -> &BuiltinTypeCheckError {
match err.0.downcast_ref() {
Some(err) => err,
Expand Down
44 changes: 42 additions & 2 deletions scylla-cql/src/types/serialize/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,26 @@ macro_rules! impl_serialize_cql_via_value {
};
}

/// Implements [`SerializeCql`] if the type wrapped over implements [`Value`].
///
/// See the [`impl_serialize_cql_via_value`] macro on information about
/// the properties of the [`SerializeCql`] implementation.
pub struct ValueAdapter<T>(pub T);

impl<T> SerializeCql for ValueAdapter<T>
where
T: Value,
{
#[inline]
fn serialize<'b>(
&self,
_typ: &ColumnType,
writer: CellWriter<'b>,
) -> Result<WrittenCellProof<'b>, SerializationError> {
serialize_legacy_value(&self.0, writer)
}
}

/// Serializes a value implementing [`Value`] by using the [`CellWriter`]
/// interface.
///
Expand Down Expand Up @@ -1470,12 +1490,12 @@ mod tests {
use std::collections::BTreeMap;

use crate::frame::response::result::{ColumnType, CqlValue};
use crate::frame::value::{MaybeUnset, Unset, Value};
use crate::frame::value::{MaybeUnset, Unset, Value, ValueTooBig};
use crate::types::serialize::value::{
BuiltinSerializationError, BuiltinSerializationErrorKind, BuiltinTypeCheckError,
BuiltinTypeCheckErrorKind, MapSerializationErrorKind, MapTypeCheckErrorKind,
SetOrListSerializationErrorKind, SetOrListTypeCheckErrorKind, TupleSerializationErrorKind,
TupleTypeCheckErrorKind,
TupleTypeCheckErrorKind, ValueAdapter,
};
use crate::types::serialize::{CellWriter, SerializationError};

Expand Down Expand Up @@ -1531,6 +1551,26 @@ mod tests {
t.serialize(typ, writer).unwrap_err()
}

#[test]
fn test_legacy_wrapper() {
struct Foo;
impl Value for Foo {
fn serialize(&self, buf: &mut Vec<u8>) -> Result<(), ValueTooBig> {
let s = "Ala ma kota";
buf.extend_from_slice(&(s.len() as i32).to_be_bytes());
buf.extend_from_slice(s.as_bytes());
Ok(())
}
}

let buf = do_serialize(ValueAdapter(Foo), &ColumnType::Text);
let expected = vec![
0, 0, 0, 11, // Length of the value
65, 108, 97, 32, 109, 97, 32, 107, 111, 116, 97, // The string
];
assert_eq!(buf, expected);
}

fn get_typeck_err(err: &SerializationError) -> &BuiltinTypeCheckError {
match err.0.downcast_ref() {
Some(err) => err,
Expand Down

0 comments on commit abee437

Please sign in to comment.