1use std::fmt::Display;
4
5use thiserror::Error;
6
7use super::value::DeserializeValue;
8use super::{make_error_replace_rust_name, DeserializationError, FrameSlice, TypeCheckError};
9use crate::frame::response::result::{ColumnSpec, ColumnType};
10use crate::value::{CqlValue, Row};
11
12#[non_exhaustive]
14pub struct RawColumn<'frame, 'metadata> {
15 pub index: usize,
16 pub spec: &'metadata ColumnSpec<'metadata>,
17 pub slice: Option<FrameSlice<'frame>>,
18}
19
20#[derive(Clone, Debug)]
22pub struct ColumnIterator<'frame, 'metadata> {
23 specs: std::iter::Enumerate<std::slice::Iter<'metadata, ColumnSpec<'metadata>>>,
24 slice: FrameSlice<'frame>,
25}
26
27impl<'frame, 'metadata> ColumnIterator<'frame, 'metadata> {
28 #[inline]
33 pub fn new(specs: &'metadata [ColumnSpec<'metadata>], slice: FrameSlice<'frame>) -> Self {
34 Self {
35 specs: specs.iter().enumerate(),
36 slice,
37 }
38 }
39
40 #[inline]
43 pub fn columns_remaining(&self) -> usize {
44 self.specs.len()
45 }
46}
47
48impl<'frame, 'metadata> Iterator for ColumnIterator<'frame, 'metadata> {
49 type Item = Result<RawColumn<'frame, 'metadata>, DeserializationError>;
50
51 #[inline]
52 fn next(&mut self) -> Option<Self::Item> {
53 let (column_index, spec) = self.specs.next()?;
54 Some(
55 self.slice
56 .read_cql_bytes()
57 .map(|slice| RawColumn {
58 index: column_index,
59 spec,
60 slice,
61 })
62 .map_err(|err| {
63 mk_deser_err::<Self>(
64 BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
65 column_index,
66 column_name: spec.name().to_owned(),
67 err: DeserializationError::new(err),
68 },
69 )
70 }),
71 )
72 }
73
74 #[inline]
75 fn size_hint(&self) -> (usize, Option<usize>) {
76 self.specs.size_hint()
77 }
78}
79
80pub trait DeserializeRow<'frame, 'metadata>
89where
90 Self: Sized,
91{
92 fn type_check(specs: &[ColumnSpec]) -> Result<(), TypeCheckError>;
97
98 fn deserialize(row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError>;
105}
106
107impl<'frame, 'metadata> DeserializeRow<'frame, 'metadata> for ColumnIterator<'frame, 'metadata> {
116 #[inline]
117 fn type_check(_specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
118 Ok(())
119 }
120
121 #[inline]
122 fn deserialize(row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError> {
123 Ok(row)
124 }
125}
126
127make_error_replace_rust_name!(
128 pub(self),
129 _typck_error_replace_rust_name,
130 TypeCheckError,
131 BuiltinTypeCheckError
132);
133
134make_error_replace_rust_name!(
135 pub,
136 deser_error_replace_rust_name,
137 DeserializationError,
138 BuiltinDeserializationError
139);
140
141impl<'frame, 'metadata> DeserializeRow<'frame, 'metadata> for Row {
147 #[inline]
148 fn type_check(_specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
149 Ok(())
151 }
152
153 #[inline]
154 fn deserialize(
155 mut row: ColumnIterator<'frame, 'metadata>,
156 ) -> Result<Self, DeserializationError> {
157 let mut columns = Vec::with_capacity(row.size_hint().0);
158 while let Some(column) = row
159 .next()
160 .transpose()
161 .map_err(deser_error_replace_rust_name::<Self>)?
162 {
163 columns.push(
164 <Option<CqlValue>>::deserialize(column.spec.typ(), column.slice).map_err(
165 |err| {
166 mk_deser_err::<Self>(
167 BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
168 column_index: column.index,
169 column_name: column.spec.name().to_owned(),
170 err,
171 },
172 )
173 },
174 )?,
175 );
176 }
177 Ok(Self { columns })
178 }
179}
180
181macro_rules! impl_tuple {
188 ($($Ti:ident),*; $($idx:literal),*; $($idf:ident),*) => {
189 impl<'frame, 'metadata, $($Ti),*> DeserializeRow<'frame, 'metadata> for ($($Ti,)*)
190 where
191 $($Ti: DeserializeValue<'frame, 'metadata>),*
192 {
193 fn type_check(specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
194 const TUPLE_LEN: usize = (&[$($idx),*] as &[i32]).len();
195
196 let column_types_iter = || specs.iter().map(|spec| spec.typ().clone().into_owned());
197 if let [$($idf),*] = &specs {
198 $(
199 <$Ti as DeserializeValue<'frame, 'metadata>>::type_check($idf.typ())
200 .map_err(|err| mk_typck_err::<Self>(column_types_iter(), BuiltinTypeCheckErrorKind::ColumnTypeCheckFailed {
201 column_index: $idx,
202 column_name: specs[$idx].name().to_owned(),
203 err
204 }))?;
205 )*
206 Ok(())
207 } else {
208 Err(mk_typck_err::<Self>(column_types_iter(), BuiltinTypeCheckErrorKind::WrongColumnCount {
209 rust_cols: TUPLE_LEN, cql_cols: specs.len()
210 }))
211 }
212 }
213
214 fn deserialize(mut row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError> {
215 const TUPLE_LEN: usize = (&[$($idx),*] as &[i32]).len();
216
217 let ret = (
218 $({
219 let column = row.next().unwrap_or_else(|| unreachable!(
220 "Typecheck should have prevented this scenario! Column count mismatch: rust type {}, cql row {}",
221 TUPLE_LEN,
222 $idx
223 )).map_err(deser_error_replace_rust_name::<Self>)?;
224
225 <$Ti as DeserializeValue<'frame, 'metadata>>::deserialize(column.spec.typ(), column.slice)
226 .map_err(|err| mk_deser_err::<Self>(BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
227 column_index: column.index,
228 column_name: column.spec.name().to_owned(),
229 err,
230 }))?
231 },)*
232 );
233 assert!(
234 row.next().is_none(),
235 "Typecheck should have prevented this scenario! Column count mismatch: rust type {}, cql row is bigger",
236 TUPLE_LEN,
237 );
238 Ok(ret)
239 }
240 }
241 }
242}
243
244use super::value::impl_tuple_multiple;
245
246impl_tuple_multiple!(
248 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
249 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
250 t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15
251);
252
253#[derive(Debug, Error, Clone)]
258#[error("Failed to type check the Rust type {rust_name} against CQL column types {cql_types:?} : {kind}")]
259pub struct BuiltinTypeCheckError {
260 pub rust_name: &'static str,
262
263 pub cql_types: Vec<ColumnType<'static>>,
265
266 pub kind: BuiltinTypeCheckErrorKind,
268}
269
270#[doc(hidden)]
272pub fn mk_typck_err<T>(
273 cql_types: impl IntoIterator<Item = ColumnType<'static>>,
274 kind: impl Into<BuiltinTypeCheckErrorKind>,
275) -> TypeCheckError {
276 mk_typck_err_named(std::any::type_name::<T>(), cql_types, kind)
277}
278
279fn mk_typck_err_named(
280 name: &'static str,
281 cql_types: impl IntoIterator<Item = ColumnType<'static>>,
282 kind: impl Into<BuiltinTypeCheckErrorKind>,
283) -> TypeCheckError {
284 TypeCheckError::new(BuiltinTypeCheckError {
285 rust_name: name,
286 cql_types: Vec::from_iter(cql_types),
287 kind: kind.into(),
288 })
289}
290
291#[derive(Debug, Clone)]
293#[non_exhaustive]
294pub enum BuiltinTypeCheckErrorKind {
295 WrongColumnCount {
297 rust_cols: usize,
299
300 cql_cols: usize,
302 },
303
304 ColumnWithUnknownName {
307 column_index: usize,
309
310 column_name: String,
312 },
313
314 ValuesMissingForColumns {
316 column_names: Vec<&'static str>,
319 },
320
321 ColumnNameMismatch {
323 field_index: usize,
325
326 column_index: usize,
328
329 rust_column_name: &'static str,
331
332 db_column_name: String,
334 },
335
336 ColumnTypeCheckFailed {
338 column_index: usize,
340
341 column_name: String,
343
344 err: TypeCheckError,
346 },
347
348 DuplicatedColumn {
350 column_index: usize,
352
353 column_name: &'static str,
355 },
356}
357
358impl Display for BuiltinTypeCheckErrorKind {
359 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360 match self {
361 BuiltinTypeCheckErrorKind::WrongColumnCount {
362 rust_cols,
363 cql_cols,
364 } => {
365 write!(f, "wrong column count: the statement operates on {cql_cols} columns, but the given rust types contains {rust_cols}")
366 }
367 BuiltinTypeCheckErrorKind::ColumnWithUnknownName { column_name, column_index } => {
368 write!(
369 f,
370 "the CQL row contains a column {} at column index {}, but the corresponding field is not found in the Rust type",
371 column_name,
372 column_index,
373 )
374 }
375 BuiltinTypeCheckErrorKind::ValuesMissingForColumns { column_names } => {
376 write!(
377 f,
378 "values for columns {:?} are missing from the DB data but are required by the Rust type",
379 column_names
380 )
381 },
382 BuiltinTypeCheckErrorKind::ColumnNameMismatch {
383 field_index,
384 column_index,rust_column_name,
385 db_column_name
386 } => write!(
387 f,
388 "expected column with name {} at column index {}, but the Rust field name at corresponding field index {} is {}",
389 db_column_name,
390 column_index,
391 field_index,
392 rust_column_name,
393 ),
394 BuiltinTypeCheckErrorKind::ColumnTypeCheckFailed {
395 column_index,
396 column_name,
397 err,
398 } => write!(
399 f,
400 "mismatched types in column {column_name} at index {column_index}: {err}"
401 ),
402 BuiltinTypeCheckErrorKind::DuplicatedColumn { column_name, column_index } => write!(
403 f,
404 "column {} occurs more than once in DB metadata; second occurrence is at column index {}",
405 column_name,
406 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() {}