1use std::fmt::Display;
7
8use thiserror::Error;
9
10use super::value::DeserializeValue;
11use super::{make_error_replace_rust_name, DeserializationError, FrameSlice, TypeCheckError};
12use crate::frame::response::result::{ColumnSpec, ColumnType};
13use crate::value::{CqlValue, Row};
14
15#[non_exhaustive]
17pub struct RawColumn<'frame, 'metadata> {
18 pub index: usize,
20
21 pub spec: &'metadata ColumnSpec<'metadata>,
23
24 pub slice: Option<FrameSlice<'frame>>,
27}
28
29#[derive(Clone, Debug)]
31pub struct ColumnIterator<'frame, 'metadata> {
32 specs: std::iter::Enumerate<std::slice::Iter<'metadata, ColumnSpec<'metadata>>>,
33 slice: FrameSlice<'frame>,
34}
35
36impl<'frame, 'metadata> ColumnIterator<'frame, 'metadata> {
37 #[inline]
42 pub fn new(specs: &'metadata [ColumnSpec<'metadata>], slice: FrameSlice<'frame>) -> Self {
43 Self {
44 specs: specs.iter().enumerate(),
45 slice,
46 }
47 }
48
49 #[inline]
52 pub fn columns_remaining(&self) -> usize {
53 self.specs.len()
54 }
55}
56
57impl<'frame, 'metadata> Iterator for ColumnIterator<'frame, 'metadata> {
58 type Item = Result<RawColumn<'frame, 'metadata>, DeserializationError>;
59
60 #[inline]
61 fn next(&mut self) -> Option<Self::Item> {
62 let (column_index, spec) = self.specs.next()?;
63 Some(
64 self.slice
65 .read_cql_bytes()
66 .map(|slice| RawColumn {
67 index: column_index,
68 spec,
69 slice,
70 })
71 .map_err(|err| {
72 mk_deser_err::<Self>(
73 BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
74 column_index,
75 column_name: spec.name().to_owned(),
76 err: DeserializationError::new(err),
77 },
78 )
79 }),
80 )
81 }
82
83 #[inline]
84 fn size_hint(&self) -> (usize, Option<usize>) {
85 self.specs.size_hint()
86 }
87}
88
89pub trait DeserializeRow<'frame, 'metadata>
98where
99 Self: Sized,
100{
101 fn type_check(specs: &[ColumnSpec]) -> Result<(), TypeCheckError>;
106
107 fn deserialize(row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError>;
114}
115
116impl<'frame, 'metadata> DeserializeRow<'frame, 'metadata> for ColumnIterator<'frame, 'metadata> {
125 #[inline]
126 fn type_check(_specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
127 Ok(())
128 }
129
130 #[inline]
131 fn deserialize(row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError> {
132 Ok(row)
133 }
134}
135
136make_error_replace_rust_name!(
137 pub(self),
138 _typck_error_replace_rust_name,
139 TypeCheckError,
140 BuiltinTypeCheckError
141);
142
143make_error_replace_rust_name!(
144 pub,
145 deser_error_replace_rust_name,
146 DeserializationError,
147 BuiltinDeserializationError
148);
149
150impl<'frame, 'metadata> DeserializeRow<'frame, 'metadata> for Row {
156 #[inline]
157 fn type_check(_specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
158 Ok(())
160 }
161
162 #[inline]
163 fn deserialize(
164 mut row: ColumnIterator<'frame, 'metadata>,
165 ) -> Result<Self, DeserializationError> {
166 let mut columns = Vec::with_capacity(row.size_hint().0);
167 while let Some(column) = row
168 .next()
169 .transpose()
170 .map_err(deser_error_replace_rust_name::<Self>)?
171 {
172 columns.push(
173 <Option<CqlValue>>::deserialize(column.spec.typ(), column.slice).map_err(
174 |err| {
175 mk_deser_err::<Self>(
176 BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
177 column_index: column.index,
178 column_name: column.spec.name().to_owned(),
179 err,
180 },
181 )
182 },
183 )?,
184 );
185 }
186 Ok(Self { columns })
187 }
188}
189
190macro_rules! impl_tuple {
197 ($($Ti:ident),*; $($idx:literal),*; $($idf:ident),*) => {
198 impl<'frame, 'metadata, $($Ti),*> DeserializeRow<'frame, 'metadata> for ($($Ti,)*)
199 where
200 $($Ti: DeserializeValue<'frame, 'metadata>),*
201 {
202 fn type_check(specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
203 const TUPLE_LEN: usize = (&[$($idx),*] as &[i32]).len();
204
205 let column_types_iter = || specs.iter().map(|spec| spec.typ().clone().into_owned());
206 if let [$($idf),*] = &specs {
207 $(
208 <$Ti as DeserializeValue<'frame, 'metadata>>::type_check($idf.typ())
209 .map_err(|err| mk_typck_err::<Self>(column_types_iter(), BuiltinTypeCheckErrorKind::ColumnTypeCheckFailed {
210 column_index: $idx,
211 column_name: specs[$idx].name().to_owned(),
212 err
213 }))?;
214 )*
215 Ok(())
216 } else {
217 Err(mk_typck_err::<Self>(column_types_iter(), BuiltinTypeCheckErrorKind::WrongColumnCount {
218 rust_cols: TUPLE_LEN, cql_cols: specs.len()
219 }))
220 }
221 }
222
223 fn deserialize(mut row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError> {
224 const TUPLE_LEN: usize = (&[$($idx),*] as &[i32]).len();
225
226 let ret = (
227 $({
228 let column = row.next().unwrap_or_else(|| unreachable!(
229 "Typecheck should have prevented this scenario! Column count mismatch: rust type {}, cql row {}",
230 TUPLE_LEN,
231 $idx
232 )).map_err(deser_error_replace_rust_name::<Self>)?;
233
234 <$Ti as DeserializeValue<'frame, 'metadata>>::deserialize(column.spec.typ(), column.slice)
235 .map_err(|err| mk_deser_err::<Self>(BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
236 column_index: column.index,
237 column_name: column.spec.name().to_owned(),
238 err,
239 }))?
240 },)*
241 );
242 assert!(
243 row.next().is_none(),
244 "Typecheck should have prevented this scenario! Column count mismatch: rust type {}, cql row is bigger",
245 TUPLE_LEN,
246 );
247 Ok(ret)
248 }
249 }
250 }
251}
252
253use super::value::impl_tuple_multiple;
254
255impl_tuple_multiple!(
257 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
258 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
259 t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15
260);
261
262#[derive(Debug, Error, Clone)]
267#[error("Failed to type check the Rust type {rust_name} against CQL column types {cql_types:?} : {kind}")]
268pub struct BuiltinTypeCheckError {
269 pub rust_name: &'static str,
271
272 pub cql_types: Vec<ColumnType<'static>>,
274
275 pub kind: BuiltinTypeCheckErrorKind,
277}
278
279#[doc(hidden)]
281pub fn mk_typck_err<T>(
282 cql_types: impl IntoIterator<Item = ColumnType<'static>>,
283 kind: impl Into<BuiltinTypeCheckErrorKind>,
284) -> TypeCheckError {
285 mk_typck_err_named(std::any::type_name::<T>(), cql_types, kind)
286}
287
288fn mk_typck_err_named(
289 name: &'static str,
290 cql_types: impl IntoIterator<Item = ColumnType<'static>>,
291 kind: impl Into<BuiltinTypeCheckErrorKind>,
292) -> TypeCheckError {
293 TypeCheckError::new(BuiltinTypeCheckError {
294 rust_name: name,
295 cql_types: Vec::from_iter(cql_types),
296 kind: kind.into(),
297 })
298}
299
300#[derive(Debug, Clone)]
302#[non_exhaustive]
303pub enum BuiltinTypeCheckErrorKind {
304 WrongColumnCount {
306 rust_cols: usize,
308
309 cql_cols: usize,
311 },
312
313 ColumnWithUnknownName {
316 column_index: usize,
318
319 column_name: String,
321 },
322
323 ValuesMissingForColumns {
325 column_names: Vec<&'static str>,
328 },
329
330 ColumnNameMismatch {
332 field_index: usize,
334
335 column_index: usize,
337
338 rust_column_name: &'static str,
340
341 db_column_name: String,
343 },
344
345 ColumnTypeCheckFailed {
347 column_index: usize,
349
350 column_name: String,
352
353 err: TypeCheckError,
355 },
356
357 DuplicatedColumn {
359 column_index: usize,
361
362 column_name: &'static str,
364 },
365}
366
367impl Display for BuiltinTypeCheckErrorKind {
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 match self {
370 BuiltinTypeCheckErrorKind::WrongColumnCount {
371 rust_cols,
372 cql_cols,
373 } => {
374 write!(f, "wrong column count: the statement operates on {cql_cols} columns, but the given rust types contains {rust_cols}")
375 }
376 BuiltinTypeCheckErrorKind::ColumnWithUnknownName { column_name, column_index } => {
377 write!(
378 f,
379 "the CQL row contains a column {column_name} at column index {column_index}, but the corresponding field is not found in the Rust type",
380 )
381 }
382 BuiltinTypeCheckErrorKind::ValuesMissingForColumns { column_names } => {
383 write!(
384 f,
385 "values for columns {column_names:?} are missing from the DB data but are required by the Rust type"
386 )
387 },
388 BuiltinTypeCheckErrorKind::ColumnNameMismatch {
389 field_index,
390 column_index,rust_column_name,
391 db_column_name
392 } => write!(
393 f,
394 "expected column with name {db_column_name} at column index {column_index}, but the Rust field name at corresponding field index {field_index} is {rust_column_name}",
395 ),
396 BuiltinTypeCheckErrorKind::ColumnTypeCheckFailed {
397 column_index,
398 column_name,
399 err,
400 } => write!(
401 f,
402 "mismatched types in column {column_name} at index {column_index}: {err}"
403 ),
404 BuiltinTypeCheckErrorKind::DuplicatedColumn { column_name, column_index } => write!(
405 f,
406 "column {column_name} occurs more than once in DB metadata; second occurrence is at column index {column_index}",
407 ),
408 }
409 }
410}
411
412#[derive(Debug, Error, Clone)]
415#[error("Failed to deserialize query result row {rust_name}: {kind}")]
416pub struct BuiltinDeserializationError {
417 pub rust_name: &'static str,
419
420 pub kind: BuiltinDeserializationErrorKind,
422}
423
424#[doc(hidden)]
426pub fn mk_deser_err<T>(kind: impl Into<BuiltinDeserializationErrorKind>) -> DeserializationError {
427 mk_deser_err_named(std::any::type_name::<T>(), kind)
428}
429
430fn mk_deser_err_named(
431 name: &'static str,
432 kind: impl Into<BuiltinDeserializationErrorKind>,
433) -> DeserializationError {
434 DeserializationError::new(BuiltinDeserializationError {
435 rust_name: name,
436 kind: kind.into(),
437 })
438}
439
440#[derive(Debug, Clone)]
442#[non_exhaustive]
443pub enum BuiltinDeserializationErrorKind {
444 ColumnDeserializationFailed {
446 column_index: usize,
448
449 column_name: String,
451
452 err: DeserializationError,
454 },
455
456 RawColumnDeserializationFailed {
459 column_index: usize,
461
462 column_name: String,
464
465 err: DeserializationError,
467 },
468}
469
470impl Display for BuiltinDeserializationErrorKind {
471 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
472 match self {
473 BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
474 column_index,
475 column_name,
476 err,
477 } => {
478 write!(
479 f,
480 "failed to deserialize column {column_name} at index {column_index}: {err}"
481 )
482 }
483 BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
484 column_index,
485 column_name,
486 err,
487 } => {
488 write!(
489 f,
490 "failed to deserialize raw column {column_name} at index {column_index} (most probably due to invalid column structure inside a row): {err}"
491 )
492 }
493 }
494 }
495}
496
497#[cfg(test)]
498#[path = "row_tests.rs"]
499pub(crate) mod tests;
500
501fn _test_struct_deserialization_name_check_skip_requires_enforce_order() {}
508
509fn _test_struct_deserialization_skip_name_check_conflicts_with_rename() {}
519
520fn _test_struct_deserialization_skip_rename_collision_with_field() {}
531
532fn _test_struct_deserialization_rename_collision_with_another_rename() {}