scylla_cql/deserialize/mod.rs
1#![doc = include_str!("README.md")]
2
3pub mod frame_slice;
4pub mod result;
5pub mod row;
6pub mod value;
7
8pub use frame_slice::FrameSlice;
9
10use std::error::Error;
11use std::sync::Arc;
12
13use thiserror::Error;
14
15// Errors
16
17/// An error indicating that a failure happened during type check.
18///
19/// The error is type-erased so that the crate users can define their own
20/// type check impls and their errors.
21/// As for the impls defined or generated
22/// by the driver itself, the following errors can be returned:
23///
24/// - [`row::BuiltinTypeCheckError`] is returned when type check of
25/// one of types with an impl built into the driver fails. It is also returned
26/// from impls generated by the `DeserializeRow` macro.
27/// - [`value::BuiltinTypeCheckError`] is analogous to the above but is
28/// returned from [`DeserializeValue::type_check`](value::DeserializeValue::type_check)
29/// instead both in the case of builtin impls and impls generated by the
30/// `DeserializeValue` macro.
31/// It won't be returned by the `Session` directly, but it might be nested
32/// in the [`row::BuiltinTypeCheckError`].
33#[derive(Debug, Clone, Error)]
34#[error("TypeCheckError: {0}")]
35pub struct TypeCheckError(pub(crate) Arc<dyn std::error::Error + Send + Sync>);
36
37impl TypeCheckError {
38 /// Constructs a new `TypeCheckError`.
39 #[inline]
40 pub fn new(err: impl std::error::Error + Send + Sync + 'static) -> Self {
41 Self(Arc::new(err))
42 }
43
44 /// Retrieve an error reason by downcasting to specific type.
45 pub fn downcast_ref<T: std::error::Error + 'static>(&self) -> Option<&T> {
46 self.0.downcast_ref()
47 }
48}
49
50/// An error indicating that a failure happened during deserialization.
51///
52/// The error is type-erased so that the crate users can define their own
53/// deserialization impls and their errors. As for the impls defined or generated
54/// by the driver itself, the following errors can be returned:
55///
56/// - [`row::BuiltinDeserializationError`] is returned when deserialization of
57/// one of types with an impl built into the driver fails. It is also returned
58/// from impls generated by the `DeserializeRow` macro.
59/// - [`value::BuiltinDeserializationError`] is analogous to the above but is
60/// returned from [`DeserializeValue::deserialize`](value::DeserializeValue::deserialize)
61/// instead both in the case of builtin impls and impls generated by the
62/// `DeserializeValue` macro.
63/// It won't be returned by the `Session` directly, but it might be nested
64/// in the [`row::BuiltinDeserializationError`].
65#[derive(Debug, Clone, Error)]
66#[error("DeserializationError: {0}")]
67pub struct DeserializationError(Arc<dyn Error + Send + Sync>);
68
69impl DeserializationError {
70 /// Constructs a new `DeserializationError`.
71 #[inline]
72 pub fn new(err: impl Error + Send + Sync + 'static) -> Self {
73 Self(Arc::new(err))
74 }
75
76 /// Retrieve an error reason by downcasting to specific type.
77 pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
78 self.0.downcast_ref()
79 }
80}
81
82// This is a hack to enable setting the proper Rust type name in error messages,
83// even though the error originates from some helper type used underneath.
84// ASSUMPTION: This should be used:
85// - ONLY in proper type_check()/deserialize() implementation,
86// - BEFORE an error is cloned (because otherwise the Arc::get_mut fails).
87macro_rules! make_error_replace_rust_name {
88 ($privacy: vis, $fn_name: ident, $outer_err: ty, $inner_err: ident) => {
89 // Not part of the public API; used in derive macros.
90 #[doc(hidden)]
91 #[allow(clippy::needless_pub_self)]
92 $privacy fn $fn_name<RustT>(mut err: $outer_err) -> $outer_err {
93 let rust_name = std::any::type_name::<RustT>();
94 match std::sync::Arc::get_mut(&mut err.0) {
95 Some(arc_mut) => {
96 if let Some(err) = arc_mut.downcast_mut::<$inner_err>() {
97 err.rust_name = rust_name;
98 }
99 },
100 None => {
101 if let Some(err) = err.0.downcast_ref::<$inner_err>() {
102 if err.rust_name != rust_name {
103 return <$outer_err>::new($inner_err {
104 rust_name,
105 ..err.clone()
106 });
107 }
108 }
109 }
110 }
111
112 err
113 }
114 };
115}
116use make_error_replace_rust_name;
117
118#[cfg(test)]
119pub(crate) mod tests {
120 use bytes::{Bytes, BytesMut};
121
122 use crate::frame::response::result::{ColumnSpec, ColumnType, TableSpec};
123 use crate::frame::types;
124
125 pub(super) static CELL1: &[u8] = &[1, 2, 3];
126 pub(super) static CELL2: &[u8] = &[4, 5, 6, 7];
127
128 pub(super) fn serialize_cells(
129 cells: impl IntoIterator<Item = Option<impl AsRef<[u8]>>>,
130 ) -> Bytes {
131 let mut bytes = BytesMut::new();
132 for cell in cells {
133 types::write_bytes_opt(cell, &mut bytes).unwrap();
134 }
135 bytes.freeze()
136 }
137
138 pub(crate) const fn spec<'a>(name: &'a str, typ: ColumnType<'a>) -> ColumnSpec<'a> {
139 ColumnSpec::borrowed(name, typ, TableSpec::borrowed("ks", "tbl"))
140 }
141}