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}