scylla_cql/serialize/
row.rs

1//! Contains the [`SerializeRow`] trait and its implementations.
2
3// Note: When editing above doc-comment edit the corresponding comment on
4// re-export module in scylla crate too.
5
6use std::collections::{BTreeMap, HashSet};
7use std::fmt::Display;
8use std::hash::BuildHasher;
9use std::{collections::HashMap, sync::Arc};
10
11use bytes::BufMut;
12use thiserror::Error;
13
14use crate::frame::request::RequestDeserializationError;
15use crate::frame::response::result::ColumnType;
16use crate::frame::response::result::PreparedMetadata;
17use crate::frame::types;
18use crate::frame::{response::result::ColumnSpec, types::RawValue};
19
20use super::value::SerializeValue;
21use super::{CellWriter, RowWriter, SerializationError};
22
23/// Contains information needed to serialize a row.
24pub struct RowSerializationContext<'a> {
25    pub(crate) columns: &'a [ColumnSpec<'a>],
26}
27
28impl<'a> RowSerializationContext<'a> {
29    /// Creates the serialization context from prepared statement metadata.
30    #[inline]
31    pub fn from_prepared(prepared: &'a PreparedMetadata) -> Self {
32        Self {
33            columns: prepared.col_specs.as_slice(),
34        }
35    }
36
37    /// Creates the serialization context directly from column specs.
38    #[inline]
39    pub fn from_specs(specs: &'a [ColumnSpec<'a>]) -> Self {
40        Self { columns: specs }
41    }
42
43    /// Constructs an empty `RowSerializationContext`, as if for a statement
44    /// with no bind markers.
45    #[inline]
46    pub const fn empty() -> Self {
47        Self { columns: &[] }
48    }
49
50    /// Returns column/bind marker specifications for given query.
51    #[inline]
52    pub fn columns(&self) -> &'a [ColumnSpec] {
53        self.columns
54    }
55}
56
57/// Represents a set of values that can be sent along a CQL statement.
58///
59/// This is a low-level trait that is exposed to the specifics to the CQL
60/// protocol and usually does not have to be implemented directly. See the
61/// chapter on "Query Values" in the driver docs for information about how
62/// this trait is supposed to be used.
63pub trait SerializeRow {
64    /// Serializes the row according to the information in the given context.
65    ///
66    /// It's the trait's responsibility to produce values in the order as
67    /// specified in given serialization context.
68    fn serialize(
69        &self,
70        ctx: &RowSerializationContext<'_>,
71        writer: &mut RowWriter,
72    ) -> Result<(), SerializationError>;
73
74    /// Returns whether this row contains any values or not.
75    ///
76    /// This method is used before executing a simple statement in order to check
77    /// whether there are any values provided to it. If there are some, then
78    /// the query will be prepared first in order to obtain information about
79    /// the bind marker types and names so that the values can be properly
80    /// type checked and serialized.
81    fn is_empty(&self) -> bool;
82}
83
84macro_rules! impl_serialize_row_for_unit {
85    () => {
86        fn serialize(
87            &self,
88            ctx: &RowSerializationContext<'_>,
89            _writer: &mut RowWriter,
90        ) -> Result<(), SerializationError> {
91            if !ctx.columns().is_empty() {
92                return Err(mk_typck_err::<Self>(
93                    BuiltinTypeCheckErrorKind::WrongColumnCount {
94                        rust_cols: 0,
95                        cql_cols: ctx.columns().len(),
96                    },
97                ));
98            }
99            // Row is empty - do nothing
100            Ok(())
101        }
102
103        #[inline]
104        fn is_empty(&self) -> bool {
105            true
106        }
107    };
108}
109
110impl SerializeRow for () {
111    impl_serialize_row_for_unit!();
112}
113
114impl SerializeRow for [u8; 0] {
115    impl_serialize_row_for_unit!();
116}
117
118macro_rules! impl_serialize_row_for_slice {
119    () => {
120        fn serialize(
121            &self,
122            ctx: &RowSerializationContext<'_>,
123            writer: &mut RowWriter,
124        ) -> Result<(), SerializationError> {
125            if ctx.columns().len() != self.len() {
126                return Err(mk_typck_err::<Self>(
127                    BuiltinTypeCheckErrorKind::WrongColumnCount {
128                        rust_cols: self.len(),
129                        cql_cols: ctx.columns().len(),
130                    },
131                ));
132            }
133            for (col, val) in ctx.columns().iter().zip(self.iter()) {
134                $crate::_macro_internal::ser::row::serialize_column::<Self>(val, col, writer)?;
135            }
136            Ok(())
137        }
138
139        #[inline]
140        fn is_empty(&self) -> bool {
141            <[T]>::is_empty(self.as_ref())
142        }
143    };
144}
145
146impl<'a, T: SerializeValue + 'a> SerializeRow for &'a [T] {
147    impl_serialize_row_for_slice!();
148}
149
150impl<T: SerializeValue> SerializeRow for Vec<T> {
151    impl_serialize_row_for_slice!();
152}
153
154impl<T: SerializeRow + ?Sized> SerializeRow for Box<T> {
155    #[inline]
156    fn serialize(
157        &self,
158        ctx: &RowSerializationContext<'_>,
159        writer: &mut RowWriter,
160    ) -> Result<(), SerializationError> {
161        self.as_ref().serialize(ctx, writer)
162    }
163
164    #[inline]
165    fn is_empty(&self) -> bool {
166        self.as_ref().is_empty()
167    }
168}
169
170macro_rules! impl_serialize_row_for_map {
171    () => {
172        fn serialize(
173            &self,
174            ctx: &RowSerializationContext<'_>,
175            writer: &mut RowWriter,
176        ) -> Result<(), SerializationError> {
177            // Unfortunately, column names aren't guaranteed to be unique.
178            // We need to track not-yet-used columns in order to see
179            // whether some values were not used at the end, and report an error.
180            let mut unused_columns: HashSet<&str> = self.keys().map(|k| k.as_ref()).collect();
181
182            for col in ctx.columns.iter() {
183                match self.get(col.name()) {
184                    None => {
185                        return Err(mk_typck_err::<Self>(
186                            BuiltinTypeCheckErrorKind::ValueMissingForColumn {
187                                name: col.name().to_owned(),
188                            },
189                        ))
190                    }
191                    Some(v) => {
192                        $crate::_macro_internal::ser::row::serialize_column::<Self>(
193                            v, col, writer,
194                        )?;
195                        let _ = unused_columns.remove(col.name());
196                    }
197                }
198            }
199
200            if !unused_columns.is_empty() {
201                // Report the lexicographically first value for deterministic error messages
202                let name = unused_columns.iter().min().unwrap();
203                return Err(mk_typck_err::<Self>(
204                    BuiltinTypeCheckErrorKind::NoColumnWithName {
205                        name: name.to_string(),
206                    },
207                ));
208            }
209
210            Ok(())
211        }
212
213        #[inline]
214        fn is_empty(&self) -> bool {
215            Self::is_empty(self)
216        }
217    };
218}
219
220impl<T: SerializeValue> SerializeRow for BTreeMap<String, T> {
221    impl_serialize_row_for_map!();
222}
223
224impl<T: SerializeValue> SerializeRow for BTreeMap<&str, T> {
225    impl_serialize_row_for_map!();
226}
227
228impl<T: SerializeValue, S: BuildHasher> SerializeRow for HashMap<String, T, S> {
229    impl_serialize_row_for_map!();
230}
231
232impl<T: SerializeValue, S: BuildHasher> SerializeRow for HashMap<&str, T, S> {
233    impl_serialize_row_for_map!();
234}
235
236impl<T: SerializeRow + ?Sized> SerializeRow for &T {
237    fn serialize(
238        &self,
239        ctx: &RowSerializationContext<'_>,
240        writer: &mut RowWriter,
241    ) -> Result<(), SerializationError> {
242        <T as SerializeRow>::serialize(self, ctx, writer)
243    }
244
245    #[inline]
246    fn is_empty(&self) -> bool {
247        <T as SerializeRow>::is_empty(self)
248    }
249}
250
251macro_rules! impl_tuple {
252    (
253        $($typs:ident),*;
254        $($fidents:ident),*;
255        $($tidents:ident),*;
256        $length:expr
257    ) => {
258        impl<$($typs: SerializeValue),*> SerializeRow for ($($typs,)*) {
259            fn serialize(
260                &self,
261                ctx: &RowSerializationContext<'_>,
262                writer: &mut RowWriter,
263            ) -> Result<(), SerializationError> {
264                let ($($tidents,)*) = match ctx.columns() {
265                    [$($tidents),*] => ($($tidents,)*),
266                    _ => return Err(mk_typck_err::<Self>(
267                        BuiltinTypeCheckErrorKind::WrongColumnCount {
268                            rust_cols: $length,
269                            cql_cols: ctx.columns().len(),
270                        },
271                    )),
272                };
273                let ($($fidents,)*) = self;
274                $(
275                    $crate::_macro_internal::ser::row::serialize_column::<Self>($fidents, $tidents, writer)?;
276                )*
277                Ok(())
278            }
279
280            #[inline]
281            fn is_empty(&self) -> bool {
282                $length == 0
283            }
284        }
285    };
286}
287
288macro_rules! impl_tuples {
289    (;;;$length:expr) => {};
290    (
291        $typ:ident$(, $($typs:ident),*)?;
292        $fident:ident$(, $($fidents:ident),*)?;
293        $tident:ident$(, $($tidents:ident),*)?;
294        $length:expr
295    ) => {
296        impl_tuples!(
297            $($($typs),*)?;
298            $($($fidents),*)?;
299            $($($tidents),*)?;
300            $length - 1
301        );
302        impl_tuple!(
303            $typ$(, $($typs),*)?;
304            $fident$(, $($fidents),*)?;
305            $tident$(, $($tidents),*)?;
306            $length
307        );
308    };
309}
310
311impl_tuples!(
312    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
313    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
314    t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
315    16
316);
317
318/// Failed to type check values for a statement, represented by one of the types
319/// built into the driver.
320#[derive(Debug, Error, Clone)]
321#[error("Failed to type check query arguments {rust_name}: {kind}")]
322pub struct BuiltinTypeCheckError {
323    /// Name of the Rust type used to represent the values.
324    pub rust_name: &'static str,
325
326    /// Detailed information about the failure.
327    pub kind: BuiltinTypeCheckErrorKind,
328}
329
330#[doc(hidden)]
331pub fn mk_typck_err<T>(kind: impl Into<BuiltinTypeCheckErrorKind>) -> SerializationError {
332    mk_typck_err_named(std::any::type_name::<T>(), kind)
333}
334
335fn mk_typck_err_named(
336    name: &'static str,
337    kind: impl Into<BuiltinTypeCheckErrorKind>,
338) -> SerializationError {
339    SerializationError::new(BuiltinTypeCheckError {
340        rust_name: name,
341        kind: kind.into(),
342    })
343}
344
345/// Failed to serialize values for a statement, represented by one of the types
346/// built into the driver.
347#[derive(Debug, Error, Clone)]
348#[error("Failed to serialize query arguments {rust_name}: {kind}")]
349pub struct BuiltinSerializationError {
350    /// Name of the Rust type used to represent the values.
351    pub rust_name: &'static str,
352
353    /// Detailed information about the failure.
354    pub kind: BuiltinSerializationErrorKind,
355}
356
357pub(crate) fn mk_ser_err<T>(kind: impl Into<BuiltinSerializationErrorKind>) -> SerializationError {
358    mk_ser_err_named(std::any::type_name::<T>(), kind)
359}
360
361fn mk_ser_err_named(
362    name: &'static str,
363    kind: impl Into<BuiltinSerializationErrorKind>,
364) -> SerializationError {
365    SerializationError::new(BuiltinSerializationError {
366        rust_name: name,
367        kind: kind.into(),
368    })
369}
370
371/// Describes why type checking values for a statement failed.
372#[derive(Debug, Clone)]
373#[non_exhaustive]
374pub enum BuiltinTypeCheckErrorKind {
375    /// The Rust type provides `rust_cols` columns, but the statement operates on `cql_cols`.
376    WrongColumnCount {
377        /// The number of values that the Rust type provides.
378        rust_cols: usize,
379
380        /// The number of columns that the statement operates on.
381        cql_cols: usize,
382    },
383
384    /// The Rust type provides a value for some column, but that column is not
385    /// present in the statement.
386    NoColumnWithName {
387        /// Name of the column that is missing in the statement.
388        name: String,
389    },
390
391    /// A value required by the statement is not provided by the Rust type.
392    ValueMissingForColumn {
393        /// Name of the column for which the Rust type doesn't
394        /// provide a value.
395        name: String,
396    },
397
398    /// A different column name was expected at given position.
399    ColumnNameMismatch {
400        /// Name of the column, as expected by the Rust type.
401        rust_column_name: String,
402
403        /// Name of the column for which the DB requested a value.
404        db_column_name: String,
405    },
406}
407
408impl Display for BuiltinTypeCheckErrorKind {
409    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410        match self {
411            BuiltinTypeCheckErrorKind::WrongColumnCount { rust_cols, cql_cols } => {
412                write!(f, "wrong column count: the statement operates on {cql_cols} columns, but the given rust type provides {rust_cols}")
413            }
414            BuiltinTypeCheckErrorKind::NoColumnWithName { name } => {
415                write!(
416                    f,
417                    "value for column {name} was provided, but there is no bind marker for this column in the query"
418                )
419            }
420            BuiltinTypeCheckErrorKind::ValueMissingForColumn { name } => {
421                write!(
422                    f,
423                    "value for column {name} was not provided, but the query requires it"
424                )
425            }
426            BuiltinTypeCheckErrorKind::ColumnNameMismatch { rust_column_name, db_column_name } => write!(
427                f,
428                "expected column with name {db_column_name} at given position, but the Rust field name is {rust_column_name}"
429            ),
430        }
431    }
432}
433
434/// Describes why serializing values for a statement failed.
435#[derive(Debug, Clone)]
436#[non_exhaustive]
437pub enum BuiltinSerializationErrorKind {
438    /// One of the columns failed to serialize.
439    ColumnSerializationFailed {
440        /// Name of the column that failed to serialize.
441        name: String,
442
443        /// The error that caused the column serialization to fail.
444        err: SerializationError,
445    },
446    /// Too many values to add, max 65,535 values can be sent in a request.
447    TooManyValues,
448}
449
450impl Display for BuiltinSerializationErrorKind {
451    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452        match self {
453            BuiltinSerializationErrorKind::ColumnSerializationFailed { name, err } => {
454                write!(f, "failed to serialize column {name}: {err}")
455            }
456            BuiltinSerializationErrorKind::TooManyValues => {
457                write!(
458                    f,
459                    "Too many values to add, max 65,535 values can be sent in a request"
460                )
461            }
462        }
463    }
464}
465
466/// A buffer containing already serialized values.
467///
468/// It is not aware of the types of contained values,
469/// it is basically a byte buffer in the format expected by the CQL protocol.
470/// Usually there is no need for a user of a driver to use this struct, it is mostly internal.
471/// The exception are APIs like `ClusterState::compute_token` / `ClusterState::get_endpoints`.
472/// Allows adding new values to the buffer and iterating over the content.
473#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
474pub struct SerializedValues {
475    serialized_values: Vec<u8>,
476    element_count: u16,
477}
478
479impl SerializedValues {
480    /// Constructs a new, empty `SerializedValues`.
481    pub const fn new() -> Self {
482        SerializedValues {
483            serialized_values: Vec::new(),
484            element_count: 0,
485        }
486    }
487
488    /// A const empty instance, useful for taking references
489    pub const EMPTY: &'static SerializedValues = &SerializedValues::new();
490
491    /// Constructs `SerializedValues` from given [`SerializeRow`] object.
492    pub fn from_serializable<T: SerializeRow + ?Sized>(
493        ctx: &RowSerializationContext,
494        row: &T,
495    ) -> Result<Self, SerializationError> {
496        Self::from_closure(|writer| row.serialize(ctx, writer)).map(|(sr, _)| sr)
497    }
498
499    /// Constructs `SerializedValues` via given closure.
500    pub fn from_closure<F, R>(f: F) -> Result<(Self, R), SerializationError>
501    where
502        F: FnOnce(&mut RowWriter) -> Result<R, SerializationError>,
503    {
504        let mut data = Vec::new();
505        let mut writer = RowWriter::new(&mut data);
506        let ret = f(&mut writer)?;
507        let element_count = match writer.value_count().try_into() {
508            Ok(n) => n,
509            Err(_) => {
510                return Err(SerializationError(Arc::new(mk_ser_err::<Self>(
511                    BuiltinSerializationErrorKind::TooManyValues,
512                ))));
513            }
514        };
515
516        Ok((
517            SerializedValues {
518                serialized_values: data,
519                element_count,
520            },
521            ret,
522        ))
523    }
524
525    /// Returns `true` if the row contains no elements.
526    #[inline]
527    pub fn is_empty(&self) -> bool {
528        self.element_count() == 0
529    }
530
531    /// Returns an iterator over the values serialized into the object so far.
532    #[inline]
533    pub fn iter(&self) -> impl Iterator<Item = RawValue> {
534        SerializedValuesIterator {
535            serialized_values: &self.serialized_values,
536        }
537    }
538
539    /// Returns the number of values written so far.
540    #[inline]
541    pub fn element_count(&self) -> u16 {
542        self.element_count
543    }
544
545    /// Returns the total serialized size of the values written so far.
546    #[inline]
547    pub fn buffer_size(&self) -> usize {
548        self.serialized_values.len()
549    }
550
551    pub(crate) fn write_to_request(&self, buf: &mut impl BufMut) {
552        buf.put_u16(self.element_count);
553        buf.put(self.serialized_values.as_slice())
554    }
555
556    // Gets the serialized values as raw bytes, without the preceding u16 length.
557    pub(crate) fn get_contents(&self) -> &[u8] {
558        &self.serialized_values
559    }
560
561    /// Serializes value and appends it to the list
562    pub fn add_value<T: SerializeValue>(
563        &mut self,
564        val: &T,
565        typ: &ColumnType,
566    ) -> Result<(), SerializationError> {
567        if self.element_count() == u16::MAX {
568            return Err(SerializationError(Arc::new(mk_ser_err::<Self>(
569                BuiltinSerializationErrorKind::TooManyValues,
570            ))));
571        }
572
573        let len_before_serialize: usize = self.serialized_values.len();
574
575        let writer = CellWriter::new(&mut self.serialized_values);
576        if let Err(e) = val.serialize(typ, writer) {
577            self.serialized_values.resize(len_before_serialize, 0);
578            Err(e)
579        } else {
580            self.element_count += 1;
581            Ok(())
582        }
583    }
584
585    /// Creates value list from the request frame
586    /// This is used only for testing - request deserialization.
587    pub(crate) fn new_from_frame(buf: &mut &[u8]) -> Result<Self, RequestDeserializationError> {
588        let values_num = types::read_short(buf)?;
589        let values_beg = *buf;
590        for _ in 0..values_num {
591            let _serialized = types::read_value(buf)?;
592        }
593
594        let values_len_in_buf = values_beg.len() - buf.len();
595        let values_in_frame = &values_beg[0..values_len_in_buf];
596        Ok(SerializedValues {
597            serialized_values: values_in_frame.to_vec(),
598            element_count: values_num,
599        })
600    }
601}
602
603impl Default for SerializedValues {
604    fn default() -> Self {
605        Self::new()
606    }
607}
608
609/// An iterator over raw values in some [`SerializedValues`].
610#[derive(Clone, Copy)]
611pub struct SerializedValuesIterator<'a> {
612    serialized_values: &'a [u8],
613}
614
615impl<'a> Iterator for SerializedValuesIterator<'a> {
616    type Item = RawValue<'a>;
617
618    fn next(&mut self) -> Option<Self::Item> {
619        if self.serialized_values.is_empty() {
620            return None;
621        }
622
623        Some(types::read_value(&mut self.serialized_values).expect("badly encoded value"))
624    }
625}
626
627mod doctests {
628
629    /// ```compile_fail
630    ///
631    /// #[derive(scylla_macros::SerializeRow)]
632    /// #[scylla(crate = scylla_cql, skip_name_checks)]
633    /// struct TestRow {}
634    /// ```
635    fn _test_struct_deserialization_name_check_skip_requires_enforce_order() {}
636
637    /// ```compile_fail
638    ///
639    /// #[derive(scylla_macros::SerializeRow)]
640    /// #[scylla(crate = scylla_cql, skip_name_checks)]
641    /// struct TestRow {
642    ///     #[scylla(rename = "b")]
643    ///     a: i32,
644    /// }
645    /// ```
646    fn _test_struct_deserialization_skip_name_check_conflicts_with_rename() {}
647
648    /// ```compile_fail
649    ///
650    /// #[derive(scylla_macros::SerializeRow)]
651    /// #[scylla(crate = scylla_cql)]
652    /// struct TestRow {
653    ///     #[scylla(rename = "b")]
654    ///     a: i32,
655    ///     b: String,
656    /// }
657    /// ```
658    fn _test_struct_deserialization_skip_rename_collision_with_field() {}
659
660    /// ```compile_fail
661    ///
662    /// #[derive(scylla_macros::SerializeRow)]
663    /// #[scylla(crate = scylla_cql)]
664    /// struct TestRow {
665    ///     #[scylla(rename = "c")]
666    ///     a: i32,
667    ///     #[scylla(rename = "c")]
668    ///     b: String,
669    /// }
670    /// ```
671    fn _test_struct_deserialization_rename_collision_with_another_rename() {}
672}
673
674#[cfg(test)]
675#[path = "row_tests.rs"]
676pub(crate) mod tests;