1use std::fmt::Display;
7
8use thiserror::Error;
9
10use super::value::DeserializeValue;
11use super::{DeserializationError, FrameSlice, TypeCheckError, make_error_replace_rust_name};
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 index: std::ops::RangeFrom<usize>,
33 specs: std::slice::Iter<'metadata, ColumnSpec<'metadata>>,
34 slice: FrameSlice<'frame>,
35}
36
37impl<'frame, 'metadata> ColumnIterator<'frame, 'metadata> {
38 #[inline]
43 pub fn new(specs: &'metadata [ColumnSpec<'metadata>], slice: FrameSlice<'frame>) -> Self {
44 Self {
45 index: 0usize..,
46 specs: specs.iter(),
47 slice,
48 }
49 }
50
51 #[inline]
54 pub fn columns_remaining(&self) -> usize {
55 self.specs.len()
56 }
57
58 #[inline]
60 pub fn type_check<RowT: DeserializeRow<'frame, 'metadata>>(
61 &self,
62 ) -> Result<(), TypeCheckError> {
63 <RowT as DeserializeRow<'frame, 'metadata>>::type_check(self.specs.as_slice())
64 }
65}
66
67impl<'frame, 'metadata> Iterator for ColumnIterator<'frame, 'metadata> {
68 type Item = Result<RawColumn<'frame, 'metadata>, DeserializationError>;
69
70 #[inline]
71 fn next(&mut self) -> Option<Self::Item> {
72 let spec = self.specs.next()?;
73 let column_index = self
74 .index
75 .next()
76 .expect("RangeFrom<usize> iterator exhausted: this indicates usize overflow (more than usize::MAX columns), which should be impossible in practice");
77 Some(
78 self.slice
79 .read_cql_bytes()
80 .map(|slice| RawColumn {
81 index: column_index,
82 spec,
83 slice,
84 })
85 .map_err(|err| {
86 mk_deser_err::<Self>(
87 BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
88 column_index,
89 column_name: spec.name().to_owned(),
90 err: DeserializationError::new(err),
91 },
92 )
93 }),
94 )
95 }
96
97 #[inline]
98 fn size_hint(&self) -> (usize, Option<usize>) {
99 self.specs.size_hint()
100 }
101}
102
103pub trait DeserializeRow<'frame, 'metadata>
112where
113 Self: Sized,
114{
115 fn type_check(specs: &[ColumnSpec]) -> Result<(), TypeCheckError>;
120
121 fn deserialize(row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError>;
128}
129
130impl<'frame, 'metadata> DeserializeRow<'frame, 'metadata> for ColumnIterator<'frame, 'metadata> {
139 #[inline]
140 fn type_check(_specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
141 Ok(())
142 }
143
144 #[inline]
145 fn deserialize(row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError> {
146 Ok(row)
147 }
148}
149
150make_error_replace_rust_name!(
151 pub(self),
152 _typck_error_replace_rust_name,
153 TypeCheckError,
154 BuiltinTypeCheckError
155);
156
157make_error_replace_rust_name!(
158 pub,
159 deser_error_replace_rust_name,
160 DeserializationError,
161 BuiltinDeserializationError
162);
163
164impl<'frame, 'metadata> DeserializeRow<'frame, 'metadata> for Row {
170 #[inline]
171 fn type_check(_specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
172 Ok(())
174 }
175
176 #[inline]
177 fn deserialize(
178 mut row: ColumnIterator<'frame, 'metadata>,
179 ) -> Result<Self, DeserializationError> {
180 let mut columns = Vec::with_capacity(row.size_hint().0);
181 while let Some(column) = row
182 .next()
183 .transpose()
184 .map_err(deser_error_replace_rust_name::<Self>)?
185 {
186 columns.push(
187 <Option<CqlValue>>::deserialize(column.spec.typ(), column.slice).map_err(
188 |err| {
189 mk_deser_err::<Self>(
190 BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
191 column_index: column.index,
192 column_name: column.spec.name().to_owned(),
193 err,
194 },
195 )
196 },
197 )?,
198 );
199 }
200 Ok(Self { columns })
201 }
202}
203
204macro_rules! impl_tuple {
211 ($($Ti:ident),*; $($idx:literal),*; $($idf:ident),*) => {
212 impl<'frame, 'metadata, $($Ti),*> DeserializeRow<'frame, 'metadata> for ($($Ti,)*)
213 where
214 $($Ti: DeserializeValue<'frame, 'metadata>),*
215 {
216 fn type_check(specs: &[ColumnSpec]) -> Result<(), TypeCheckError> {
217 const TUPLE_LEN: usize = (&[$($idx),*] as &[i32]).len();
218
219 let column_types_iter = || specs.iter().map(|spec| spec.typ().clone().into_owned());
220 if let [$($idf),*] = &specs {
221 $(
222 <$Ti as DeserializeValue<'frame, 'metadata>>::type_check($idf.typ())
223 .map_err(|err| mk_typck_err::<Self>(column_types_iter(), BuiltinTypeCheckErrorKind::ColumnTypeCheckFailed {
224 column_index: $idx,
225 column_name: specs[$idx].name().to_owned(),
226 err
227 }))?;
228 )*
229 Ok(())
230 } else {
231 Err(mk_typck_err::<Self>(column_types_iter(), BuiltinTypeCheckErrorKind::WrongColumnCount {
232 rust_cols: TUPLE_LEN, cql_cols: specs.len()
233 }))
234 }
235 }
236
237 fn deserialize(mut row: ColumnIterator<'frame, 'metadata>) -> Result<Self, DeserializationError> {
238 const TUPLE_LEN: usize = (&[$($idx),*] as &[i32]).len();
239
240 let ret = (
241 $({
242 let column = row.next().unwrap_or_else(|| unreachable!(
243 "Typecheck should have prevented this scenario! Column count mismatch: rust type {}, cql row {}",
244 TUPLE_LEN,
245 $idx
246 )).map_err(deser_error_replace_rust_name::<Self>)?;
247
248 <$Ti as DeserializeValue<'frame, 'metadata>>::deserialize(column.spec.typ(), column.slice)
249 .map_err(|err| mk_deser_err::<Self>(BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
250 column_index: column.index,
251 column_name: column.spec.name().to_owned(),
252 err,
253 }))?
254 },)*
255 );
256 assert!(
257 row.next().is_none(),
258 "Typecheck should have prevented this scenario! Column count mismatch: rust type {}, cql row is bigger",
259 TUPLE_LEN,
260 );
261 Ok(ret)
262 }
263 }
264 }
265}
266
267use super::value::impl_tuple_multiple;
268
269impl_tuple_multiple!(
271 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
272 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
273 t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15
274);
275
276#[derive(Debug, Error, Clone)]
281#[error(
282 "Failed to type check the Rust type {rust_name} against CQL column types {cql_types:?} : {kind}"
283)]
284pub struct BuiltinTypeCheckError {
285 pub rust_name: &'static str,
287
288 pub cql_types: Vec<ColumnType<'static>>,
290
291 pub kind: BuiltinTypeCheckErrorKind,
293}
294
295#[doc(hidden)]
297pub fn mk_typck_err<T>(
298 cql_types: impl IntoIterator<Item = ColumnType<'static>>,
299 kind: impl Into<BuiltinTypeCheckErrorKind>,
300) -> TypeCheckError {
301 mk_typck_err_named(std::any::type_name::<T>(), cql_types, kind)
302}
303
304fn mk_typck_err_named(
305 name: &'static str,
306 cql_types: impl IntoIterator<Item = ColumnType<'static>>,
307 kind: impl Into<BuiltinTypeCheckErrorKind>,
308) -> TypeCheckError {
309 TypeCheckError::new(BuiltinTypeCheckError {
310 rust_name: name,
311 cql_types: Vec::from_iter(cql_types),
312 kind: kind.into(),
313 })
314}
315
316#[derive(Debug, Clone)]
318#[non_exhaustive]
319pub enum BuiltinTypeCheckErrorKind {
320 WrongColumnCount {
322 rust_cols: usize,
324
325 cql_cols: usize,
327 },
328
329 ColumnWithUnknownName {
332 column_index: usize,
334
335 column_name: String,
337 },
338
339 ValuesMissingForColumns {
341 column_names: Vec<&'static str>,
344 },
345
346 ColumnNameMismatch {
348 field_index: usize,
350
351 column_index: usize,
353
354 rust_column_name: &'static str,
356
357 db_column_name: String,
359 },
360
361 ColumnTypeCheckFailed {
363 column_index: usize,
365
366 column_name: String,
368
369 err: TypeCheckError,
371 },
372
373 DuplicatedColumn {
375 column_index: usize,
377
378 column_name: &'static str,
380 },
381}
382
383impl Display for BuiltinTypeCheckErrorKind {
384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385 match self {
386 BuiltinTypeCheckErrorKind::WrongColumnCount {
387 rust_cols,
388 cql_cols,
389 } => {
390 write!(
391 f,
392 "wrong column count: the statement operates on {cql_cols} columns, but the given rust types contains {rust_cols}"
393 )
394 }
395 BuiltinTypeCheckErrorKind::ColumnWithUnknownName {
396 column_name,
397 column_index,
398 } => {
399 write!(
400 f,
401 "the CQL row contains a column {column_name} at column index {column_index}, but the corresponding field is not found in the Rust type",
402 )
403 }
404 BuiltinTypeCheckErrorKind::ValuesMissingForColumns { column_names } => {
405 write!(
406 f,
407 "values for columns {column_names:?} are missing from the DB data but are required by the Rust type"
408 )
409 }
410 BuiltinTypeCheckErrorKind::ColumnNameMismatch {
411 field_index,
412 column_index,
413 rust_column_name,
414 db_column_name,
415 } => write!(
416 f,
417 "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}",
418 ),
419 BuiltinTypeCheckErrorKind::ColumnTypeCheckFailed {
420 column_index,
421 column_name,
422 err,
423 } => write!(
424 f,
425 "mismatched types in column {column_name} at index {column_index}: {err}"
426 ),
427 BuiltinTypeCheckErrorKind::DuplicatedColumn {
428 column_name,
429 column_index,
430 } => write!(
431 f,
432 "column {column_name} occurs more than once in DB metadata; second occurrence is at column index {column_index}",
433 ),
434 }
435 }
436}
437
438#[derive(Debug, Error, Clone)]
441#[error("Failed to deserialize query result row {rust_name}: {kind}")]
442pub struct BuiltinDeserializationError {
443 pub rust_name: &'static str,
445
446 pub kind: BuiltinDeserializationErrorKind,
448}
449
450#[doc(hidden)]
452pub fn mk_deser_err<T>(kind: impl Into<BuiltinDeserializationErrorKind>) -> DeserializationError {
453 mk_deser_err_named(std::any::type_name::<T>(), kind)
454}
455
456fn mk_deser_err_named(
457 name: &'static str,
458 kind: impl Into<BuiltinDeserializationErrorKind>,
459) -> DeserializationError {
460 DeserializationError::new(BuiltinDeserializationError {
461 rust_name: name,
462 kind: kind.into(),
463 })
464}
465
466#[derive(Debug, Clone)]
468#[non_exhaustive]
469pub enum BuiltinDeserializationErrorKind {
470 ColumnDeserializationFailed {
472 column_index: usize,
474
475 column_name: String,
477
478 err: DeserializationError,
480 },
481
482 RawColumnDeserializationFailed {
485 column_index: usize,
487
488 column_name: String,
490
491 err: DeserializationError,
493 },
494}
495
496impl Display for BuiltinDeserializationErrorKind {
497 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
498 match self {
499 BuiltinDeserializationErrorKind::ColumnDeserializationFailed {
500 column_index,
501 column_name,
502 err,
503 } => {
504 write!(
505 f,
506 "failed to deserialize column {column_name} at index {column_index}: {err}"
507 )
508 }
509 BuiltinDeserializationErrorKind::RawColumnDeserializationFailed {
510 column_index,
511 column_name,
512 err,
513 } => {
514 write!(
515 f,
516 "failed to deserialize raw column {column_name} at index {column_index} (most probably due to invalid column structure inside a row): {err}"
517 )
518 }
519 }
520 }
521}
522
523#[cfg(test)]
524#[path = "row_tests.rs"]
525pub(crate) mod tests;
526
527fn _test_struct_deserialization_name_check_skip_requires_enforce_order() {}
534
535fn _test_struct_deserialization_skip_name_check_conflicts_with_rename() {}
545
546fn _test_struct_deserialization_skip_rename_collision_with_field() {}
557
558fn _test_struct_deserialization_rename_collision_with_another_rename() {}