scylla_cql/serialize/
value.rs

1//! Contains the [`SerializeValue`] trait and its implementations.
2
3// Note: When editing above doc-comment edit the corresponding comment on
4// re-export module in scylla crate too.
5
6use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
7use std::fmt::Display;
8use std::hash::BuildHasher;
9use std::net::IpAddr;
10use std::ops::Deref as _;
11use std::sync::Arc;
12
13use thiserror::Error;
14use uuid::Uuid;
15
16use crate::frame::response::result::{CollectionType, ColumnType, NativeType};
17use crate::frame::types::vint_encode;
18use crate::value::{
19    Counter, CqlDate, CqlDecimal, CqlDecimalBorrowed, CqlDuration, CqlTime, CqlTimestamp,
20    CqlTimeuuid, CqlValue, CqlVarint, CqlVarintBorrowed, MaybeUnset, Unset,
21};
22
23#[cfg(feature = "chrono-04")]
24use crate::value::ValueOverflow;
25
26use super::writers::WrittenCellProof;
27use super::{CellWriter, SerializationError};
28
29/// A type that can be serialized and sent along with a CQL statement.
30///
31/// This is a low-level trait that is exposed to the specifics to the CQL
32/// protocol and usually does not have to be implemented directly. See the
33/// chapter on "Query Values" in the driver docs for information about how
34/// this trait is supposed to be used.
35pub trait SerializeValue {
36    /// Serializes the value to given CQL type.
37    ///
38    /// The value should produce a `[value]`, according to the [CQL protocol
39    /// specification](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec),
40    /// containing the serialized value. See section 6 of the document on how
41    /// the contents of the `[value]` should look like.
42    ///
43    /// The value produced should match the type provided by `typ`. If the
44    /// value cannot be serialized to that type, an error should be returned.
45    ///
46    /// The [`CellWriter`] provided to the method ensures that the value produced
47    /// will be properly framed (i.e. incorrectly written value should not
48    /// cause the rest of the request to be misinterpreted), but otherwise
49    /// the implementor of the trait is responsible for producing the value
50    /// in a correct format.
51    fn serialize<'b>(
52        &self,
53        typ: &ColumnType,
54        writer: CellWriter<'b>,
55    ) -> Result<WrittenCellProof<'b>, SerializationError>;
56}
57
58macro_rules! exact_type_check {
59    ($typ:ident, $($cql:tt),*) => {
60        match $typ {
61            $(ColumnType::Native(NativeType::$cql))|* => {},
62            _ => return Err(mk_typck_err::<Self>(
63                $typ,
64                BuiltinTypeCheckErrorKind::MismatchedType {
65                    expected: &[$(ColumnType::Native(NativeType::$cql)),*],
66                }
67            ))
68        }
69    };
70}
71
72macro_rules! impl_serialize_via_writer {
73    (|$me:ident, $writer:ident| $e:expr) => {
74        impl_serialize_via_writer!(|$me, _typ, $writer| $e);
75    };
76    (|$me:ident, $typ:ident, $writer:ident| $e:expr) => {
77        fn serialize<'b>(
78            &self,
79            typ: &ColumnType,
80            writer: CellWriter<'b>,
81        ) -> Result<WrittenCellProof<'b>, SerializationError> {
82            let $writer = writer;
83            let $typ = typ;
84            let $me = self;
85            let proof = $e;
86            Ok(proof)
87        }
88    };
89}
90
91impl SerializeValue for i8 {
92    impl_serialize_via_writer!(|me, typ, writer| {
93        exact_type_check!(typ, TinyInt);
94        writer.set_value(me.to_be_bytes().as_slice()).unwrap()
95    });
96}
97impl SerializeValue for i16 {
98    impl_serialize_via_writer!(|me, typ, writer| {
99        exact_type_check!(typ, SmallInt);
100        writer.set_value(me.to_be_bytes().as_slice()).unwrap()
101    });
102}
103impl SerializeValue for i32 {
104    impl_serialize_via_writer!(|me, typ, writer| {
105        exact_type_check!(typ, Int);
106        writer.set_value(me.to_be_bytes().as_slice()).unwrap()
107    });
108}
109impl SerializeValue for i64 {
110    impl_serialize_via_writer!(|me, typ, writer| {
111        exact_type_check!(typ, BigInt);
112        writer.set_value(me.to_be_bytes().as_slice()).unwrap()
113    });
114}
115impl SerializeValue for CqlDecimal {
116    impl_serialize_via_writer!(|me, typ, writer| {
117        exact_type_check!(typ, Decimal);
118        let mut builder = writer.into_value_builder();
119        let (bytes, scale) = me.as_signed_be_bytes_slice_and_exponent();
120        builder.append_bytes(&scale.to_be_bytes());
121        builder.append_bytes(bytes);
122        builder
123            .finish()
124            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
125    });
126}
127impl SerializeValue for CqlDecimalBorrowed<'_> {
128    impl_serialize_via_writer!(|me, typ, writer| {
129        exact_type_check!(typ, Decimal);
130        let mut builder = writer.into_value_builder();
131        let (bytes, scale) = me.as_signed_be_bytes_slice_and_exponent();
132        builder.append_bytes(&scale.to_be_bytes());
133        builder.append_bytes(bytes);
134        builder
135            .finish()
136            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
137    });
138}
139#[cfg(feature = "bigdecimal-04")]
140impl SerializeValue for bigdecimal_04::BigDecimal {
141    impl_serialize_via_writer!(|me, typ, writer| {
142        exact_type_check!(typ, Decimal);
143        let mut builder = writer.into_value_builder();
144        let (value, scale) = me.as_bigint_and_exponent();
145        let scale: i32 = scale
146            .try_into()
147            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::ValueOverflow))?;
148        builder.append_bytes(&scale.to_be_bytes());
149        builder.append_bytes(&value.to_signed_bytes_be());
150        builder
151            .finish()
152            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
153    });
154}
155impl SerializeValue for CqlDate {
156    impl_serialize_via_writer!(|me, typ, writer| {
157        exact_type_check!(typ, Date);
158        writer.set_value(me.0.to_be_bytes().as_slice()).unwrap()
159    });
160}
161impl SerializeValue for CqlTimestamp {
162    impl_serialize_via_writer!(|me, typ, writer| {
163        exact_type_check!(typ, Timestamp);
164        writer.set_value(me.0.to_be_bytes().as_slice()).unwrap()
165    });
166}
167impl SerializeValue for CqlTime {
168    impl_serialize_via_writer!(|me, typ, writer| {
169        exact_type_check!(typ, Time);
170        writer.set_value(me.0.to_be_bytes().as_slice()).unwrap()
171    });
172}
173#[cfg(feature = "chrono-04")]
174impl SerializeValue for chrono_04::NaiveDate {
175    impl_serialize_via_writer!(|me, typ, writer| {
176        exact_type_check!(typ, Date);
177        <CqlDate as SerializeValue>::serialize(&(*me).into(), typ, writer)?
178    });
179}
180#[cfg(feature = "chrono-04")]
181impl SerializeValue for chrono_04::DateTime<chrono_04::Utc> {
182    impl_serialize_via_writer!(|me, typ, writer| {
183        exact_type_check!(typ, Timestamp);
184        <CqlTimestamp as SerializeValue>::serialize(&(*me).into(), typ, writer)?
185    });
186}
187#[cfg(feature = "chrono-04")]
188impl SerializeValue for chrono_04::NaiveTime {
189    impl_serialize_via_writer!(|me, typ, writer| {
190        exact_type_check!(typ, Time);
191        let cql_time = CqlTime::try_from(*me).map_err(|_: ValueOverflow| {
192            mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::ValueOverflow)
193        })?;
194        <CqlTime as SerializeValue>::serialize(&cql_time, typ, writer)?
195    });
196}
197#[cfg(feature = "time-03")]
198impl SerializeValue for time_03::Date {
199    impl_serialize_via_writer!(|me, typ, writer| {
200        exact_type_check!(typ, Date);
201        <CqlDate as SerializeValue>::serialize(&(*me).into(), typ, writer)?
202    });
203}
204#[cfg(feature = "time-03")]
205impl SerializeValue for time_03::OffsetDateTime {
206    impl_serialize_via_writer!(|me, typ, writer| {
207        exact_type_check!(typ, Timestamp);
208        <CqlTimestamp as SerializeValue>::serialize(&(*me).into(), typ, writer)?
209    });
210}
211#[cfg(feature = "time-03")]
212impl SerializeValue for time_03::Time {
213    impl_serialize_via_writer!(|me, typ, writer| {
214        exact_type_check!(typ, Time);
215        <CqlTime as SerializeValue>::serialize(&(*me).into(), typ, writer)?
216    });
217}
218#[cfg(feature = "secrecy-08")]
219impl<V: SerializeValue + secrecy_08::Zeroize> SerializeValue for secrecy_08::Secret<V> {
220    fn serialize<'b>(
221        &self,
222        typ: &ColumnType,
223        writer: CellWriter<'b>,
224    ) -> Result<WrittenCellProof<'b>, SerializationError> {
225        use secrecy_08::ExposeSecret;
226        V::serialize(self.expose_secret(), typ, writer)
227    }
228}
229impl SerializeValue for bool {
230    impl_serialize_via_writer!(|me, typ, writer| {
231        exact_type_check!(typ, Boolean);
232        writer.set_value(&[*me as u8]).unwrap()
233    });
234}
235impl SerializeValue for f32 {
236    impl_serialize_via_writer!(|me, typ, writer| {
237        exact_type_check!(typ, Float);
238        writer.set_value(me.to_be_bytes().as_slice()).unwrap()
239    });
240}
241impl SerializeValue for f64 {
242    impl_serialize_via_writer!(|me, typ, writer| {
243        exact_type_check!(typ, Double);
244        writer.set_value(me.to_be_bytes().as_slice()).unwrap()
245    });
246}
247impl SerializeValue for Uuid {
248    impl_serialize_via_writer!(|me, typ, writer| {
249        exact_type_check!(typ, Uuid);
250        writer.set_value(me.as_bytes().as_ref()).unwrap()
251    });
252}
253impl SerializeValue for CqlTimeuuid {
254    impl_serialize_via_writer!(|me, typ, writer| {
255        exact_type_check!(typ, Timeuuid);
256        writer.set_value(me.as_bytes().as_ref()).unwrap()
257    });
258}
259impl SerializeValue for CqlVarint {
260    impl_serialize_via_writer!(|me, typ, writer| {
261        exact_type_check!(typ, Varint);
262        writer
263            .set_value(me.as_signed_bytes_be_slice())
264            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
265    });
266}
267impl SerializeValue for CqlVarintBorrowed<'_> {
268    impl_serialize_via_writer!(|me, typ, writer| {
269        exact_type_check!(typ, Varint);
270        writer
271            .set_value(me.as_signed_bytes_be_slice())
272            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
273    });
274}
275#[cfg(feature = "num-bigint-03")]
276impl SerializeValue for num_bigint_03::BigInt {
277    impl_serialize_via_writer!(|me, typ, writer| {
278        exact_type_check!(typ, Varint);
279        // TODO: The allocation here can be avoided and we can reimplement
280        // `to_signed_bytes_be` by using `to_u64_digits` and a bit of custom
281        // logic. Need better tests in order to do this.
282        writer
283            .set_value(me.to_signed_bytes_be().as_slice())
284            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
285    });
286}
287#[cfg(feature = "num-bigint-04")]
288impl SerializeValue for num_bigint_04::BigInt {
289    impl_serialize_via_writer!(|me, typ, writer| {
290        exact_type_check!(typ, Varint);
291        // TODO: See above comment for num-bigint-03.
292        writer
293            .set_value(me.to_signed_bytes_be().as_slice())
294            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
295    });
296}
297impl SerializeValue for &str {
298    impl_serialize_via_writer!(|me, typ, writer| {
299        exact_type_check!(typ, Ascii, Text);
300        writer
301            .set_value(me.as_bytes())
302            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
303    });
304}
305impl SerializeValue for Vec<u8> {
306    impl_serialize_via_writer!(|me, typ, writer| {
307        exact_type_check!(typ, Blob);
308        writer
309            .set_value(me.as_ref())
310            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
311    });
312}
313impl SerializeValue for &[u8] {
314    impl_serialize_via_writer!(|me, typ, writer| {
315        exact_type_check!(typ, Blob);
316        writer
317            .set_value(me)
318            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
319    });
320}
321impl<const N: usize> SerializeValue for [u8; N] {
322    impl_serialize_via_writer!(|me, typ, writer| {
323        exact_type_check!(typ, Blob);
324        writer
325            .set_value(me.as_ref())
326            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
327    });
328}
329impl SerializeValue for IpAddr {
330    impl_serialize_via_writer!(|me, typ, writer| {
331        exact_type_check!(typ, Inet);
332        match me {
333            IpAddr::V4(ip) => writer.set_value(&ip.octets()).unwrap(),
334            IpAddr::V6(ip) => writer.set_value(&ip.octets()).unwrap(),
335        }
336    });
337}
338impl SerializeValue for String {
339    impl_serialize_via_writer!(|me, typ, writer| {
340        exact_type_check!(typ, Ascii, Text);
341        writer
342            .set_value(me.as_bytes())
343            .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))?
344    });
345}
346impl<T: SerializeValue> SerializeValue for Option<T> {
347    fn serialize<'b>(
348        &self,
349        typ: &ColumnType,
350        writer: CellWriter<'b>,
351    ) -> Result<WrittenCellProof<'b>, SerializationError> {
352        match self {
353            Some(v) => v.serialize(typ, writer),
354            None => Ok(writer.set_null()),
355        }
356    }
357}
358impl SerializeValue for Unset {
359    impl_serialize_via_writer!(|_me, writer| writer.set_unset());
360}
361impl SerializeValue for Counter {
362    impl_serialize_via_writer!(|me, typ, writer| {
363        exact_type_check!(typ, Counter);
364        writer.set_value(me.0.to_be_bytes().as_slice()).unwrap()
365    });
366}
367impl SerializeValue for CqlDuration {
368    impl_serialize_via_writer!(|me, typ, writer| {
369        exact_type_check!(typ, Duration);
370        // TODO: adjust vint_encode to use CellValueBuilder or something like that
371        let mut buf = Vec::with_capacity(27); // worst case size is 27
372        vint_encode(me.months as i64, &mut buf);
373        vint_encode(me.days as i64, &mut buf);
374        vint_encode(me.nanoseconds, &mut buf);
375        writer.set_value(buf.as_slice()).unwrap()
376    });
377}
378impl<V: SerializeValue> SerializeValue for MaybeUnset<V> {
379    fn serialize<'b>(
380        &self,
381        typ: &ColumnType,
382        writer: CellWriter<'b>,
383    ) -> Result<WrittenCellProof<'b>, SerializationError> {
384        match self {
385            MaybeUnset::Set(v) => v.serialize(typ, writer),
386            MaybeUnset::Unset => Ok(writer.set_unset()),
387        }
388    }
389}
390impl<T: SerializeValue + ?Sized> SerializeValue for &T {
391    fn serialize<'b>(
392        &self,
393        typ: &ColumnType,
394        writer: CellWriter<'b>,
395    ) -> Result<WrittenCellProof<'b>, SerializationError> {
396        T::serialize(*self, typ, writer)
397    }
398}
399impl<T: SerializeValue + ?Sized> SerializeValue for Box<T> {
400    fn serialize<'b>(
401        &self,
402        typ: &ColumnType,
403        writer: CellWriter<'b>,
404    ) -> Result<WrittenCellProof<'b>, SerializationError> {
405        T::serialize(&**self, typ, writer)
406    }
407}
408impl<V: SerializeValue, S: BuildHasher + Default> SerializeValue for HashSet<V, S> {
409    fn serialize<'b>(
410        &self,
411        typ: &ColumnType,
412        writer: CellWriter<'b>,
413    ) -> Result<WrittenCellProof<'b>, SerializationError> {
414        serialize_sequence(
415            std::any::type_name::<Self>(),
416            self.len(),
417            self.iter(),
418            typ,
419            writer,
420        )
421    }
422}
423impl<K: SerializeValue, V: SerializeValue, S: BuildHasher> SerializeValue for HashMap<K, V, S> {
424    fn serialize<'b>(
425        &self,
426        typ: &ColumnType,
427        writer: CellWriter<'b>,
428    ) -> Result<WrittenCellProof<'b>, SerializationError> {
429        serialize_mapping(
430            std::any::type_name::<Self>(),
431            self.len(),
432            self.iter(),
433            typ,
434            writer,
435        )
436    }
437}
438impl<V: SerializeValue> SerializeValue for BTreeSet<V> {
439    fn serialize<'b>(
440        &self,
441        typ: &ColumnType,
442        writer: CellWriter<'b>,
443    ) -> Result<WrittenCellProof<'b>, SerializationError> {
444        serialize_sequence(
445            std::any::type_name::<Self>(),
446            self.len(),
447            self.iter(),
448            typ,
449            writer,
450        )
451    }
452}
453impl<K: SerializeValue, V: SerializeValue> SerializeValue for BTreeMap<K, V> {
454    fn serialize<'b>(
455        &self,
456        typ: &ColumnType,
457        writer: CellWriter<'b>,
458    ) -> Result<WrittenCellProof<'b>, SerializationError> {
459        serialize_mapping(
460            std::any::type_name::<Self>(),
461            self.len(),
462            self.iter(),
463            typ,
464            writer,
465        )
466    }
467}
468impl<T: SerializeValue> SerializeValue for Vec<T> {
469    fn serialize<'b>(
470        &self,
471        typ: &ColumnType,
472        writer: CellWriter<'b>,
473    ) -> Result<WrittenCellProof<'b>, SerializationError> {
474        serialize_sequence(
475            std::any::type_name::<Self>(),
476            self.len(),
477            self.iter(),
478            typ,
479            writer,
480        )
481    }
482}
483impl<'a, T: SerializeValue + 'a> SerializeValue for &'a [T] {
484    fn serialize<'b>(
485        &self,
486        typ: &ColumnType,
487        writer: CellWriter<'b>,
488    ) -> Result<WrittenCellProof<'b>, SerializationError> {
489        serialize_sequence(
490            std::any::type_name::<Self>(),
491            self.len(),
492            self.iter(),
493            typ,
494            writer,
495        )
496    }
497}
498impl SerializeValue for CqlValue {
499    fn serialize<'b>(
500        &self,
501        typ: &ColumnType,
502        writer: CellWriter<'b>,
503    ) -> Result<WrittenCellProof<'b>, SerializationError> {
504        serialize_cql_value(self, typ, writer).map_err(fix_cql_value_name_in_err)
505    }
506}
507
508fn serialize_cql_value<'b>(
509    value: &CqlValue,
510    typ: &ColumnType,
511    writer: CellWriter<'b>,
512) -> Result<WrittenCellProof<'b>, SerializationError> {
513    match value {
514        CqlValue::Ascii(a) => <_ as SerializeValue>::serialize(&a, typ, writer),
515        CqlValue::Boolean(b) => <_ as SerializeValue>::serialize(&b, typ, writer),
516        CqlValue::Blob(b) => <_ as SerializeValue>::serialize(&b, typ, writer),
517        CqlValue::Counter(c) => <_ as SerializeValue>::serialize(&c, typ, writer),
518        CqlValue::Decimal(d) => <_ as SerializeValue>::serialize(&d, typ, writer),
519        CqlValue::Date(d) => <_ as SerializeValue>::serialize(&d, typ, writer),
520        CqlValue::Double(d) => <_ as SerializeValue>::serialize(&d, typ, writer),
521        CqlValue::Duration(d) => <_ as SerializeValue>::serialize(&d, typ, writer),
522        CqlValue::Empty => {
523            if !typ.supports_special_empty_value() {
524                return Err(mk_typck_err::<CqlValue>(
525                    typ,
526                    BuiltinTypeCheckErrorKind::NotEmptyable,
527                ));
528            }
529            Ok(writer.set_value(&[]).unwrap())
530        }
531        CqlValue::Float(f) => <_ as SerializeValue>::serialize(&f, typ, writer),
532        CqlValue::Int(i) => <_ as SerializeValue>::serialize(&i, typ, writer),
533        CqlValue::BigInt(b) => <_ as SerializeValue>::serialize(&b, typ, writer),
534        CqlValue::Text(t) => <_ as SerializeValue>::serialize(&t, typ, writer),
535        CqlValue::Timestamp(t) => <_ as SerializeValue>::serialize(&t, typ, writer),
536        CqlValue::Inet(i) => <_ as SerializeValue>::serialize(&i, typ, writer),
537        CqlValue::List(l) => <_ as SerializeValue>::serialize(&l, typ, writer),
538        CqlValue::Map(m) => serialize_mapping(
539            std::any::type_name::<CqlValue>(),
540            m.len(),
541            m.iter().map(|p| (&p.0, &p.1)),
542            typ,
543            writer,
544        ),
545        CqlValue::Set(s) => <_ as SerializeValue>::serialize(&s, typ, writer),
546        CqlValue::UserDefinedType {
547            keyspace,
548            name: type_name,
549            fields,
550        } => serialize_udt(typ, keyspace, type_name, fields, writer),
551        CqlValue::SmallInt(s) => <_ as SerializeValue>::serialize(&s, typ, writer),
552        CqlValue::TinyInt(t) => <_ as SerializeValue>::serialize(&t, typ, writer),
553        CqlValue::Time(t) => <_ as SerializeValue>::serialize(&t, typ, writer),
554        CqlValue::Timeuuid(t) => <_ as SerializeValue>::serialize(&t, typ, writer),
555        CqlValue::Tuple(t) => {
556            // We allow serializing tuples that have less fields
557            // than the database tuple, but not the other way around.
558            let fields = match typ {
559                ColumnType::Tuple(fields) => {
560                    if fields.len() < t.len() {
561                        return Err(mk_typck_err::<CqlValue>(
562                            typ,
563                            TupleTypeCheckErrorKind::WrongElementCount {
564                                rust_type_el_count: t.len(),
565                                cql_type_el_count: fields.len(),
566                            },
567                        ));
568                    }
569                    fields
570                }
571                _ => {
572                    return Err(mk_typck_err::<CqlValue>(
573                        typ,
574                        TupleTypeCheckErrorKind::NotTuple,
575                    ))
576                }
577            };
578            serialize_tuple_like(typ, fields.iter(), t.iter(), writer)
579        }
580        CqlValue::Uuid(u) => <_ as SerializeValue>::serialize(&u, typ, writer),
581        CqlValue::Varint(v) => <_ as SerializeValue>::serialize(&v, typ, writer),
582    }
583}
584
585fn fix_cql_value_name_in_err(mut err: SerializationError) -> SerializationError {
586    // The purpose of this function is to change the `rust_name` field
587    // in the error to CqlValue. Most of the time, the `err` given to the
588    // function here will be the sole owner of the data, so theoretically
589    // we could fix this in place.
590
591    let rust_name = std::any::type_name::<CqlValue>();
592
593    match Arc::get_mut(&mut err.0) {
594        Some(err_mut) => {
595            if let Some(err) = err_mut.downcast_mut::<BuiltinTypeCheckError>() {
596                err.rust_name = rust_name;
597            } else if let Some(err) = err_mut.downcast_mut::<BuiltinSerializationError>() {
598                err.rust_name = rust_name;
599            }
600        }
601        None => {
602            // The `None` case shouldn't happen considering how we are using
603            // the function in the code now, but let's provide it here anyway
604            // for correctness.
605            if let Some(err) = err.0.downcast_ref::<BuiltinTypeCheckError>() {
606                if err.rust_name != rust_name {
607                    return SerializationError::new(BuiltinTypeCheckError {
608                        rust_name,
609                        ..err.clone()
610                    });
611                }
612            }
613            if let Some(err) = err.0.downcast_ref::<BuiltinSerializationError>() {
614                if err.rust_name != rust_name {
615                    return SerializationError::new(BuiltinSerializationError {
616                        rust_name,
617                        ..err.clone()
618                    });
619                }
620            }
621        }
622    };
623
624    err
625}
626
627fn serialize_udt<'b>(
628    typ: &ColumnType,
629    keyspace: &str,
630    type_name: &str,
631    values: &[(String, Option<CqlValue>)],
632    writer: CellWriter<'b>,
633) -> Result<WrittenCellProof<'b>, SerializationError> {
634    let (dst_type_name, dst_keyspace, field_types) = match typ {
635        ColumnType::UserDefinedType {
636            definition: udt, ..
637        } => (&udt.name, &udt.keyspace, &udt.field_types),
638        _ => return Err(mk_typck_err::<CqlValue>(typ, UdtTypeCheckErrorKind::NotUdt)),
639    };
640
641    if keyspace != dst_keyspace || type_name != dst_type_name {
642        return Err(mk_typck_err::<CqlValue>(
643            typ,
644            UdtTypeCheckErrorKind::NameMismatch {
645                keyspace: dst_keyspace.clone().into_owned(),
646                type_name: dst_type_name.clone().into_owned(),
647            },
648        ));
649    }
650
651    // Allow columns present in the CQL type which are not present in CqlValue,
652    // but not the other way around
653    let mut indexed_fields: HashMap<_, _> = values.iter().map(|(k, v)| (k.as_str(), v)).collect();
654
655    let mut builder = writer.into_value_builder();
656    for (fname, ftyp) in field_types {
657        // Take a value from the original list.
658        // If a field is missing, write null instead.
659        let fvalue = indexed_fields
660            .remove(fname.deref())
661            .and_then(|x| x.as_ref());
662
663        let writer = builder.make_sub_writer();
664        match fvalue {
665            None => writer.set_null(),
666            Some(v) => serialize_cql_value(v, ftyp, writer).map_err(|err| {
667                let err = fix_cql_value_name_in_err(err);
668                mk_ser_err::<CqlValue>(
669                    typ,
670                    UdtSerializationErrorKind::FieldSerializationFailed {
671                        field_name: fname.clone().into_owned(),
672                        err,
673                    },
674                )
675            })?,
676        };
677    }
678
679    // If there are some leftover fields, it's an error.
680    if !indexed_fields.is_empty() {
681        // In order to have deterministic errors, return an error about
682        // the lexicographically smallest field.
683        let fname = indexed_fields.keys().min().unwrap();
684        return Err(mk_typck_err::<CqlValue>(
685            typ,
686            UdtTypeCheckErrorKind::NoSuchFieldInUdt {
687                field_name: fname.to_string(),
688            },
689        ));
690    }
691
692    builder
693        .finish()
694        .map_err(|_| mk_ser_err::<CqlValue>(typ, BuiltinSerializationErrorKind::SizeOverflow))
695}
696
697fn serialize_tuple_like<'t, 'b>(
698    typ: &ColumnType,
699    field_types: impl Iterator<Item = &'t ColumnType<'t>>,
700    field_values: impl Iterator<Item = &'t Option<CqlValue>>,
701    writer: CellWriter<'b>,
702) -> Result<WrittenCellProof<'b>, SerializationError> {
703    let mut builder = writer.into_value_builder();
704
705    for (index, (el, el_typ)) in field_values.zip(field_types).enumerate() {
706        let sub = builder.make_sub_writer();
707        match el {
708            None => sub.set_null(),
709            Some(el) => serialize_cql_value(el, el_typ, sub).map_err(|err| {
710                let err = fix_cql_value_name_in_err(err);
711                mk_ser_err::<CqlValue>(
712                    typ,
713                    TupleSerializationErrorKind::ElementSerializationFailed { index, err },
714                )
715            })?,
716        };
717    }
718
719    builder
720        .finish()
721        .map_err(|_| mk_ser_err::<CqlValue>(typ, BuiltinSerializationErrorKind::SizeOverflow))
722}
723
724macro_rules! impl_tuple {
725    (
726        $($typs:ident),*;
727        $($fidents:ident),*;
728        $($tidents:ident),*;
729        $length:expr
730    ) => {
731        impl<$($typs: SerializeValue),*> SerializeValue for ($($typs,)*) {
732            fn serialize<'b>(
733                &self,
734                typ: &ColumnType,
735                writer: CellWriter<'b>,
736            ) -> Result<WrittenCellProof<'b>, SerializationError> {
737                let ($($tidents,)*) = match typ {
738                    ColumnType::Tuple(typs) => match typs.as_slice() {
739                        [$($tidents),*] => ($($tidents,)*),
740                        _ => return Err(mk_typck_err::<Self>(
741                            typ,
742                            TupleTypeCheckErrorKind::WrongElementCount {
743                                rust_type_el_count: $length,
744                                cql_type_el_count: typs.len(),
745                            }
746                        ))
747                    }
748                    _ => return Err(mk_typck_err::<Self>(
749                        typ,
750                        TupleTypeCheckErrorKind::NotTuple,
751                    ))
752                };
753                let ($($fidents,)*) = self;
754                let mut builder = writer.into_value_builder();
755                let index = 0;
756                $(
757                    <$typs as SerializeValue>::serialize($fidents, $tidents, builder.make_sub_writer())
758                        .map_err(|err| mk_ser_err::<Self>(
759                            typ,
760                            TupleSerializationErrorKind::ElementSerializationFailed {
761                                index,
762                                err,
763                            }
764                        ))?;
765                    let index = index + 1;
766                )*
767                let _ = index;
768                builder
769                    .finish()
770                    .map_err(|_| mk_ser_err::<Self>(typ, BuiltinSerializationErrorKind::SizeOverflow))
771            }
772        }
773    };
774}
775
776macro_rules! impl_tuples {
777    (;;;$length:expr) => {};
778    (
779        $typ:ident$(, $($typs:ident),*)?;
780        $fident:ident$(, $($fidents:ident),*)?;
781        $tident:ident$(, $($tidents:ident),*)?;
782        $length:expr
783    ) => {
784        impl_tuples!(
785            $($($typs),*)?;
786            $($($fidents),*)?;
787            $($($tidents),*)?;
788            $length - 1
789        );
790        impl_tuple!(
791            $typ$(, $($typs),*)?;
792            $fident$(, $($fidents),*)?;
793            $tident$(, $($tidents),*)?;
794            $length
795        );
796    };
797}
798
799impl_tuples!(
800    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
801    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15;
802    t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
803    16
804);
805
806fn serialize_sequence<'t, 'b, T: SerializeValue + 't>(
807    rust_name: &'static str,
808    len: usize,
809    iter: impl Iterator<Item = &'t T>,
810    typ: &ColumnType,
811    writer: CellWriter<'b>,
812) -> Result<WrittenCellProof<'b>, SerializationError> {
813    let elt = match typ {
814        ColumnType::Collection {
815            frozen: false,
816            typ: CollectionType::List(elt),
817        }
818        | ColumnType::Collection {
819            frozen: false,
820            typ: CollectionType::Set(elt),
821        } => elt,
822        _ => {
823            return Err(mk_typck_err_named(
824                rust_name,
825                typ,
826                SetOrListTypeCheckErrorKind::NotSetOrList,
827            ));
828        }
829    };
830
831    let mut builder = writer.into_value_builder();
832
833    let element_count: i32 = len.try_into().map_err(|_| {
834        mk_ser_err_named(
835            rust_name,
836            typ,
837            SetOrListSerializationErrorKind::TooManyElements,
838        )
839    })?;
840    builder.append_bytes(&element_count.to_be_bytes());
841
842    for el in iter {
843        T::serialize(el, elt, builder.make_sub_writer()).map_err(|err| {
844            mk_ser_err_named(
845                rust_name,
846                typ,
847                SetOrListSerializationErrorKind::ElementSerializationFailed(err),
848            )
849        })?;
850    }
851
852    builder
853        .finish()
854        .map_err(|_| mk_ser_err_named(rust_name, typ, BuiltinSerializationErrorKind::SizeOverflow))
855}
856
857fn serialize_mapping<'t, 'b, K: SerializeValue + 't, V: SerializeValue + 't>(
858    rust_name: &'static str,
859    len: usize,
860    iter: impl Iterator<Item = (&'t K, &'t V)>,
861    typ: &ColumnType,
862    writer: CellWriter<'b>,
863) -> Result<WrittenCellProof<'b>, SerializationError> {
864    let (ktyp, vtyp) = match typ {
865        ColumnType::Collection {
866            frozen: false,
867            typ: CollectionType::Map(k, v),
868        } => (k, v),
869        _ => {
870            return Err(mk_typck_err_named(
871                rust_name,
872                typ,
873                MapTypeCheckErrorKind::NotMap,
874            ));
875        }
876    };
877
878    let mut builder = writer.into_value_builder();
879
880    let element_count: i32 = len.try_into().map_err(|_| {
881        mk_ser_err_named(rust_name, typ, MapSerializationErrorKind::TooManyElements)
882    })?;
883    builder.append_bytes(&element_count.to_be_bytes());
884
885    for (k, v) in iter {
886        K::serialize(k, ktyp, builder.make_sub_writer()).map_err(|err| {
887            mk_ser_err_named(
888                rust_name,
889                typ,
890                MapSerializationErrorKind::KeySerializationFailed(err),
891            )
892        })?;
893        V::serialize(v, vtyp, builder.make_sub_writer()).map_err(|err| {
894            mk_ser_err_named(
895                rust_name,
896                typ,
897                MapSerializationErrorKind::ValueSerializationFailed(err),
898            )
899        })?;
900    }
901
902    builder
903        .finish()
904        .map_err(|_| mk_ser_err_named(rust_name, typ, BuiltinSerializationErrorKind::SizeOverflow))
905}
906
907/// Type checking of one of the built-in types failed.
908#[derive(Debug, Error, Clone)]
909#[error("Failed to type check Rust type {rust_name} against CQL type {got:?}: {kind}")]
910pub struct BuiltinTypeCheckError {
911    /// Name of the Rust type being serialized.
912    pub rust_name: &'static str,
913
914    /// The CQL type that the Rust type was being serialized to.
915    pub got: ColumnType<'static>,
916
917    /// Detailed information about the failure.
918    pub kind: BuiltinTypeCheckErrorKind,
919}
920
921fn mk_typck_err<T>(
922    got: &ColumnType,
923    kind: impl Into<BuiltinTypeCheckErrorKind>,
924) -> SerializationError {
925    mk_typck_err_named(std::any::type_name::<T>(), got, kind)
926}
927
928fn mk_typck_err_named(
929    name: &'static str,
930    got: &ColumnType,
931    kind: impl Into<BuiltinTypeCheckErrorKind>,
932) -> SerializationError {
933    SerializationError::new(BuiltinTypeCheckError {
934        rust_name: name,
935        got: got.clone().into_owned(),
936        kind: kind.into(),
937    })
938}
939
940/// Serialization of one of the built-in types failed.
941#[derive(Debug, Error, Clone)]
942#[error("Failed to serialize Rust type {rust_name} into CQL type {got:?}: {kind}")]
943pub struct BuiltinSerializationError {
944    /// Name of the Rust type being serialized.
945    pub rust_name: &'static str,
946
947    /// The CQL type that the Rust type was being serialized to.
948    pub got: ColumnType<'static>,
949
950    /// Detailed information about the failure.
951    pub kind: BuiltinSerializationErrorKind,
952}
953
954pub(crate) fn mk_ser_err<T>(
955    got: &ColumnType,
956    kind: impl Into<BuiltinSerializationErrorKind>,
957) -> SerializationError {
958    mk_ser_err_named(std::any::type_name::<T>(), got, kind)
959}
960
961fn mk_ser_err_named(
962    name: &'static str,
963    got: &ColumnType,
964    kind: impl Into<BuiltinSerializationErrorKind>,
965) -> SerializationError {
966    SerializationError::new(BuiltinSerializationError {
967        rust_name: name,
968        got: got.clone().into_owned(),
969        kind: kind.into(),
970    })
971}
972
973/// Describes why type checking some of the built-in types has failed.
974#[derive(Debug, Clone)]
975#[non_exhaustive]
976pub enum BuiltinTypeCheckErrorKind {
977    /// Expected one from a list of particular types.
978    MismatchedType {
979        /// The list of types that the Rust type can serialize as.
980        expected: &'static [ColumnType<'static>],
981    },
982
983    /// Expected a type that can be empty.
984    NotEmptyable,
985
986    /// A type check failure specific to a CQL set or list.
987    SetOrListError(SetOrListTypeCheckErrorKind),
988
989    /// A type check failure specific to a CQL map.
990    MapError(MapTypeCheckErrorKind),
991
992    /// A type check failure specific to a CQL tuple.
993    TupleError(TupleTypeCheckErrorKind),
994
995    /// A type check failure specific to a CQL UDT.
996    UdtError(UdtTypeCheckErrorKind),
997}
998
999impl From<SetOrListTypeCheckErrorKind> for BuiltinTypeCheckErrorKind {
1000    fn from(value: SetOrListTypeCheckErrorKind) -> Self {
1001        BuiltinTypeCheckErrorKind::SetOrListError(value)
1002    }
1003}
1004
1005impl From<MapTypeCheckErrorKind> for BuiltinTypeCheckErrorKind {
1006    fn from(value: MapTypeCheckErrorKind) -> Self {
1007        BuiltinTypeCheckErrorKind::MapError(value)
1008    }
1009}
1010
1011impl From<TupleTypeCheckErrorKind> for BuiltinTypeCheckErrorKind {
1012    fn from(value: TupleTypeCheckErrorKind) -> Self {
1013        BuiltinTypeCheckErrorKind::TupleError(value)
1014    }
1015}
1016
1017impl From<UdtTypeCheckErrorKind> for BuiltinTypeCheckErrorKind {
1018    fn from(value: UdtTypeCheckErrorKind) -> Self {
1019        BuiltinTypeCheckErrorKind::UdtError(value)
1020    }
1021}
1022
1023impl Display for BuiltinTypeCheckErrorKind {
1024    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1025        match self {
1026            BuiltinTypeCheckErrorKind::MismatchedType { expected } => {
1027                write!(f, "expected one of the CQL types: {expected:?}")
1028            }
1029            BuiltinTypeCheckErrorKind::NotEmptyable => {
1030                f.write_str("the separate empty representation is not valid for this type")
1031            }
1032            BuiltinTypeCheckErrorKind::SetOrListError(err) => err.fmt(f),
1033            BuiltinTypeCheckErrorKind::MapError(err) => err.fmt(f),
1034            BuiltinTypeCheckErrorKind::TupleError(err) => err.fmt(f),
1035            BuiltinTypeCheckErrorKind::UdtError(err) => err.fmt(f),
1036        }
1037    }
1038}
1039
1040/// Describes why serialization of some of the built-in types has failed.
1041#[derive(Debug, Clone)]
1042#[non_exhaustive]
1043pub enum BuiltinSerializationErrorKind {
1044    /// The size of the Rust value is too large to fit in the CQL serialization
1045    /// format (over i32::MAX bytes).
1046    SizeOverflow,
1047
1048    /// The Rust value is out of range supported by the CQL type.
1049    ValueOverflow,
1050
1051    /// A serialization failure specific to a CQL set or list.
1052    SetOrListError(SetOrListSerializationErrorKind),
1053
1054    /// A serialization failure specific to a CQL map.
1055    MapError(MapSerializationErrorKind),
1056
1057    /// A serialization failure specific to a CQL tuple.
1058    TupleError(TupleSerializationErrorKind),
1059
1060    /// A serialization failure specific to a CQL UDT.
1061    UdtError(UdtSerializationErrorKind),
1062}
1063
1064impl From<SetOrListSerializationErrorKind> for BuiltinSerializationErrorKind {
1065    fn from(value: SetOrListSerializationErrorKind) -> Self {
1066        BuiltinSerializationErrorKind::SetOrListError(value)
1067    }
1068}
1069
1070impl From<MapSerializationErrorKind> for BuiltinSerializationErrorKind {
1071    fn from(value: MapSerializationErrorKind) -> Self {
1072        BuiltinSerializationErrorKind::MapError(value)
1073    }
1074}
1075
1076impl From<TupleSerializationErrorKind> for BuiltinSerializationErrorKind {
1077    fn from(value: TupleSerializationErrorKind) -> Self {
1078        BuiltinSerializationErrorKind::TupleError(value)
1079    }
1080}
1081
1082impl From<UdtSerializationErrorKind> for BuiltinSerializationErrorKind {
1083    fn from(value: UdtSerializationErrorKind) -> Self {
1084        BuiltinSerializationErrorKind::UdtError(value)
1085    }
1086}
1087
1088impl Display for BuiltinSerializationErrorKind {
1089    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1090        match self {
1091            BuiltinSerializationErrorKind::SizeOverflow => {
1092                f.write_str("the Rust value is too big to be serialized in the CQL protocol format")
1093            }
1094            BuiltinSerializationErrorKind::ValueOverflow => {
1095                f.write_str("the Rust value is out of range supported by the CQL type")
1096            }
1097            BuiltinSerializationErrorKind::SetOrListError(err) => err.fmt(f),
1098            BuiltinSerializationErrorKind::MapError(err) => err.fmt(f),
1099            BuiltinSerializationErrorKind::TupleError(err) => err.fmt(f),
1100            BuiltinSerializationErrorKind::UdtError(err) => err.fmt(f),
1101        }
1102    }
1103}
1104
1105/// Describes why type checking of a map type failed.
1106#[derive(Debug, Clone)]
1107#[non_exhaustive]
1108pub enum MapTypeCheckErrorKind {
1109    /// The CQL type is not a map.
1110    NotMap,
1111}
1112
1113impl Display for MapTypeCheckErrorKind {
1114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1115        match self {
1116            MapTypeCheckErrorKind::NotMap => f.write_str(
1117                "the CQL type the Rust type was attempted to be type checked against was not a map",
1118            ),
1119        }
1120    }
1121}
1122
1123/// Describes why serialization of a map type failed.
1124#[derive(Debug, Clone)]
1125#[non_exhaustive]
1126pub enum MapSerializationErrorKind {
1127    /// The many contains too many items, exceeding the protocol limit (i32::MAX).
1128    TooManyElements,
1129
1130    /// One of the keys in the map failed to serialize.
1131    KeySerializationFailed(SerializationError),
1132
1133    /// One of the values in the map failed to serialize.
1134    ValueSerializationFailed(SerializationError),
1135}
1136
1137impl Display for MapSerializationErrorKind {
1138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1139        match self {
1140            MapSerializationErrorKind::TooManyElements => {
1141                f.write_str("the map contains too many elements to fit in CQL representation")
1142            }
1143            MapSerializationErrorKind::KeySerializationFailed(err) => {
1144                write!(f, "failed to serialize one of the keys: {}", err)
1145            }
1146            MapSerializationErrorKind::ValueSerializationFailed(err) => {
1147                write!(f, "failed to serialize one of the values: {}", err)
1148            }
1149        }
1150    }
1151}
1152
1153/// Describes why type checking of a set or list type failed.
1154#[derive(Debug, Clone)]
1155#[non_exhaustive]
1156pub enum SetOrListTypeCheckErrorKind {
1157    /// The CQL type is neither a set not a list.
1158    NotSetOrList,
1159}
1160
1161impl Display for SetOrListTypeCheckErrorKind {
1162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1163        match self {
1164            SetOrListTypeCheckErrorKind::NotSetOrList => {
1165                f.write_str("the CQL type the Rust type was attempted to be type checked against was neither a set or a list")
1166            }
1167        }
1168    }
1169}
1170
1171/// Describes why serialization of a set or list type failed.
1172#[derive(Debug, Clone)]
1173#[non_exhaustive]
1174pub enum SetOrListSerializationErrorKind {
1175    /// The set/list contains too many items, exceeding the protocol limit (i32::MAX).
1176    TooManyElements,
1177
1178    /// One of the elements of the set/list failed to serialize.
1179    ElementSerializationFailed(SerializationError),
1180}
1181
1182impl Display for SetOrListSerializationErrorKind {
1183    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1184        match self {
1185            SetOrListSerializationErrorKind::TooManyElements => f.write_str(
1186                "the collection contains too many elements to fit in CQL representation",
1187            ),
1188            SetOrListSerializationErrorKind::ElementSerializationFailed(err) => {
1189                write!(f, "failed to serialize one of the elements: {err}")
1190            }
1191        }
1192    }
1193}
1194
1195/// Describes why type checking of a tuple failed.
1196#[derive(Debug, Clone)]
1197#[non_exhaustive]
1198pub enum TupleTypeCheckErrorKind {
1199    /// The CQL type is not a tuple.
1200    NotTuple,
1201
1202    /// The tuple has the wrong element count.
1203    ///
1204    /// Note that it is allowed to write a Rust tuple with less elements
1205    /// than the corresponding CQL type, but not more. The additional, unknown
1206    /// elements will be set to null.
1207    WrongElementCount {
1208        /// The number of elements that the Rust tuple has.
1209        rust_type_el_count: usize,
1210
1211        /// The number of elements that the CQL tuple type has.
1212        cql_type_el_count: usize,
1213    },
1214}
1215
1216impl Display for TupleTypeCheckErrorKind {
1217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1218        match self {
1219            TupleTypeCheckErrorKind::NotTuple => f.write_str(
1220                "the CQL type the Rust type was attempted to be type checked against is not a tuple"
1221            ),
1222            TupleTypeCheckErrorKind::WrongElementCount { rust_type_el_count, cql_type_el_count } => write!(
1223                f,
1224                "wrong tuple element count: CQL type has {cql_type_el_count}, the Rust tuple has {rust_type_el_count}"
1225            ),
1226        }
1227    }
1228}
1229
1230/// Describes why serialize of a tuple failed.
1231#[derive(Debug, Clone)]
1232#[non_exhaustive]
1233pub enum TupleSerializationErrorKind {
1234    /// One of the tuple elements failed to serialize.
1235    ElementSerializationFailed {
1236        /// Index of the tuple element that failed to serialize.
1237        index: usize,
1238
1239        /// The error that caused the tuple field serialization to fail.
1240        err: SerializationError,
1241    },
1242}
1243
1244impl Display for TupleSerializationErrorKind {
1245    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1246        match self {
1247            TupleSerializationErrorKind::ElementSerializationFailed { index, err } => {
1248                write!(f, "element no. {index} failed to serialize: {err}")
1249            }
1250        }
1251    }
1252}
1253
1254/// Describes why type checking of a user defined type failed.
1255#[derive(Debug, Clone)]
1256#[non_exhaustive]
1257pub enum UdtTypeCheckErrorKind {
1258    /// The CQL type is not a user defined type.
1259    NotUdt,
1260
1261    /// The name of the UDT being serialized to does not match.
1262    NameMismatch {
1263        /// Keyspace in which the UDT was defined.
1264        keyspace: String,
1265
1266        /// Name of the UDT.
1267        type_name: String,
1268    },
1269
1270    /// The Rust data does not have a field that is required in the CQL UDT type.
1271    ValueMissingForUdtField {
1272        /// Name of field that the CQL UDT requires but is missing in the Rust struct.
1273        field_name: String,
1274    },
1275
1276    /// The Rust data contains a field that is not present in the UDT.
1277    NoSuchFieldInUdt {
1278        /// Name of the Rust struct field that is missing in the UDT.
1279        field_name: String,
1280    },
1281
1282    /// A different field name was expected at given position.
1283    FieldNameMismatch {
1284        /// The name of the Rust field.
1285        rust_field_name: String,
1286
1287        /// The name of the CQL UDT field.
1288        db_field_name: String,
1289    },
1290}
1291
1292impl Display for UdtTypeCheckErrorKind {
1293    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1294        match self {
1295            UdtTypeCheckErrorKind::NotUdt => f.write_str("the CQL type the Rust type was attempted to be type checked against is not a UDT"),
1296            UdtTypeCheckErrorKind::NameMismatch {
1297                keyspace,
1298                type_name,
1299            } => write!(
1300                f,
1301                "the Rust UDT name does not match the actual CQL UDT name ({keyspace}.{type_name})"
1302            ),
1303            UdtTypeCheckErrorKind::ValueMissingForUdtField { field_name } => {
1304                write!(f, "the field {field_name} is missing in the Rust data but is required by the CQL UDT type")
1305            }
1306            UdtTypeCheckErrorKind::NoSuchFieldInUdt { field_name } => write!(
1307                f,
1308                "the field {field_name} that is present in the Rust data is not present in the CQL type"
1309            ),
1310            UdtTypeCheckErrorKind::FieldNameMismatch { rust_field_name, db_field_name } => write!(
1311                f,
1312                "expected field with name {db_field_name} at given position, but the Rust field name is {rust_field_name}"
1313            ),
1314        }
1315    }
1316}
1317
1318/// Describes why serialization of a user defined type failed.
1319#[derive(Debug, Clone)]
1320#[non_exhaustive]
1321pub enum UdtSerializationErrorKind {
1322    /// One of the fields failed to serialize.
1323    FieldSerializationFailed {
1324        /// Name of the field which failed to serialize.
1325        field_name: String,
1326
1327        /// The error that caused the UDT field serialization to fail.
1328        err: SerializationError,
1329    },
1330}
1331
1332impl Display for UdtSerializationErrorKind {
1333    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1334        match self {
1335            UdtSerializationErrorKind::FieldSerializationFailed { field_name, err } => {
1336                write!(f, "field {field_name} failed to serialize: {err}")
1337            }
1338        }
1339    }
1340}
1341
1342mod doctests {
1343    /// ```compile_fail
1344    ///
1345    /// #[derive(scylla_macros::SerializeValue)]
1346    /// #[scylla(crate = scylla_cql, skip_name_checks)]
1347    /// struct TestUdt {}
1348    /// ```
1349    fn _test_udt_bad_attributes_skip_name_check_requires_enforce_order() {}
1350
1351    /// ```compile_fail
1352    ///
1353    /// #[derive(scylla_macros::SerializeValue)]
1354    /// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
1355    /// struct TestUdt {
1356    ///     #[scylla(rename = "b")]
1357    ///     a: i32,
1358    /// }
1359    /// ```
1360    fn _test_udt_bad_attributes_skip_name_check_conflicts_with_rename() {}
1361
1362    /// ```compile_fail
1363    ///
1364    /// #[derive(scylla_macros::SerializeValue)]
1365    /// #[scylla(crate = scylla_cql)]
1366    /// struct TestUdt {
1367    ///     #[scylla(rename = "b")]
1368    ///     a: i32,
1369    ///     b: String,
1370    /// }
1371    /// ```
1372    fn _test_udt_bad_attributes_rename_collision_with_field() {}
1373
1374    /// ```compile_fail
1375    ///
1376    /// #[derive(scylla_macros::SerializeValue)]
1377    /// #[scylla(crate = scylla_cql)]
1378    /// struct TestUdt {
1379    ///     #[scylla(rename = "c")]
1380    ///     a: i32,
1381    ///     #[scylla(rename = "c")]
1382    ///     b: String,
1383    /// }
1384    /// ```
1385    fn _test_udt_bad_attributes_rename_collision_with_another_rename() {}
1386
1387    /// ```compile_fail
1388    ///
1389    /// #[derive(scylla_macros::SerializeValue)]
1390    /// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
1391    /// struct TestUdt {
1392    ///     a: i32,
1393    ///     #[scylla(allow_missing)]
1394    ///     b: bool,
1395    ///     c: String,
1396    /// }
1397    /// ```
1398    fn _test_udt_bad_attributes_name_skip_name_checks_limitations_on_allow_missing() {}
1399
1400    /// ```
1401    ///
1402    /// #[derive(scylla_macros::SerializeValue)]
1403    /// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
1404    /// struct TestUdt {
1405    ///     a: i32,
1406    ///     #[scylla(allow_missing)]
1407    ///     b: bool,
1408    ///     #[scylla(allow_missing)]
1409    ///     c: String,
1410    /// }
1411    /// ```
1412    fn _test_udt_good_attributes_name_skip_name_checks_limitations_on_allow_missing() {}
1413
1414    /// ```
1415    /// #[derive(scylla_macros::SerializeValue)]
1416    /// #[scylla(crate = scylla_cql)]
1417    /// struct TestUdt {
1418    ///     a: i32,
1419    ///     #[scylla(allow_missing)]
1420    ///     b: bool,
1421    ///     c: String,
1422    /// }
1423    /// ```
1424    fn _test_udt_unordered_flavour_no_limitations_on_allow_missing() {}
1425
1426    /// ```
1427    /// #[derive(scylla_macros::SerializeValue)]
1428    /// #[scylla(crate = scylla_cql)]
1429    /// struct TestUdt {
1430    ///     a: i32,
1431    ///     #[scylla(default_when_null)]
1432    ///     b: bool,
1433    ///     c: String,
1434    /// }
1435    /// ```
1436    fn _test_udt_default_when_null_is_accepted() {}
1437}
1438
1439#[cfg(test)]
1440#[path = "value_tests.rs"]
1441pub(crate) mod tests;