use std::collections::{BTreeMap, HashSet};
use std::fmt::Display;
use std::hash::BuildHasher;
use std::{collections::HashMap, sync::Arc};
use bytes::BufMut;
use thiserror::Error;
use crate::frame::request::RequestDeserializationError;
use crate::frame::response::result::ColumnType;
use crate::frame::response::result::PreparedMetadata;
use crate::frame::types;
use crate::frame::{response::result::ColumnSpec, types::RawValue};
use super::value::SerializeValue;
use super::{CellWriter, RowWriter, SerializationError};
pub struct RowSerializationContext<'a> {
pub(crate) columns: &'a [ColumnSpec<'a>],
}
impl<'a> RowSerializationContext<'a> {
#[inline]
pub fn from_prepared(prepared: &'a PreparedMetadata) -> Self {
Self {
columns: prepared.col_specs.as_slice(),
}
}
#[inline]
pub fn from_specs(specs: &'a [ColumnSpec<'a>]) -> Self {
Self { columns: specs }
}
#[inline]
pub const fn empty() -> Self {
Self { columns: &[] }
}
#[inline]
pub fn columns(&self) -> &'a [ColumnSpec] {
self.columns
}
}
pub trait SerializeRow {
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError>;
fn is_empty(&self) -> bool;
}
macro_rules! impl_serialize_row_for_unit {
() => {
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
_writer: &mut RowWriter,
) -> Result<(), SerializationError> {
if !ctx.columns().is_empty() {
return Err(mk_typck_err::<Self>(
BuiltinTypeCheckErrorKind::WrongColumnCount {
rust_cols: 0,
cql_cols: ctx.columns().len(),
},
));
}
Ok(())
}
#[inline]
fn is_empty(&self) -> bool {
true
}
};
}
impl SerializeRow for () {
impl_serialize_row_for_unit!();
}
impl SerializeRow for [u8; 0] {
impl_serialize_row_for_unit!();
}
macro_rules! impl_serialize_row_for_slice {
() => {
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError> {
if ctx.columns().len() != self.len() {
return Err(mk_typck_err::<Self>(
BuiltinTypeCheckErrorKind::WrongColumnCount {
rust_cols: self.len(),
cql_cols: ctx.columns().len(),
},
));
}
for (col, val) in ctx.columns().iter().zip(self.iter()) {
$crate::_macro_internal::ser::row::serialize_column::<Self>(val, col, writer)?;
}
Ok(())
}
#[inline]
fn is_empty(&self) -> bool {
<[T]>::is_empty(self.as_ref())
}
};
}
impl<'a, T: SerializeValue + 'a> SerializeRow for &'a [T] {
impl_serialize_row_for_slice!();
}
impl<T: SerializeValue> SerializeRow for Vec<T> {
impl_serialize_row_for_slice!();
}
impl<T: SerializeRow + ?Sized> SerializeRow for Box<T> {
#[inline]
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError> {
self.as_ref().serialize(ctx, writer)
}
#[inline]
fn is_empty(&self) -> bool {
self.as_ref().is_empty()
}
}
macro_rules! impl_serialize_row_for_map {
() => {
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError> {
let mut unused_columns: HashSet<&str> = self.keys().map(|k| k.as_ref()).collect();
for col in ctx.columns.iter() {
match self.get(col.name()) {
None => {
return Err(mk_typck_err::<Self>(
BuiltinTypeCheckErrorKind::ValueMissingForColumn {
name: col.name().to_owned(),
},
))
}
Some(v) => {
$crate::_macro_internal::ser::row::serialize_column::<Self>(
v, col, writer,
)?;
let _ = unused_columns.remove(col.name());
}
}
}
if !unused_columns.is_empty() {
let name = unused_columns.iter().min().unwrap();
return Err(mk_typck_err::<Self>(
BuiltinTypeCheckErrorKind::NoColumnWithName {
name: name.to_string(),
},
));
}
Ok(())
}
#[inline]
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
};
}
impl<T: SerializeValue> SerializeRow for BTreeMap<String, T> {
impl_serialize_row_for_map!();
}
impl<T: SerializeValue> SerializeRow for BTreeMap<&str, T> {
impl_serialize_row_for_map!();
}
impl<T: SerializeValue, S: BuildHasher> SerializeRow for HashMap<String, T, S> {
impl_serialize_row_for_map!();
}
impl<T: SerializeValue, S: BuildHasher> SerializeRow for HashMap<&str, T, S> {
impl_serialize_row_for_map!();
}
impl<T: SerializeRow + ?Sized> SerializeRow for &T {
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError> {
<T as SerializeRow>::serialize(self, ctx, writer)
}
#[inline]
fn is_empty(&self) -> bool {
<T as SerializeRow>::is_empty(self)
}
}
macro_rules! impl_tuple {
(
$($typs:ident),*;
$($fidents:ident),*;
$($tidents:ident),*;
$length:expr
) => {
impl<$($typs: SerializeValue),*> SerializeRow for ($($typs,)*) {
fn serialize(
&self,
ctx: &RowSerializationContext<'_>,
writer: &mut RowWriter,
) -> Result<(), SerializationError> {
let ($($tidents,)*) = match ctx.columns() {
[$($tidents),*] => ($($tidents,)*),
_ => return Err(mk_typck_err::<Self>(
BuiltinTypeCheckErrorKind::WrongColumnCount {
rust_cols: $length,
cql_cols: ctx.columns().len(),
},
)),
};
let ($($fidents,)*) = self;
$(
$crate::_macro_internal::ser::row::serialize_column::<Self>($fidents, $tidents, writer)?;
)*
Ok(())
}
#[inline]
fn is_empty(&self) -> bool {
$length == 0
}
}
};
}
macro_rules! impl_tuples {
(;;;$length:expr) => {};
(
$typ:ident$(, $($typs:ident),*)?;
$fident:ident$(, $($fidents:ident),*)?;
$tident:ident$(, $($tidents:ident),*)?;
$length:expr
) => {
impl_tuples!(
$($($typs),*)?;
$($($fidents),*)?;
$($($tidents),*)?;
$length - 1
);
impl_tuple!(
$typ$(, $($typs),*)?;
$fident$(, $($fidents),*)?;
$tident$(, $($tidents),*)?;
$length
);
};
}
impl_tuples!(
T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
16
);
#[derive(Debug, Error, Clone)]
#[error("Failed to type check query arguments {rust_name}: {kind}")]
pub struct BuiltinTypeCheckError {
pub rust_name: &'static str,
pub kind: BuiltinTypeCheckErrorKind,
}
#[doc(hidden)]
pub fn mk_typck_err<T>(kind: impl Into<BuiltinTypeCheckErrorKind>) -> SerializationError {
mk_typck_err_named(std::any::type_name::<T>(), kind)
}
fn mk_typck_err_named(
name: &'static str,
kind: impl Into<BuiltinTypeCheckErrorKind>,
) -> SerializationError {
SerializationError::new(BuiltinTypeCheckError {
rust_name: name,
kind: kind.into(),
})
}
#[derive(Debug, Error, Clone)]
#[error("Failed to serialize query arguments {rust_name}: {kind}")]
pub struct BuiltinSerializationError {
pub rust_name: &'static str,
pub kind: BuiltinSerializationErrorKind,
}
pub(crate) fn mk_ser_err<T>(kind: impl Into<BuiltinSerializationErrorKind>) -> SerializationError {
mk_ser_err_named(std::any::type_name::<T>(), kind)
}
fn mk_ser_err_named(
name: &'static str,
kind: impl Into<BuiltinSerializationErrorKind>,
) -> SerializationError {
SerializationError::new(BuiltinSerializationError {
rust_name: name,
kind: kind.into(),
})
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum BuiltinTypeCheckErrorKind {
WrongColumnCount {
rust_cols: usize,
cql_cols: usize,
},
NoColumnWithName {
name: String,
},
ValueMissingForColumn {
name: String,
},
ColumnNameMismatch {
rust_column_name: String,
db_column_name: String,
},
}
impl Display for BuiltinTypeCheckErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BuiltinTypeCheckErrorKind::WrongColumnCount { rust_cols, cql_cols } => {
write!(f, "wrong column count: the statement operates on {cql_cols} columns, but the given rust type provides {rust_cols}")
}
BuiltinTypeCheckErrorKind::NoColumnWithName { name } => {
write!(
f,
"value for column {name} was provided, but there is no bind marker for this column in the query"
)
}
BuiltinTypeCheckErrorKind::ValueMissingForColumn { name } => {
write!(
f,
"value for column {name} was not provided, but the query requires it"
)
}
BuiltinTypeCheckErrorKind::ColumnNameMismatch { rust_column_name, db_column_name } => write!(
f,
"expected column with name {db_column_name} at given position, but the Rust field name is {rust_column_name}"
),
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum BuiltinSerializationErrorKind {
ColumnSerializationFailed {
name: String,
err: SerializationError,
},
TooManyValues,
}
impl Display for BuiltinSerializationErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BuiltinSerializationErrorKind::ColumnSerializationFailed { name, err } => {
write!(f, "failed to serialize column {name}: {err}")
}
BuiltinSerializationErrorKind::TooManyValues => {
write!(
f,
"Too many values to add, max 65,535 values can be sent in a request"
)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SerializedValues {
serialized_values: Vec<u8>,
element_count: u16,
}
impl SerializedValues {
pub const fn new() -> Self {
SerializedValues {
serialized_values: Vec::new(),
element_count: 0,
}
}
pub const EMPTY: &'static SerializedValues = &SerializedValues::new();
pub fn from_serializable<T: SerializeRow + ?Sized>(
ctx: &RowSerializationContext,
row: &T,
) -> Result<Self, SerializationError> {
Self::from_closure(|writer| row.serialize(ctx, writer)).map(|(sr, _)| sr)
}
pub fn from_closure<F, R>(f: F) -> Result<(Self, R), SerializationError>
where
F: FnOnce(&mut RowWriter) -> Result<R, SerializationError>,
{
let mut data = Vec::new();
let mut writer = RowWriter::new(&mut data);
let ret = f(&mut writer)?;
let element_count = match writer.value_count().try_into() {
Ok(n) => n,
Err(_) => {
return Err(SerializationError(Arc::new(mk_ser_err::<Self>(
BuiltinSerializationErrorKind::TooManyValues,
))));
}
};
Ok((
SerializedValues {
serialized_values: data,
element_count,
},
ret,
))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.element_count() == 0
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = RawValue> {
SerializedValuesIterator {
serialized_values: &self.serialized_values,
}
}
#[inline]
pub fn element_count(&self) -> u16 {
self.element_count
}
#[inline]
pub fn buffer_size(&self) -> usize {
self.serialized_values.len()
}
pub(crate) fn write_to_request(&self, buf: &mut impl BufMut) {
buf.put_u16(self.element_count);
buf.put(self.serialized_values.as_slice())
}
pub(crate) fn get_contents(&self) -> &[u8] {
&self.serialized_values
}
pub fn add_value<T: SerializeValue>(
&mut self,
val: &T,
typ: &ColumnType,
) -> Result<(), SerializationError> {
if self.element_count() == u16::MAX {
return Err(SerializationError(Arc::new(mk_ser_err::<Self>(
BuiltinSerializationErrorKind::TooManyValues,
))));
}
let len_before_serialize: usize = self.serialized_values.len();
let writer = CellWriter::new(&mut self.serialized_values);
if let Err(e) = val.serialize(typ, writer) {
self.serialized_values.resize(len_before_serialize, 0);
Err(e)
} else {
self.element_count += 1;
Ok(())
}
}
pub(crate) fn new_from_frame(buf: &mut &[u8]) -> Result<Self, RequestDeserializationError> {
let values_num = types::read_short(buf)?;
let values_beg = *buf;
for _ in 0..values_num {
let _serialized = types::read_value(buf)?;
}
let values_len_in_buf = values_beg.len() - buf.len();
let values_in_frame = &values_beg[0..values_len_in_buf];
Ok(SerializedValues {
serialized_values: values_in_frame.to_vec(),
element_count: values_num,
})
}
}
impl Default for SerializedValues {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Copy)]
pub struct SerializedValuesIterator<'a> {
serialized_values: &'a [u8],
}
impl<'a> Iterator for SerializedValuesIterator<'a> {
type Item = RawValue<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.serialized_values.is_empty() {
return None;
}
Some(types::read_value(&mut self.serialized_values).expect("badly encoded value"))
}
}
mod doctests {
fn _test_struct_deserialization_name_check_skip_requires_enforce_order() {}
fn _test_struct_deserialization_skip_name_check_conflicts_with_rename() {}
fn _test_struct_deserialization_skip_rename_collision_with_field() {}
fn _test_struct_deserialization_rename_collision_with_another_rename() {}
}
#[cfg(test)]
#[path = "row_tests.rs"]
pub(crate) mod tests;