1use std::net::IpAddr;
5
6use thiserror::Error;
7use uuid::Uuid;
8
9use crate::utils::safe_format::IteratorSafeFormatExt;
10
11#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16#[error(
17 "Conversion between CQL type and another type is not possible because\
18 value of one of them is too large to fit in the other"
19)]
20pub struct ValueOverflow;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
24pub struct Unset;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
28pub struct Counter(pub i64);
29
30#[derive(Debug, Clone, Copy, Default)]
32pub enum MaybeUnset<V> {
33 #[default]
35 Unset,
36 Set(V),
38}
39
40impl<V> MaybeUnset<V> {
41 #[inline]
43 pub fn from_option(opt: Option<V>) -> Self {
44 match opt {
45 Some(v) => Self::Set(v),
46 None => Self::Unset,
47 }
48 }
49}
50
51pub trait Emptiable {}
62
63impl Emptiable for bool {}
66impl Emptiable for i8 {}
67impl Emptiable for i16 {}
68impl Emptiable for i32 {}
69impl Emptiable for i64 {}
70impl Emptiable for f32 {}
71impl Emptiable for f64 {}
72
73impl Emptiable for CqlVarint {}
74impl<'b> Emptiable for CqlVarintBorrowed<'b> {}
75impl Emptiable for CqlDecimal {}
76impl<'b> Emptiable for CqlDecimalBorrowed<'b> {}
77impl Emptiable for CqlDate {}
78impl Emptiable for CqlTime {}
79impl Emptiable for CqlTimestamp {}
80impl Emptiable for CqlTimeuuid {}
81
82impl Emptiable for std::net::IpAddr {}
83impl Emptiable for uuid::Uuid {}
84
85#[cfg(feature = "num-bigint-03")]
86impl Emptiable for num_bigint_03::BigInt {}
87#[cfg(feature = "num-bigint-04")]
88impl Emptiable for num_bigint_04::BigInt {}
89#[cfg(feature = "bigdecimal-04")]
90impl Emptiable for bigdecimal_04::BigDecimal {}
91
92#[cfg(feature = "chrono-04")]
93impl Emptiable for chrono_04::NaiveDate {}
94#[cfg(feature = "chrono-04")]
95impl Emptiable for chrono_04::NaiveTime {}
96#[cfg(feature = "chrono-04")]
97impl Emptiable for chrono_04::DateTime<chrono_04::Utc> {}
98
99#[cfg(feature = "time-03")]
100impl Emptiable for time_03::Date {}
101#[cfg(feature = "time-03")]
102impl Emptiable for time_03::Time {}
103#[cfg(feature = "time-03")]
104impl Emptiable for time_03::OffsetDateTime {}
105
106#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
115pub enum MaybeEmpty<T: Emptiable> {
116 Empty,
118 Value(T),
120}
121
122#[derive(Debug, Clone, Copy, Eq)]
127pub struct CqlTimeuuid(Uuid);
128
129impl CqlTimeuuid {
131 pub fn nil() -> Self {
134 Self(Uuid::nil())
135 }
136
137 pub fn as_bytes(&self) -> &[u8; 16] {
140 self.0.as_bytes()
141 }
142
143 pub fn as_u128(&self) -> u128 {
146 self.0.as_u128()
147 }
148
149 pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) {
152 self.0.as_fields()
153 }
154
155 pub fn as_u64_pair(&self) -> (u64, u64) {
158 self.0.as_u64_pair()
159 }
160
161 pub fn from_slice(b: &[u8]) -> Result<Self, uuid::Error> {
164 Ok(Self(Uuid::from_slice(b)?))
165 }
166
167 pub fn from_slice_le(b: &[u8]) -> Result<Self, uuid::Error> {
170 Ok(Self(Uuid::from_slice_le(b)?))
171 }
172
173 pub fn from_bytes(bytes: [u8; 16]) -> Self {
176 Self(Uuid::from_bytes(bytes))
177 }
178
179 pub fn from_bytes_le(bytes: [u8; 16]) -> Self {
182 Self(Uuid::from_bytes_le(bytes))
183 }
184
185 pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self {
188 Self(Uuid::from_fields(d1, d2, d3, d4))
189 }
190
191 pub fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self {
194 Self(Uuid::from_fields_le(d1, d2, d3, d4))
195 }
196
197 pub fn from_u128(v: u128) -> Self {
200 Self(Uuid::from_u128(v))
201 }
202
203 pub fn from_u128_le(v: u128) -> Self {
206 Self(Uuid::from_u128_le(v))
207 }
208
209 pub fn from_u64_pair(high_bits: u64, low_bits: u64) -> Self {
212 Self(Uuid::from_u64_pair(high_bits, low_bits))
213 }
214}
215
216impl CqlTimeuuid {
217 fn msb(&self) -> u64 {
219 let bytes = self.0.as_bytes();
223 u64::from_be_bytes([
224 bytes[6] & 0x0f,
225 bytes[7],
226 bytes[4],
227 bytes[5],
228 bytes[0],
229 bytes[1],
230 bytes[2],
231 bytes[3],
232 ])
233 }
234
235 fn lsb(&self) -> u64 {
236 let bytes = self.0.as_bytes();
237 u64::from_be_bytes([
238 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
239 ])
240 }
241
242 fn lsb_signed(&self) -> u64 {
243 self.lsb() ^ 0x8080808080808080
244 }
245}
246
247impl std::str::FromStr for CqlTimeuuid {
248 type Err = uuid::Error;
249
250 fn from_str(s: &str) -> Result<Self, Self::Err> {
251 Ok(Self(Uuid::from_str(s)?))
252 }
253}
254
255impl std::fmt::Display for CqlTimeuuid {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 write!(f, "{}", self.0)
258 }
259}
260
261impl AsRef<Uuid> for CqlTimeuuid {
262 fn as_ref(&self) -> &Uuid {
263 &self.0
264 }
265}
266
267impl From<CqlTimeuuid> for Uuid {
268 fn from(value: CqlTimeuuid) -> Self {
269 value.0
270 }
271}
272
273impl From<Uuid> for CqlTimeuuid {
274 fn from(value: Uuid) -> Self {
275 Self(value)
276 }
277}
278
279impl Ord for CqlTimeuuid {
287 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
288 let mut res = self.msb().cmp(&other.msb());
289 if let std::cmp::Ordering::Equal = res {
290 res = self.lsb_signed().cmp(&other.lsb_signed());
291 }
292 res
293 }
294}
295
296impl PartialOrd for CqlTimeuuid {
297 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
298 Some(self.cmp(other))
299 }
300}
301
302impl PartialEq for CqlTimeuuid {
303 fn eq(&self, other: &Self) -> bool {
304 self.cmp(other) == std::cmp::Ordering::Equal
305 }
306}
307
308impl std::hash::Hash for CqlTimeuuid {
309 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
310 self.lsb_signed().hash(state);
311 self.msb().hash(state);
312 }
313}
314
315#[derive(Clone, Eq, Debug)]
343pub struct CqlVarint(Vec<u8>);
344
345#[derive(Clone, Eq, Debug)]
350pub struct CqlVarintBorrowed<'b>(&'b [u8]);
351
352impl CqlVarint {
354 pub fn from_signed_bytes_be(digits: Vec<u8>) -> Self {
359 Self(digits)
360 }
361
362 pub fn from_signed_bytes_be_slice(digits: &[u8]) -> Self {
367 Self::from_signed_bytes_be(digits.to_vec())
368 }
369}
370
371impl<'b> CqlVarintBorrowed<'b> {
373 pub fn from_signed_bytes_be_slice(digits: &'b [u8]) -> Self {
378 Self(digits)
379 }
380}
381
382impl CqlVarint {
384 pub fn into_signed_bytes_be(self) -> Vec<u8> {
387 self.0
388 }
389
390 pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
393 &self.0
394 }
395}
396
397impl CqlVarintBorrowed<'_> {
399 pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
402 self.0
403 }
404}
405
406trait AsVarintSlice {
409 fn as_slice(&self) -> &[u8];
410}
411impl AsVarintSlice for CqlVarint {
412 fn as_slice(&self) -> &[u8] {
413 self.as_signed_bytes_be_slice()
414 }
415}
416impl AsVarintSlice for CqlVarintBorrowed<'_> {
417 fn as_slice(&self) -> &[u8] {
418 self.as_signed_bytes_be_slice()
419 }
420}
421
422trait AsNormalizedVarintSlice {
425 fn as_normalized_slice(&self) -> &[u8];
426}
427impl<V: AsVarintSlice> AsNormalizedVarintSlice for V {
428 fn as_normalized_slice(&self) -> &[u8] {
429 let digits = self.as_slice();
430 if digits.is_empty() {
431 return &[0];
434 }
435
436 let non_zero_position = match digits.iter().position(|b| *b != 0) {
437 Some(pos) => pos,
438 None => {
439 return &[0];
441 }
442 };
443
444 if non_zero_position > 0 {
445 let zeros_to_remove = if digits[non_zero_position] > 0x7f {
448 non_zero_position - 1
451 } else {
452 non_zero_position
454 };
455 return &digits[zeros_to_remove..];
456 }
457
458 digits
460 }
461}
462
463impl PartialEq for CqlVarint {
477 fn eq(&self, other: &Self) -> bool {
478 self.as_normalized_slice() == other.as_normalized_slice()
479 }
480}
481
482impl std::hash::Hash for CqlVarint {
484 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
485 self.as_normalized_slice().hash(state)
486 }
487}
488
489impl PartialEq for CqlVarintBorrowed<'_> {
503 fn eq(&self, other: &Self) -> bool {
504 self.as_normalized_slice() == other.as_normalized_slice()
505 }
506}
507
508impl std::hash::Hash for CqlVarintBorrowed<'_> {
510 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
511 self.as_normalized_slice().hash(state)
512 }
513}
514
515#[cfg(feature = "num-bigint-03")]
516impl From<num_bigint_03::BigInt> for CqlVarint {
517 fn from(value: num_bigint_03::BigInt) -> Self {
518 Self(value.to_signed_bytes_be())
519 }
520}
521
522#[cfg(feature = "num-bigint-03")]
523impl From<CqlVarint> for num_bigint_03::BigInt {
524 fn from(val: CqlVarint) -> Self {
525 num_bigint_03::BigInt::from_signed_bytes_be(&val.0)
526 }
527}
528
529#[cfg(feature = "num-bigint-03")]
530impl From<CqlVarintBorrowed<'_>> for num_bigint_03::BigInt {
531 fn from(val: CqlVarintBorrowed<'_>) -> Self {
532 num_bigint_03::BigInt::from_signed_bytes_be(val.0)
533 }
534}
535
536#[cfg(feature = "num-bigint-04")]
537impl From<num_bigint_04::BigInt> for CqlVarint {
538 fn from(value: num_bigint_04::BigInt) -> Self {
539 Self(value.to_signed_bytes_be())
540 }
541}
542
543#[cfg(feature = "num-bigint-04")]
544impl From<CqlVarint> for num_bigint_04::BigInt {
545 fn from(val: CqlVarint) -> Self {
546 num_bigint_04::BigInt::from_signed_bytes_be(&val.0)
547 }
548}
549
550#[cfg(feature = "num-bigint-04")]
551impl From<CqlVarintBorrowed<'_>> for num_bigint_04::BigInt {
552 fn from(val: CqlVarintBorrowed<'_>) -> Self {
553 num_bigint_04::BigInt::from_signed_bytes_be(val.0)
554 }
555}
556
557#[derive(Clone, PartialEq, Eq, Debug)]
577pub struct CqlDecimal {
578 int_val: CqlVarint,
579 scale: i32,
580}
581
582#[derive(Clone, PartialEq, Eq, Debug)]
591pub struct CqlDecimalBorrowed<'b> {
592 int_val: CqlVarintBorrowed<'b>,
593 scale: i32,
594}
595
596impl CqlDecimal {
598 pub fn from_signed_be_bytes_and_exponent(bytes: Vec<u8>, scale: i32) -> Self {
603 Self {
604 int_val: CqlVarint::from_signed_bytes_be(bytes),
605 scale,
606 }
607 }
608
609 pub fn from_signed_be_bytes_slice_and_exponent(bytes: &[u8], scale: i32) -> Self {
614 Self::from_signed_be_bytes_and_exponent(bytes.to_vec(), scale)
615 }
616}
617
618impl<'b> CqlDecimalBorrowed<'b> {
620 pub fn from_signed_be_bytes_slice_and_exponent(bytes: &'b [u8], scale: i32) -> Self {
625 Self {
626 int_val: CqlVarintBorrowed::from_signed_bytes_be_slice(bytes),
627 scale,
628 }
629 }
630}
631
632impl CqlDecimal {
634 pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
637 (self.int_val.as_signed_bytes_be_slice(), self.scale)
638 }
639
640 pub fn into_signed_be_bytes_and_exponent(self) -> (Vec<u8>, i32) {
643 (self.int_val.into_signed_bytes_be(), self.scale)
644 }
645}
646
647impl CqlDecimalBorrowed<'_> {
649 pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
652 (self.int_val.as_signed_bytes_be_slice(), self.scale)
653 }
654}
655
656#[cfg(feature = "bigdecimal-04")]
657impl From<CqlDecimal> for bigdecimal_04::BigDecimal {
658 fn from(value: CqlDecimal) -> Self {
659 Self::from((
660 bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(
661 value.int_val.as_signed_bytes_be_slice(),
662 ),
663 value.scale as i64,
664 ))
665 }
666}
667
668#[cfg(feature = "bigdecimal-04")]
669impl From<CqlDecimalBorrowed<'_>> for bigdecimal_04::BigDecimal {
670 fn from(value: CqlDecimalBorrowed) -> Self {
671 Self::from((
672 bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(
673 value.int_val.as_signed_bytes_be_slice(),
674 ),
675 value.scale as i64,
676 ))
677 }
678}
679
680#[cfg(feature = "bigdecimal-04")]
681impl TryFrom<bigdecimal_04::BigDecimal> for CqlDecimal {
682 type Error = <i64 as TryInto<i32>>::Error;
683
684 fn try_from(value: bigdecimal_04::BigDecimal) -> Result<Self, Self::Error> {
685 let (bigint, scale) = value.into_bigint_and_exponent();
686 let bytes = bigint.to_signed_bytes_be();
687 Ok(Self::from_signed_be_bytes_and_exponent(
688 bytes,
689 scale.try_into()?,
690 ))
691 }
692}
693
694#[derive(Clone, Copy, PartialEq, Eq, Debug)]
698pub struct CqlDate(pub u32);
699
700#[derive(Clone, Copy, PartialEq, Eq, Debug)]
704pub struct CqlTimestamp(pub i64);
705
706#[derive(Clone, Copy, PartialEq, Eq, Debug)]
710pub struct CqlTime(pub i64);
711
712impl CqlDate {
713 fn try_to_chrono_04_naive_date(&self) -> Result<chrono_04::NaiveDate, ValueOverflow> {
714 let days_since_unix_epoch = self.0 as i64 - (1 << 31);
715
716 let duration_since_unix_epoch =
719 chrono_04::Duration::try_days(days_since_unix_epoch).unwrap();
720
721 chrono_04::NaiveDate::from_yo_opt(1970, 1)
722 .unwrap()
723 .checked_add_signed(duration_since_unix_epoch)
724 .ok_or(ValueOverflow)
725 }
726}
727
728#[cfg(feature = "chrono-04")]
729impl From<chrono_04::NaiveDate> for CqlDate {
730 fn from(value: chrono_04::NaiveDate) -> Self {
731 let unix_epoch = chrono_04::NaiveDate::from_yo_opt(1970, 1).unwrap();
732
733 let days = ((1 << 31) + value.signed_duration_since(unix_epoch).num_days()) as u32;
736
737 Self(days)
738 }
739}
740
741#[cfg(feature = "chrono-04")]
742impl TryInto<chrono_04::NaiveDate> for CqlDate {
743 type Error = ValueOverflow;
744
745 fn try_into(self) -> Result<chrono_04::NaiveDate, Self::Error> {
746 self.try_to_chrono_04_naive_date()
747 }
748}
749
750impl CqlTimestamp {
751 fn try_to_chrono_04_datetime_utc(
752 &self,
753 ) -> Result<chrono_04::DateTime<chrono_04::Utc>, ValueOverflow> {
754 use chrono_04::TimeZone;
755 match chrono_04::Utc.timestamp_millis_opt(self.0) {
756 chrono_04::LocalResult::Single(datetime) => Ok(datetime),
757 _ => Err(ValueOverflow),
758 }
759 }
760}
761
762#[cfg(feature = "chrono-04")]
763impl From<chrono_04::DateTime<chrono_04::Utc>> for CqlTimestamp {
764 fn from(value: chrono_04::DateTime<chrono_04::Utc>) -> Self {
765 Self(value.timestamp_millis())
766 }
767}
768
769#[cfg(feature = "chrono-04")]
770impl TryInto<chrono_04::DateTime<chrono_04::Utc>> for CqlTimestamp {
771 type Error = ValueOverflow;
772
773 fn try_into(self) -> Result<chrono_04::DateTime<chrono_04::Utc>, Self::Error> {
774 self.try_to_chrono_04_datetime_utc()
775 }
776}
777
778#[cfg(feature = "chrono-04")]
779impl TryFrom<chrono_04::NaiveTime> for CqlTime {
780 type Error = ValueOverflow;
781
782 fn try_from(value: chrono_04::NaiveTime) -> Result<Self, Self::Error> {
783 let nanos = value
784 .signed_duration_since(chrono_04::NaiveTime::MIN)
785 .num_nanoseconds()
786 .unwrap();
787
788 if nanos <= 86399999999999 {
790 Ok(Self(nanos))
791 } else {
792 Err(ValueOverflow)
793 }
794 }
795}
796
797#[cfg(feature = "chrono-04")]
798impl TryInto<chrono_04::NaiveTime> for CqlTime {
799 type Error = ValueOverflow;
800
801 fn try_into(self) -> Result<chrono_04::NaiveTime, Self::Error> {
802 let secs = (self.0 / 1_000_000_000)
803 .try_into()
804 .map_err(|_| ValueOverflow)?;
805 let nanos = (self.0 % 1_000_000_000)
806 .try_into()
807 .map_err(|_| ValueOverflow)?;
808 chrono_04::NaiveTime::from_num_seconds_from_midnight_opt(secs, nanos).ok_or(ValueOverflow)
809 }
810}
811
812#[cfg(feature = "time-03")]
813impl From<time_03::Date> for CqlDate {
814 fn from(value: time_03::Date) -> Self {
815 const JULIAN_DAY_OFFSET: i64 =
816 (1 << 31) - time_03::OffsetDateTime::UNIX_EPOCH.date().to_julian_day() as i64;
817
818 const _: () = assert!(
820 time_03::Date::MAX.to_julian_day() as i64 + JULIAN_DAY_OFFSET < u32::MAX as i64
821 );
822 const _: () = assert!(
823 time_03::Date::MIN.to_julian_day() as i64 + JULIAN_DAY_OFFSET > u32::MIN as i64
824 );
825
826 let days = value.to_julian_day() as i64 + JULIAN_DAY_OFFSET;
827
828 Self(days as u32)
829 }
830}
831
832#[cfg(feature = "time-03")]
833impl TryInto<time_03::Date> for CqlDate {
834 type Error = ValueOverflow;
835
836 fn try_into(self) -> Result<time_03::Date, Self::Error> {
837 const JULIAN_DAY_OFFSET: i64 =
838 (1 << 31) - time_03::OffsetDateTime::UNIX_EPOCH.date().to_julian_day() as i64;
839
840 let julian_days = (self.0 as i64 - JULIAN_DAY_OFFSET)
841 .try_into()
842 .map_err(|_| ValueOverflow)?;
843
844 time_03::Date::from_julian_day(julian_days).map_err(|_| ValueOverflow)
845 }
846}
847
848#[cfg(feature = "time-03")]
849impl From<time_03::OffsetDateTime> for CqlTimestamp {
850 fn from(value: time_03::OffsetDateTime) -> Self {
851 const _: () = assert!(
854 time_03::PrimitiveDateTime::MAX
855 .assume_utc()
856 .unix_timestamp_nanos()
857 / 1_000_000
859 < i64::MAX as i128
860 );
861 const _: () = assert!(
862 time_03::PrimitiveDateTime::MIN
863 .assume_utc()
864 .unix_timestamp_nanos()
865 / 1_000_000
866 > i64::MIN as i128
867 );
868
869 Self(value.unix_timestamp() * 1000 + value.millisecond() as i64)
871 }
872}
873
874#[cfg(feature = "time-03")]
875impl TryInto<time_03::OffsetDateTime> for CqlTimestamp {
876 type Error = ValueOverflow;
877
878 fn try_into(self) -> Result<time_03::OffsetDateTime, Self::Error> {
879 time_03::OffsetDateTime::from_unix_timestamp_nanos(self.0 as i128 * 1_000_000)
880 .map_err(|_| ValueOverflow)
881 }
882}
883
884#[cfg(feature = "time-03")]
885impl From<time_03::Time> for CqlTime {
886 fn from(value: time_03::Time) -> Self {
887 let (h, m, s, n) = value.as_hms_nano();
888
889 let nanos = (h as i64 * 3600 + m as i64 * 60 + s as i64) * 1_000_000_000 + n as i64;
891
892 Self(nanos)
893 }
894}
895
896#[cfg(feature = "time-03")]
897impl TryInto<time_03::Time> for CqlTime {
898 type Error = ValueOverflow;
899
900 fn try_into(self) -> Result<time_03::Time, Self::Error> {
901 let h = self.0 / 3_600_000_000_000;
902 let m = self.0 / 60_000_000_000 % 60;
903 let s = self.0 / 1_000_000_000 % 60;
904 let n = self.0 % 1_000_000_000;
905
906 time_03::Time::from_hms_nano(
907 h.try_into().map_err(|_| ValueOverflow)?,
908 m as u8,
909 s as u8,
910 n as u32,
911 )
912 .map_err(|_| ValueOverflow)
913 }
914}
915
916#[derive(Clone, Debug, Copy, PartialEq, Eq)]
918pub struct CqlDuration {
919 pub months: i32,
921 pub days: i32,
923 pub nanoseconds: i64,
925}
926
927#[derive(Clone, Debug, PartialEq)]
933#[non_exhaustive]
934pub enum CqlValue {
935 Ascii(String),
937 Boolean(bool),
939 Blob(Vec<u8>),
941 Counter(Counter),
943 Decimal(CqlDecimal),
945 Date(CqlDate),
948 Double(f64),
950 Duration(CqlDuration),
952 Empty,
954 Float(f32),
956 Int(i32),
958 BigInt(i64),
960 Text(String),
962 Timestamp(CqlTimestamp),
964 Inet(IpAddr),
966 List(Vec<CqlValue>),
968 Map(Vec<(CqlValue, CqlValue)>),
971 Set(Vec<CqlValue>),
973 UserDefinedType {
977 keyspace: String,
979 name: String,
981 fields: Vec<(String, Option<CqlValue>)>,
983 },
984 SmallInt(i16),
986 TinyInt(i8),
988 Time(CqlTime),
990 Timeuuid(CqlTimeuuid),
992 Tuple(Vec<Option<CqlValue>>),
995 Uuid(Uuid),
997 Varint(CqlVarint),
999 Vector(Vec<CqlValue>),
1002}
1003
1004impl CqlValue {
1005 pub fn as_ascii(&self) -> Option<&String> {
1007 match self {
1008 Self::Ascii(s) => Some(s),
1009 _ => None,
1010 }
1011 }
1012
1013 pub fn as_cql_date(&self) -> Option<CqlDate> {
1015 match self {
1016 Self::Date(d) => Some(*d),
1017 _ => None,
1018 }
1019 }
1020
1021 pub fn as_cql_timestamp(&self) -> Option<CqlTimestamp> {
1023 match self {
1024 Self::Timestamp(i) => Some(*i),
1025 _ => None,
1026 }
1027 }
1028
1029 pub fn as_cql_time(&self) -> Option<CqlTime> {
1031 match self {
1032 Self::Time(i) => Some(*i),
1033 _ => None,
1034 }
1035 }
1036
1037 pub fn as_cql_duration(&self) -> Option<CqlDuration> {
1039 match self {
1040 Self::Duration(i) => Some(*i),
1041 _ => None,
1042 }
1043 }
1044
1045 pub fn as_counter(&self) -> Option<Counter> {
1047 match self {
1048 Self::Counter(i) => Some(*i),
1049 _ => None,
1050 }
1051 }
1052
1053 pub fn as_boolean(&self) -> Option<bool> {
1055 match self {
1056 Self::Boolean(i) => Some(*i),
1057 _ => None,
1058 }
1059 }
1060
1061 pub fn as_double(&self) -> Option<f64> {
1063 match self {
1064 Self::Double(d) => Some(*d),
1065 _ => None,
1066 }
1067 }
1068
1069 pub fn as_uuid(&self) -> Option<Uuid> {
1071 match self {
1072 Self::Uuid(u) => Some(*u),
1073 _ => None,
1074 }
1075 }
1076
1077 pub fn as_float(&self) -> Option<f32> {
1079 match self {
1080 Self::Float(f) => Some(*f),
1081 _ => None,
1082 }
1083 }
1084
1085 pub fn as_int(&self) -> Option<i32> {
1087 match self {
1088 Self::Int(i) => Some(*i),
1089 _ => None,
1090 }
1091 }
1092
1093 pub fn as_bigint(&self) -> Option<i64> {
1095 match self {
1096 Self::BigInt(i) => Some(*i),
1097 _ => None,
1098 }
1099 }
1100
1101 pub fn as_tinyint(&self) -> Option<i8> {
1103 match self {
1104 Self::TinyInt(i) => Some(*i),
1105 _ => None,
1106 }
1107 }
1108
1109 pub fn as_smallint(&self) -> Option<i16> {
1111 match self {
1112 Self::SmallInt(i) => Some(*i),
1113 _ => None,
1114 }
1115 }
1116
1117 pub fn as_blob(&self) -> Option<&Vec<u8>> {
1119 match self {
1120 Self::Blob(v) => Some(v),
1121 _ => None,
1122 }
1123 }
1124
1125 pub fn as_text(&self) -> Option<&String> {
1127 match self {
1128 Self::Text(s) => Some(s),
1129 _ => None,
1130 }
1131 }
1132
1133 pub fn as_timeuuid(&self) -> Option<CqlTimeuuid> {
1135 match self {
1136 Self::Timeuuid(u) => Some(*u),
1137 _ => None,
1138 }
1139 }
1140
1141 pub fn into_string(self) -> Option<String> {
1143 match self {
1144 Self::Ascii(s) => Some(s),
1145 Self::Text(s) => Some(s),
1146 _ => None,
1147 }
1148 }
1149
1150 pub fn into_blob(self) -> Option<Vec<u8>> {
1152 match self {
1153 Self::Blob(b) => Some(b),
1154 _ => None,
1155 }
1156 }
1157
1158 pub fn as_inet(&self) -> Option<IpAddr> {
1160 match self {
1161 Self::Inet(a) => Some(*a),
1162 _ => None,
1163 }
1164 }
1165
1166 pub fn as_list(&self) -> Option<&Vec<CqlValue>> {
1168 match self {
1169 Self::List(s) => Some(s),
1170 _ => None,
1171 }
1172 }
1173
1174 pub fn as_set(&self) -> Option<&Vec<CqlValue>> {
1176 match self {
1177 Self::Set(s) => Some(s),
1178 _ => None,
1179 }
1180 }
1181
1182 pub fn as_vector(&self) -> Option<&Vec<CqlValue>> {
1184 match self {
1185 Self::Vector(s) => Some(s),
1186 _ => None,
1187 }
1188 }
1189
1190 pub fn as_map(&self) -> Option<&Vec<(CqlValue, CqlValue)>> {
1193 match self {
1194 Self::Map(s) => Some(s),
1195 _ => None,
1196 }
1197 }
1198
1199 pub fn as_udt(&self) -> Option<&Vec<(String, Option<CqlValue>)>> {
1203 match self {
1204 Self::UserDefinedType { fields, .. } => Some(fields),
1205 _ => None,
1206 }
1207 }
1208
1209 pub fn into_vec(self) -> Option<Vec<CqlValue>> {
1211 match self {
1212 Self::List(s) => Some(s),
1213 Self::Set(s) => Some(s),
1214 Self::Vector(s) => Some(s),
1215 _ => None,
1216 }
1217 }
1218
1219 pub fn into_pair_vec(self) -> Option<Vec<(CqlValue, CqlValue)>> {
1222 match self {
1223 Self::Map(s) => Some(s),
1224 _ => None,
1225 }
1226 }
1227
1228 pub fn into_udt_pair_vec(self) -> Option<Vec<(String, Option<CqlValue>)>> {
1231 match self {
1232 Self::UserDefinedType { fields, .. } => Some(fields),
1233 _ => None,
1234 }
1235 }
1236
1237 pub fn into_cql_varint(self) -> Option<CqlVarint> {
1239 match self {
1240 Self::Varint(i) => Some(i),
1241 _ => None,
1242 }
1243 }
1244
1245 pub fn into_cql_decimal(self) -> Option<CqlDecimal> {
1247 match self {
1248 Self::Decimal(i) => Some(i),
1249 _ => None,
1250 }
1251 }
1252 }
1254
1255impl std::fmt::Display for CqlValue {
1258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1259 use crate::pretty::{
1260 CqlStringLiteralDisplayer, HexBytes, MaybeNullDisplayer, PairDisplayer,
1261 };
1262
1263 match self {
1264 CqlValue::Ascii(a) => write!(f, "{}", CqlStringLiteralDisplayer(a))?,
1266 CqlValue::Text(t) => write!(f, "{}", CqlStringLiteralDisplayer(t))?,
1267 CqlValue::Blob(b) => write!(f, "0x{:x}", HexBytes(b))?,
1268 CqlValue::Empty => write!(f, "0x")?,
1269 CqlValue::Decimal(d) => {
1270 let (bytes, scale) = d.as_signed_be_bytes_slice_and_exponent();
1271 write!(
1272 f,
1273 "blobAsDecimal(0x{:x}{:x})",
1274 HexBytes(&scale.to_be_bytes()),
1275 HexBytes(bytes)
1276 )?
1277 }
1278 CqlValue::Float(fl) => write!(f, "{fl}")?,
1279 CqlValue::Double(d) => write!(f, "{d}")?,
1280 CqlValue::Boolean(b) => write!(f, "{b}")?,
1281 CqlValue::Int(i) => write!(f, "{i}")?,
1282 CqlValue::BigInt(bi) => write!(f, "{bi}")?,
1283 CqlValue::Inet(i) => write!(f, "'{i}'")?,
1284 CqlValue::SmallInt(si) => write!(f, "{si}")?,
1285 CqlValue::TinyInt(ti) => write!(f, "{ti}")?,
1286 CqlValue::Varint(vi) => write!(
1287 f,
1288 "blobAsVarint(0x{:x})",
1289 HexBytes(vi.as_signed_bytes_be_slice())
1290 )?,
1291 CqlValue::Counter(c) => write!(f, "{}", c.0)?,
1292 CqlValue::Date(d) => {
1293 match d.try_to_chrono_04_naive_date() {
1296 Ok(d) => write!(f, "'{d}'")?,
1297 Err(_) => f.write_str("<date out of representable range>")?,
1298 }
1299 }
1300 CqlValue::Duration(d) => write!(f, "{}mo{}d{}ns", d.months, d.days, d.nanoseconds)?,
1301 CqlValue::Time(CqlTime(t)) => {
1302 write!(
1303 f,
1304 "'{:02}:{:02}:{:02}.{:09}'",
1305 t / 3_600_000_000_000,
1306 t / 60_000_000_000 % 60,
1307 t / 1_000_000_000 % 60,
1308 t % 1_000_000_000,
1309 )?;
1310 }
1311 CqlValue::Timestamp(ts) => match ts.try_to_chrono_04_datetime_utc() {
1312 Ok(d) => write!(f, "{}", d.format("'%Y-%m-%d %H:%M:%S%.3f%z'"))?,
1313 Err(_) => f.write_str("<timestamp out of representable range>")?,
1314 },
1315 CqlValue::Timeuuid(t) => write!(f, "{t}")?,
1316 CqlValue::Uuid(u) => write!(f, "{u}")?,
1317
1318 CqlValue::Tuple(t) => {
1320 f.write_str("(")?;
1321 t.iter()
1322 .map(|x| MaybeNullDisplayer(x.as_ref()))
1323 .safe_format(",")
1324 .fmt(f)?;
1325 f.write_str(")")?;
1326 }
1327 CqlValue::List(v) | CqlValue::Vector(v) => {
1328 f.write_str("[")?;
1329 v.iter().safe_format(",").fmt(f)?;
1330 f.write_str("]")?;
1331 }
1332 CqlValue::Set(v) => {
1333 f.write_str("{")?;
1334 v.iter().safe_format(",").fmt(f)?;
1335 f.write_str("}")?;
1336 }
1337 CqlValue::Map(m) => {
1338 f.write_str("{")?;
1339 m.iter()
1340 .map(|(k, v)| PairDisplayer(k, v))
1341 .safe_format(",")
1342 .fmt(f)?;
1343 f.write_str("}")?;
1344 }
1345 CqlValue::UserDefinedType {
1346 keyspace: _,
1347 name: _,
1348 fields,
1349 } => {
1350 f.write_str("{")?;
1351 fields
1352 .iter()
1353 .map(|(k, v)| PairDisplayer(k, MaybeNullDisplayer(v.as_ref())))
1354 .safe_format(",")
1355 .fmt(f)?;
1356 f.write_str("}")?;
1357 }
1358 }
1359 Ok(())
1360 }
1361}
1362
1363#[derive(Debug, Default, PartialEq)]
1374pub struct Row {
1375 pub columns: Vec<Option<CqlValue>>,
1379}
1380
1381#[cfg(test)]
1382mod tests {
1383 use std::str::FromStr as _;
1384
1385 use super::*;
1386
1387 #[test]
1388 fn timeuuid_msb_byte_order() {
1389 let uuid = CqlTimeuuid::from_str("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
1390
1391 assert_eq!(0x0607040500010203, uuid.msb());
1392 }
1393
1394 #[test]
1395 fn timeuuid_msb_clears_version_bits() {
1396 let uuid = CqlTimeuuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
1398
1399 assert_eq!(0x0fffffffffffffff, uuid.msb());
1400 }
1401
1402 #[test]
1403 fn timeuuid_lsb_byte_order() {
1404 let uuid = CqlTimeuuid::from_str("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
1405
1406 assert_eq!(0x08090a0b0c0d0e0f, uuid.lsb());
1407 }
1408
1409 #[test]
1410 fn timeuuid_lsb_modifies_no_bits() {
1411 let uuid = CqlTimeuuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
1412
1413 assert_eq!(0xffffffffffffffff, uuid.lsb());
1414 }
1415
1416 #[test]
1417 fn timeuuid_nil() {
1418 let uuid = CqlTimeuuid::nil();
1419
1420 assert_eq!(0x0000000000000000, uuid.msb());
1421 assert_eq!(0x0000000000000000, uuid.lsb());
1422 }
1423
1424 #[test]
1425 fn test_cql_value_displayer() {
1426 assert_eq!(format!("{}", CqlValue::Boolean(true)), "true");
1427 assert_eq!(format!("{}", CqlValue::Int(123)), "123");
1428 assert_eq!(
1429 format!(
1430 "{}",
1431 CqlValue::Decimal(CqlDecimal::from_signed_be_bytes_and_exponent(
1433 vec![0x01, 0xE2, 0x40],
1434 3
1435 ))
1436 ),
1437 "blobAsDecimal(0x0000000301e240)"
1438 );
1439 assert_eq!(format!("{}", CqlValue::Float(12.75)), "12.75");
1440 assert_eq!(
1441 format!("{}", CqlValue::Text("Ala ma kota".to_owned())),
1442 "'Ala ma kota'"
1443 );
1444 assert_eq!(
1445 format!("{}", CqlValue::Text("Foo's".to_owned())),
1446 "'Foo''s'"
1447 );
1448
1449 assert_eq!(
1451 format!("{}", CqlValue::Date(CqlDate(40 + (1 << 31)))),
1452 "'1970-02-10'"
1453 );
1454 assert_eq!(
1455 format!(
1456 "{}",
1457 CqlValue::Duration(CqlDuration {
1458 months: 1,
1459 days: 2,
1460 nanoseconds: 3,
1461 })
1462 ),
1463 "1mo2d3ns"
1464 );
1465 let t = chrono_04::NaiveTime::from_hms_nano_opt(6, 5, 4, 123)
1466 .unwrap()
1467 .signed_duration_since(chrono_04::NaiveTime::MIN);
1468 let t = t.num_nanoseconds().unwrap();
1469 assert_eq!(
1470 format!("{}", CqlValue::Time(CqlTime(t))),
1471 "'06:05:04.000000123'"
1472 );
1473
1474 let t = chrono_04::NaiveDate::from_ymd_opt(2005, 4, 2)
1475 .unwrap()
1476 .and_time(chrono_04::NaiveTime::from_hms_opt(19, 37, 42).unwrap());
1477 assert_eq!(
1478 format!(
1479 "{}",
1480 CqlValue::Timestamp(CqlTimestamp(
1481 t.signed_duration_since(chrono_04::NaiveDateTime::default())
1482 .num_milliseconds()
1483 ))
1484 ),
1485 "'2005-04-02 19:37:42.000+0000'"
1486 );
1487
1488 let list_or_set = vec![CqlValue::Int(1), CqlValue::Int(3), CqlValue::Int(2)];
1490 assert_eq!(
1491 format!("{}", CqlValue::List(list_or_set.clone())),
1492 "[1,3,2]"
1493 );
1494 assert_eq!(format!("{}", CqlValue::Set(list_or_set.clone())), "{1,3,2}");
1495
1496 let tuple: Vec<_> = list_or_set
1497 .into_iter()
1498 .map(Some)
1499 .chain(std::iter::once(None))
1500 .collect();
1501 assert_eq!(format!("{}", CqlValue::Tuple(tuple)), "(1,3,2,null)");
1502
1503 let map = vec![
1504 (CqlValue::Text("foo".to_owned()), CqlValue::Int(123)),
1505 (CqlValue::Text("bar".to_owned()), CqlValue::Int(321)),
1506 ];
1507 assert_eq!(format!("{}", CqlValue::Map(map)), "{'foo':123,'bar':321}");
1508
1509 let fields = vec![
1510 ("foo".to_owned(), Some(CqlValue::Int(123))),
1511 ("bar".to_owned(), Some(CqlValue::Int(321))),
1512 ];
1513 assert_eq!(
1514 format!(
1515 "{}",
1516 CqlValue::UserDefinedType {
1517 keyspace: "ks".to_owned(),
1518 name: "typ".to_owned(),
1519 fields,
1520 }
1521 ),
1522 "{foo:123,bar:321}"
1523 );
1524 }
1525}