1use std::net::IpAddr;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7use thiserror::Error;
8use uuid::Uuid;
9
10use crate::utils::safe_format::IteratorSafeFormatExt;
11
12#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17#[error(
18 "Conversion between CQL type and another type is not possible because\
19 value of one of them is too large to fit in the other"
20)]
21pub struct ValueOverflow;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
25pub struct Unset;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
29pub struct Counter(pub i64);
30
31#[derive(Debug, Clone, Copy, Default)]
33pub enum MaybeUnset<V> {
34 #[default]
36 Unset,
37 Set(V),
39}
40
41impl<V> MaybeUnset<V> {
42 #[inline]
44 pub fn from_option(opt: Option<V>) -> Self {
45 match opt {
46 Some(v) => Self::Set(v),
47 None => Self::Unset,
48 }
49 }
50}
51
52pub trait Emptiable {}
63
64impl Emptiable for bool {}
67impl Emptiable for i8 {}
68impl Emptiable for i16 {}
69impl Emptiable for i32 {}
70impl Emptiable for i64 {}
71impl Emptiable for f32 {}
72impl Emptiable for f64 {}
73
74impl Emptiable for CqlVarint {}
75impl<'b> Emptiable for CqlVarintBorrowed<'b> {}
76impl Emptiable for CqlDecimal {}
77impl<'b> Emptiable for CqlDecimalBorrowed<'b> {}
78impl Emptiable for CqlDate {}
79impl Emptiable for CqlTime {}
80impl Emptiable for CqlTimestamp {}
81impl Emptiable for CqlTimeuuid {}
82
83impl Emptiable for std::net::IpAddr {}
84impl Emptiable for uuid::Uuid {}
85
86#[cfg(feature = "num-bigint-03")]
87impl Emptiable for num_bigint_03::BigInt {}
88#[cfg(feature = "num-bigint-04")]
89impl Emptiable for num_bigint_04::BigInt {}
90#[cfg(feature = "bigdecimal-04")]
91impl Emptiable for bigdecimal_04::BigDecimal {}
92
93#[cfg(feature = "chrono-04")]
94impl Emptiable for chrono_04::NaiveDate {}
95#[cfg(feature = "chrono-04")]
96impl Emptiable for chrono_04::NaiveTime {}
97#[cfg(feature = "chrono-04")]
98impl Emptiable for chrono_04::DateTime<chrono_04::Utc> {}
99
100#[cfg(feature = "time-03")]
101impl Emptiable for time_03::Date {}
102#[cfg(feature = "time-03")]
103impl Emptiable for time_03::Time {}
104#[cfg(feature = "time-03")]
105impl Emptiable for time_03::OffsetDateTime {}
106
107#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
116pub enum MaybeEmpty<T: Emptiable> {
117 Empty,
119 Value(T),
121}
122
123#[derive(Debug, Clone, Copy, Eq)]
128pub struct CqlTimeuuid(Uuid);
129
130impl CqlTimeuuid {
132 pub fn nil() -> Self {
135 Self(Uuid::nil())
136 }
137
138 pub fn as_bytes(&self) -> &[u8; 16] {
141 self.0.as_bytes()
142 }
143
144 pub fn as_u128(&self) -> u128 {
147 self.0.as_u128()
148 }
149
150 pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) {
153 self.0.as_fields()
154 }
155
156 pub fn as_u64_pair(&self) -> (u64, u64) {
159 self.0.as_u64_pair()
160 }
161
162 pub fn from_slice(b: &[u8]) -> Result<Self, uuid::Error> {
165 Ok(Self(Uuid::from_slice(b)?))
166 }
167
168 pub fn from_slice_le(b: &[u8]) -> Result<Self, uuid::Error> {
171 Ok(Self(Uuid::from_slice_le(b)?))
172 }
173
174 pub fn from_bytes(bytes: [u8; 16]) -> Self {
177 Self(Uuid::from_bytes(bytes))
178 }
179
180 pub fn from_bytes_le(bytes: [u8; 16]) -> Self {
183 Self(Uuid::from_bytes_le(bytes))
184 }
185
186 pub fn from_fields(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self {
189 Self(Uuid::from_fields(d1, d2, d3, d4))
190 }
191
192 pub fn from_fields_le(d1: u32, d2: u16, d3: u16, d4: &[u8; 8]) -> Self {
195 Self(Uuid::from_fields_le(d1, d2, d3, d4))
196 }
197
198 pub fn from_u128(v: u128) -> Self {
201 Self(Uuid::from_u128(v))
202 }
203
204 pub fn from_u128_le(v: u128) -> Self {
207 Self(Uuid::from_u128_le(v))
208 }
209
210 pub fn from_u64_pair(high_bits: u64, low_bits: u64) -> Self {
213 Self(Uuid::from_u64_pair(high_bits, low_bits))
214 }
215}
216
217impl CqlTimeuuid {
218 fn msb(&self) -> u64 {
220 let bytes = self.0.as_bytes();
224 u64::from_be_bytes([
225 bytes[6] & 0x0f,
226 bytes[7],
227 bytes[4],
228 bytes[5],
229 bytes[0],
230 bytes[1],
231 bytes[2],
232 bytes[3],
233 ])
234 }
235
236 fn lsb(&self) -> u64 {
237 let bytes = self.0.as_bytes();
238 u64::from_be_bytes([
239 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
240 ])
241 }
242
243 fn lsb_signed(&self) -> u64 {
255 self.lsb() ^ 0x8080808080808080
256 }
257}
258
259impl std::str::FromStr for CqlTimeuuid {
260 type Err = uuid::Error;
261
262 fn from_str(s: &str) -> Result<Self, Self::Err> {
263 Ok(Self(Uuid::from_str(s)?))
264 }
265}
266
267impl std::fmt::Display for CqlTimeuuid {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 write!(f, "{}", self.0)
270 }
271}
272
273impl AsRef<Uuid> for CqlTimeuuid {
274 fn as_ref(&self) -> &Uuid {
275 &self.0
276 }
277}
278
279impl From<CqlTimeuuid> for Uuid {
280 fn from(value: CqlTimeuuid) -> Self {
281 value.0
282 }
283}
284
285impl From<Uuid> for CqlTimeuuid {
286 fn from(value: Uuid) -> Self {
287 Self(value)
288 }
289}
290
291impl Ord for CqlTimeuuid {
299 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
300 let mut res = self.msb().cmp(&other.msb());
301 if let std::cmp::Ordering::Equal = res {
302 res = self.lsb_signed().cmp(&other.lsb_signed());
303 }
304 res
305 }
306}
307
308impl PartialOrd for CqlTimeuuid {
309 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
310 Some(self.cmp(other))
311 }
312}
313
314impl PartialEq for CqlTimeuuid {
315 fn eq(&self, other: &Self) -> bool {
316 self.cmp(other) == std::cmp::Ordering::Equal
317 }
318}
319
320impl std::hash::Hash for CqlTimeuuid {
321 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
322 self.lsb_signed().hash(state);
323 self.msb().hash(state);
324 }
325}
326
327#[derive(Clone, Eq, Debug)]
355pub struct CqlVarint(Vec<u8>);
356
357#[derive(Clone, Eq, Debug)]
362pub struct CqlVarintBorrowed<'b>(&'b [u8]);
363
364impl CqlVarint {
366 pub fn from_signed_bytes_be(digits: Vec<u8>) -> Self {
371 Self(digits)
372 }
373
374 pub fn from_signed_bytes_be_slice(digits: &[u8]) -> Self {
379 Self::from_signed_bytes_be(digits.to_vec())
380 }
381}
382
383impl<'b> CqlVarintBorrowed<'b> {
385 pub fn from_signed_bytes_be_slice(digits: &'b [u8]) -> Self {
390 Self(digits)
391 }
392}
393
394impl CqlVarint {
396 pub fn into_signed_bytes_be(self) -> Vec<u8> {
399 self.0
400 }
401
402 pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
405 &self.0
406 }
407}
408
409impl CqlVarintBorrowed<'_> {
411 pub fn as_signed_bytes_be_slice(&self) -> &[u8] {
414 self.0
415 }
416}
417
418trait AsVarintSlice {
421 fn as_slice(&self) -> &[u8];
422}
423impl AsVarintSlice for CqlVarint {
424 fn as_slice(&self) -> &[u8] {
425 self.as_signed_bytes_be_slice()
426 }
427}
428impl AsVarintSlice for CqlVarintBorrowed<'_> {
429 fn as_slice(&self) -> &[u8] {
430 self.as_signed_bytes_be_slice()
431 }
432}
433
434trait AsNormalizedVarintSlice {
437 fn as_normalized_slice(&self) -> &[u8];
438}
439impl<V: AsVarintSlice> AsNormalizedVarintSlice for V {
440 fn as_normalized_slice(&self) -> &[u8] {
441 let digits = self.as_slice();
442 if digits.is_empty() {
443 return &[0];
446 }
447
448 let non_zero_position = match digits.iter().position(|b| *b != 0) {
449 Some(pos) => pos,
450 None => {
451 return &[0];
453 }
454 };
455
456 if non_zero_position > 0 {
457 let zeros_to_remove = if digits[non_zero_position] > 0x7f {
460 non_zero_position - 1
463 } else {
464 non_zero_position
466 };
467 return &digits[zeros_to_remove..];
468 }
469
470 digits
472 }
473}
474
475impl PartialEq for CqlVarint {
489 fn eq(&self, other: &Self) -> bool {
490 self.as_normalized_slice() == other.as_normalized_slice()
491 }
492}
493
494impl std::hash::Hash for CqlVarint {
496 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
497 self.as_normalized_slice().hash(state)
498 }
499}
500
501impl PartialEq for CqlVarintBorrowed<'_> {
515 fn eq(&self, other: &Self) -> bool {
516 self.as_normalized_slice() == other.as_normalized_slice()
517 }
518}
519
520impl std::hash::Hash for CqlVarintBorrowed<'_> {
522 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
523 self.as_normalized_slice().hash(state)
524 }
525}
526
527#[cfg(feature = "num-bigint-03")]
528impl From<num_bigint_03::BigInt> for CqlVarint {
529 fn from(value: num_bigint_03::BigInt) -> Self {
530 Self(value.to_signed_bytes_be())
531 }
532}
533
534#[cfg(feature = "num-bigint-03")]
535impl From<CqlVarint> for num_bigint_03::BigInt {
536 fn from(val: CqlVarint) -> Self {
537 num_bigint_03::BigInt::from_signed_bytes_be(&val.0)
538 }
539}
540
541#[cfg(feature = "num-bigint-03")]
542impl From<CqlVarintBorrowed<'_>> for num_bigint_03::BigInt {
543 fn from(val: CqlVarintBorrowed<'_>) -> Self {
544 num_bigint_03::BigInt::from_signed_bytes_be(val.0)
545 }
546}
547
548#[cfg(feature = "num-bigint-04")]
549impl From<num_bigint_04::BigInt> for CqlVarint {
550 fn from(value: num_bigint_04::BigInt) -> Self {
551 Self(value.to_signed_bytes_be())
552 }
553}
554
555#[cfg(feature = "num-bigint-04")]
556impl From<CqlVarint> for num_bigint_04::BigInt {
557 fn from(val: CqlVarint) -> Self {
558 num_bigint_04::BigInt::from_signed_bytes_be(&val.0)
559 }
560}
561
562#[cfg(feature = "num-bigint-04")]
563impl From<CqlVarintBorrowed<'_>> for num_bigint_04::BigInt {
564 fn from(val: CqlVarintBorrowed<'_>) -> Self {
565 num_bigint_04::BigInt::from_signed_bytes_be(val.0)
566 }
567}
568
569#[derive(Clone, PartialEq, Eq, Debug)]
589pub struct CqlDecimal {
590 int_val: CqlVarint,
591 scale: i32,
592}
593
594#[derive(Clone, PartialEq, Eq, Debug)]
603pub struct CqlDecimalBorrowed<'b> {
604 int_val: CqlVarintBorrowed<'b>,
605 scale: i32,
606}
607
608impl CqlDecimal {
610 pub fn from_signed_be_bytes_and_exponent(bytes: Vec<u8>, scale: i32) -> Self {
615 Self {
616 int_val: CqlVarint::from_signed_bytes_be(bytes),
617 scale,
618 }
619 }
620
621 pub fn from_signed_be_bytes_slice_and_exponent(bytes: &[u8], scale: i32) -> Self {
626 Self::from_signed_be_bytes_and_exponent(bytes.to_vec(), scale)
627 }
628}
629
630impl<'b> CqlDecimalBorrowed<'b> {
632 pub fn from_signed_be_bytes_slice_and_exponent(bytes: &'b [u8], scale: i32) -> Self {
637 Self {
638 int_val: CqlVarintBorrowed::from_signed_bytes_be_slice(bytes),
639 scale,
640 }
641 }
642}
643
644impl CqlDecimal {
646 pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
649 (self.int_val.as_signed_bytes_be_slice(), self.scale)
650 }
651
652 pub fn into_signed_be_bytes_and_exponent(self) -> (Vec<u8>, i32) {
655 (self.int_val.into_signed_bytes_be(), self.scale)
656 }
657}
658
659impl CqlDecimalBorrowed<'_> {
661 pub fn as_signed_be_bytes_slice_and_exponent(&self) -> (&[u8], i32) {
664 (self.int_val.as_signed_bytes_be_slice(), self.scale)
665 }
666}
667
668#[cfg(feature = "bigdecimal-04")]
669impl From<CqlDecimal> for bigdecimal_04::BigDecimal {
670 fn from(value: CqlDecimal) -> 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 From<CqlDecimalBorrowed<'_>> for bigdecimal_04::BigDecimal {
682 fn from(value: CqlDecimalBorrowed) -> Self {
683 Self::from((
684 bigdecimal_04::num_bigint::BigInt::from_signed_bytes_be(
685 value.int_val.as_signed_bytes_be_slice(),
686 ),
687 value.scale as i64,
688 ))
689 }
690}
691
692#[cfg(feature = "bigdecimal-04")]
693impl TryFrom<bigdecimal_04::BigDecimal> for CqlDecimal {
694 type Error = <i64 as TryInto<i32>>::Error;
695
696 fn try_from(value: bigdecimal_04::BigDecimal) -> Result<Self, Self::Error> {
697 let (bigint, scale) = value.into_bigint_and_exponent();
698 let bytes = bigint.to_signed_bytes_be();
699 Ok(Self::from_signed_be_bytes_and_exponent(
700 bytes,
701 scale.try_into()?,
702 ))
703 }
704}
705
706#[derive(Clone, Copy, PartialEq, Eq, Debug)]
710pub struct CqlDate(pub u32);
711
712#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
716pub struct CqlTimestamp(pub i64);
717
718#[derive(Clone, Copy, PartialEq, Eq, Debug)]
722pub struct CqlTime(pub i64);
723
724impl CqlDate {
725 fn try_to_chrono_04_naive_date(&self) -> Result<chrono_04::NaiveDate, ValueOverflow> {
726 let days_since_unix_epoch = self.0 as i64 - (1 << 31);
727
728 let duration_since_unix_epoch =
731 chrono_04::Duration::try_days(days_since_unix_epoch).unwrap();
732
733 chrono_04::NaiveDate::from_yo_opt(1970, 1)
734 .unwrap()
735 .checked_add_signed(duration_since_unix_epoch)
736 .ok_or(ValueOverflow)
737 }
738}
739
740#[cfg(feature = "chrono-04")]
741impl From<chrono_04::NaiveDate> for CqlDate {
742 fn from(value: chrono_04::NaiveDate) -> Self {
743 let unix_epoch = chrono_04::NaiveDate::from_yo_opt(1970, 1).unwrap();
744
745 let days = ((1 << 31) + value.signed_duration_since(unix_epoch).num_days()) as u32;
748
749 Self(days)
750 }
751}
752
753#[cfg(feature = "chrono-04")]
754impl TryInto<chrono_04::NaiveDate> for CqlDate {
755 type Error = ValueOverflow;
756
757 fn try_into(self) -> Result<chrono_04::NaiveDate, Self::Error> {
758 self.try_to_chrono_04_naive_date()
759 }
760}
761
762impl CqlTimestamp {
763 pub const MIN: CqlTimestamp = CqlTimestamp(i64::MIN);
765
766 pub const MAX: CqlTimestamp = CqlTimestamp(i64::MAX);
768
769 pub fn now() -> Self {
786 match SystemTime::now().duration_since(UNIX_EPOCH) {
787 Ok(d) => Self(
788 i64::try_from(d.as_millis())
789 .expect("system clock is too far past the Unix epoch to fit in a CqlTimestamp"),
790 ),
791 Err(e) => {
792 let ms = i64::try_from(e.duration().as_millis()).expect(
793 "system clock is too far before the Unix epoch to fit in a CqlTimestamp",
794 );
795 Self(-ms)
798 }
799 }
800 }
801
802 pub fn checked_duration_since(self, earlier: CqlTimestamp) -> Option<std::time::Duration> {
809 if self.0 < earlier.0 {
810 return None;
811 }
812 Some(std::time::Duration::from_millis(self.0.abs_diff(earlier.0)))
816 }
817
818 fn try_to_chrono_04_datetime_utc(
819 &self,
820 ) -> Result<chrono_04::DateTime<chrono_04::Utc>, ValueOverflow> {
821 use chrono_04::TimeZone;
822 match chrono_04::Utc.timestamp_millis_opt(self.0) {
823 chrono_04::LocalResult::Single(datetime) => Ok(datetime),
824 _ => Err(ValueOverflow),
825 }
826 }
827}
828
829impl std::ops::Add<std::time::Duration> for CqlTimestamp {
830 type Output = CqlTimestamp;
831
832 fn add(self, rhs: std::time::Duration) -> CqlTimestamp {
836 let rhs_ms = i128::try_from(rhs.as_millis()).unwrap_or(i128::MAX);
837 let result = i128::from(self.0) + rhs_ms;
838 CqlTimestamp(i64::try_from(result).expect("overflow when adding Duration to CqlTimestamp"))
839 }
840}
841
842impl std::ops::AddAssign<std::time::Duration> for CqlTimestamp {
843 fn add_assign(&mut self, rhs: std::time::Duration) {
847 *self = *self + rhs;
848 }
849}
850
851impl std::ops::Sub<std::time::Duration> for CqlTimestamp {
852 type Output = CqlTimestamp;
853
854 fn sub(self, rhs: std::time::Duration) -> CqlTimestamp {
858 let rhs_ms = i128::try_from(rhs.as_millis()).unwrap_or(i128::MAX);
859 let result = i128::from(self.0) - rhs_ms;
860 CqlTimestamp(
861 i64::try_from(result).expect("overflow when subtracting Duration from CqlTimestamp"),
862 )
863 }
864}
865
866impl std::ops::SubAssign<std::time::Duration> for CqlTimestamp {
867 fn sub_assign(&mut self, rhs: std::time::Duration) {
871 *self = *self - rhs;
872 }
873}
874
875#[cfg(feature = "chrono-04")]
876impl From<chrono_04::DateTime<chrono_04::Utc>> for CqlTimestamp {
877 fn from(value: chrono_04::DateTime<chrono_04::Utc>) -> Self {
878 Self(value.timestamp_millis())
879 }
880}
881
882#[cfg(feature = "chrono-04")]
883impl TryInto<chrono_04::DateTime<chrono_04::Utc>> for CqlTimestamp {
884 type Error = ValueOverflow;
885
886 fn try_into(self) -> Result<chrono_04::DateTime<chrono_04::Utc>, Self::Error> {
887 self.try_to_chrono_04_datetime_utc()
888 }
889}
890
891#[cfg(feature = "chrono-04")]
892impl TryFrom<chrono_04::NaiveTime> for CqlTime {
893 type Error = ValueOverflow;
894
895 fn try_from(value: chrono_04::NaiveTime) -> Result<Self, Self::Error> {
896 let nanos = value
897 .signed_duration_since(chrono_04::NaiveTime::MIN)
898 .num_nanoseconds()
899 .unwrap();
900
901 if nanos <= 86399999999999 {
903 Ok(Self(nanos))
904 } else {
905 Err(ValueOverflow)
906 }
907 }
908}
909
910#[cfg(feature = "chrono-04")]
911impl TryInto<chrono_04::NaiveTime> for CqlTime {
912 type Error = ValueOverflow;
913
914 fn try_into(self) -> Result<chrono_04::NaiveTime, Self::Error> {
915 let secs = (self.0 / 1_000_000_000)
916 .try_into()
917 .map_err(|_| ValueOverflow)?;
918 let nanos = (self.0 % 1_000_000_000)
919 .try_into()
920 .map_err(|_| ValueOverflow)?;
921 chrono_04::NaiveTime::from_num_seconds_from_midnight_opt(secs, nanos).ok_or(ValueOverflow)
922 }
923}
924
925#[cfg(feature = "time-03")]
926impl From<time_03::Date> for CqlDate {
927 fn from(value: time_03::Date) -> Self {
928 const JULIAN_DAY_OFFSET: i64 =
929 (1 << 31) - time_03::OffsetDateTime::UNIX_EPOCH.date().to_julian_day() as i64;
930
931 const _: () = assert!(
933 time_03::Date::MAX.to_julian_day() as i64 + JULIAN_DAY_OFFSET < u32::MAX as i64
934 );
935 const _: () = assert!(
936 time_03::Date::MIN.to_julian_day() as i64 + JULIAN_DAY_OFFSET > u32::MIN as i64
937 );
938
939 let days = value.to_julian_day() as i64 + JULIAN_DAY_OFFSET;
940
941 Self(days as u32)
942 }
943}
944
945#[cfg(feature = "time-03")]
946impl TryInto<time_03::Date> for CqlDate {
947 type Error = ValueOverflow;
948
949 fn try_into(self) -> Result<time_03::Date, Self::Error> {
950 const JULIAN_DAY_OFFSET: i64 =
951 (1 << 31) - time_03::OffsetDateTime::UNIX_EPOCH.date().to_julian_day() as i64;
952
953 let julian_days = (self.0 as i64 - JULIAN_DAY_OFFSET)
954 .try_into()
955 .map_err(|_| ValueOverflow)?;
956
957 time_03::Date::from_julian_day(julian_days).map_err(|_| ValueOverflow)
958 }
959}
960
961#[cfg(feature = "time-03")]
962impl From<time_03::OffsetDateTime> for CqlTimestamp {
963 fn from(value: time_03::OffsetDateTime) -> Self {
964 const _: () = assert!(
967 time_03::PrimitiveDateTime::MAX
968 .assume_utc()
969 .unix_timestamp_nanos()
970 / 1_000_000
972 < i64::MAX as i128
973 );
974 const _: () = assert!(
975 time_03::PrimitiveDateTime::MIN
976 .assume_utc()
977 .unix_timestamp_nanos()
978 / 1_000_000
979 > i64::MIN as i128
980 );
981
982 Self(value.unix_timestamp() * 1000 + value.millisecond() as i64)
984 }
985}
986
987#[cfg(feature = "time-03")]
988impl TryInto<time_03::OffsetDateTime> for CqlTimestamp {
989 type Error = ValueOverflow;
990
991 fn try_into(self) -> Result<time_03::OffsetDateTime, Self::Error> {
992 time_03::OffsetDateTime::from_unix_timestamp_nanos(self.0 as i128 * 1_000_000)
993 .map_err(|_| ValueOverflow)
994 }
995}
996
997#[cfg(feature = "time-03")]
998impl From<time_03::Time> for CqlTime {
999 fn from(value: time_03::Time) -> Self {
1000 let (h, m, s, n) = value.as_hms_nano();
1001
1002 let nanos = (h as i64 * 3600 + m as i64 * 60 + s as i64) * 1_000_000_000 + n as i64;
1004
1005 Self(nanos)
1006 }
1007}
1008
1009#[cfg(feature = "time-03")]
1010impl TryInto<time_03::Time> for CqlTime {
1011 type Error = ValueOverflow;
1012
1013 fn try_into(self) -> Result<time_03::Time, Self::Error> {
1014 let h = self.0 / 3_600_000_000_000;
1015 let m = self.0 / 60_000_000_000 % 60;
1016 let s = self.0 / 1_000_000_000 % 60;
1017 let n = self.0 % 1_000_000_000;
1018
1019 time_03::Time::from_hms_nano(
1020 h.try_into().map_err(|_| ValueOverflow)?,
1021 m as u8,
1022 s as u8,
1023 n as u32,
1024 )
1025 .map_err(|_| ValueOverflow)
1026 }
1027}
1028
1029#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1031pub struct CqlDuration {
1032 pub months: i32,
1034 pub days: i32,
1036 pub nanoseconds: i64,
1038}
1039
1040#[derive(Clone, Debug, PartialEq)]
1046#[non_exhaustive]
1047pub enum CqlValue {
1048 Ascii(String),
1050 Boolean(bool),
1052 Blob(Vec<u8>),
1054 Counter(Counter),
1056 Decimal(CqlDecimal),
1058 Date(CqlDate),
1061 Double(f64),
1063 Duration(CqlDuration),
1065 Empty,
1067 Float(f32),
1069 Int(i32),
1071 BigInt(i64),
1073 Text(String),
1075 Timestamp(CqlTimestamp),
1077 Inet(IpAddr),
1079 List(Vec<CqlValue>),
1081 Map(Vec<(CqlValue, CqlValue)>),
1084 Set(Vec<CqlValue>),
1086 UserDefinedType {
1090 keyspace: String,
1092 name: String,
1094 fields: Vec<(String, Option<CqlValue>)>,
1096 },
1097 SmallInt(i16),
1099 TinyInt(i8),
1101 Time(CqlTime),
1103 Timeuuid(CqlTimeuuid),
1105 Tuple(Vec<Option<CqlValue>>),
1108 Uuid(Uuid),
1110 Varint(CqlVarint),
1112 Vector(Vec<CqlValue>),
1115}
1116
1117impl CqlValue {
1118 pub fn as_ascii(&self) -> Option<&String> {
1120 match self {
1121 Self::Ascii(s) => Some(s),
1122 _ => None,
1123 }
1124 }
1125
1126 pub fn as_cql_date(&self) -> Option<CqlDate> {
1128 match self {
1129 Self::Date(d) => Some(*d),
1130 _ => None,
1131 }
1132 }
1133
1134 pub fn as_cql_timestamp(&self) -> Option<CqlTimestamp> {
1136 match self {
1137 Self::Timestamp(i) => Some(*i),
1138 _ => None,
1139 }
1140 }
1141
1142 pub fn as_cql_time(&self) -> Option<CqlTime> {
1144 match self {
1145 Self::Time(i) => Some(*i),
1146 _ => None,
1147 }
1148 }
1149
1150 pub fn as_cql_duration(&self) -> Option<CqlDuration> {
1152 match self {
1153 Self::Duration(i) => Some(*i),
1154 _ => None,
1155 }
1156 }
1157
1158 pub fn as_counter(&self) -> Option<Counter> {
1160 match self {
1161 Self::Counter(i) => Some(*i),
1162 _ => None,
1163 }
1164 }
1165
1166 pub fn as_boolean(&self) -> Option<bool> {
1168 match self {
1169 Self::Boolean(i) => Some(*i),
1170 _ => None,
1171 }
1172 }
1173
1174 pub fn as_double(&self) -> Option<f64> {
1176 match self {
1177 Self::Double(d) => Some(*d),
1178 _ => None,
1179 }
1180 }
1181
1182 pub fn as_uuid(&self) -> Option<Uuid> {
1184 match self {
1185 Self::Uuid(u) => Some(*u),
1186 _ => None,
1187 }
1188 }
1189
1190 pub fn as_float(&self) -> Option<f32> {
1192 match self {
1193 Self::Float(f) => Some(*f),
1194 _ => None,
1195 }
1196 }
1197
1198 pub fn as_int(&self) -> Option<i32> {
1200 match self {
1201 Self::Int(i) => Some(*i),
1202 _ => None,
1203 }
1204 }
1205
1206 pub fn as_bigint(&self) -> Option<i64> {
1208 match self {
1209 Self::BigInt(i) => Some(*i),
1210 _ => None,
1211 }
1212 }
1213
1214 pub fn as_tinyint(&self) -> Option<i8> {
1216 match self {
1217 Self::TinyInt(i) => Some(*i),
1218 _ => None,
1219 }
1220 }
1221
1222 pub fn as_smallint(&self) -> Option<i16> {
1224 match self {
1225 Self::SmallInt(i) => Some(*i),
1226 _ => None,
1227 }
1228 }
1229
1230 pub fn as_blob(&self) -> Option<&Vec<u8>> {
1232 match self {
1233 Self::Blob(v) => Some(v),
1234 _ => None,
1235 }
1236 }
1237
1238 pub fn as_text(&self) -> Option<&String> {
1240 match self {
1241 Self::Text(s) => Some(s),
1242 _ => None,
1243 }
1244 }
1245
1246 pub fn as_timeuuid(&self) -> Option<CqlTimeuuid> {
1248 match self {
1249 Self::Timeuuid(u) => Some(*u),
1250 _ => None,
1251 }
1252 }
1253
1254 pub fn into_string(self) -> Option<String> {
1256 match self {
1257 Self::Ascii(s) => Some(s),
1258 Self::Text(s) => Some(s),
1259 _ => None,
1260 }
1261 }
1262
1263 pub fn into_blob(self) -> Option<Vec<u8>> {
1265 match self {
1266 Self::Blob(b) => Some(b),
1267 _ => None,
1268 }
1269 }
1270
1271 pub fn as_inet(&self) -> Option<IpAddr> {
1273 match self {
1274 Self::Inet(a) => Some(*a),
1275 _ => None,
1276 }
1277 }
1278
1279 pub fn as_list(&self) -> Option<&Vec<CqlValue>> {
1281 match self {
1282 Self::List(s) => Some(s),
1283 _ => None,
1284 }
1285 }
1286
1287 pub fn as_set(&self) -> Option<&Vec<CqlValue>> {
1289 match self {
1290 Self::Set(s) => Some(s),
1291 _ => None,
1292 }
1293 }
1294
1295 pub fn as_vector(&self) -> Option<&Vec<CqlValue>> {
1297 match self {
1298 Self::Vector(s) => Some(s),
1299 _ => None,
1300 }
1301 }
1302
1303 pub fn as_map(&self) -> Option<&Vec<(CqlValue, CqlValue)>> {
1306 match self {
1307 Self::Map(s) => Some(s),
1308 _ => None,
1309 }
1310 }
1311
1312 pub fn as_udt(&self) -> Option<&Vec<(String, Option<CqlValue>)>> {
1316 match self {
1317 Self::UserDefinedType { fields, .. } => Some(fields),
1318 _ => None,
1319 }
1320 }
1321
1322 pub fn into_vec(self) -> Option<Vec<CqlValue>> {
1324 match self {
1325 Self::List(s) => Some(s),
1326 Self::Set(s) => Some(s),
1327 Self::Vector(s) => Some(s),
1328 _ => None,
1329 }
1330 }
1331
1332 pub fn into_pair_vec(self) -> Option<Vec<(CqlValue, CqlValue)>> {
1335 match self {
1336 Self::Map(s) => Some(s),
1337 _ => None,
1338 }
1339 }
1340
1341 pub fn into_udt_pair_vec(self) -> Option<Vec<(String, Option<CqlValue>)>> {
1344 match self {
1345 Self::UserDefinedType { fields, .. } => Some(fields),
1346 _ => None,
1347 }
1348 }
1349
1350 pub fn into_cql_varint(self) -> Option<CqlVarint> {
1352 match self {
1353 Self::Varint(i) => Some(i),
1354 _ => None,
1355 }
1356 }
1357
1358 pub fn into_cql_decimal(self) -> Option<CqlDecimal> {
1360 match self {
1361 Self::Decimal(i) => Some(i),
1362 _ => None,
1363 }
1364 }
1365 }
1367
1368impl std::fmt::Display for CqlValue {
1371 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1372 use crate::pretty::{
1373 CqlStringLiteralDisplayer, HexBytes, MaybeNullDisplayer, PairDisplayer,
1374 };
1375
1376 match self {
1377 CqlValue::Ascii(a) => write!(f, "{}", CqlStringLiteralDisplayer(a))?,
1379 CqlValue::Text(t) => write!(f, "{}", CqlStringLiteralDisplayer(t))?,
1380 CqlValue::Blob(b) => write!(f, "0x{:x}", HexBytes(b))?,
1381 CqlValue::Empty => write!(f, "0x")?,
1382 CqlValue::Decimal(d) => {
1383 let (bytes, scale) = d.as_signed_be_bytes_slice_and_exponent();
1384 write!(
1385 f,
1386 "blobAsDecimal(0x{:x}{:x})",
1387 HexBytes(&scale.to_be_bytes()),
1388 HexBytes(bytes)
1389 )?
1390 }
1391 CqlValue::Float(fl) => write!(f, "{fl}")?,
1392 CqlValue::Double(d) => write!(f, "{d}")?,
1393 CqlValue::Boolean(b) => write!(f, "{b}")?,
1394 CqlValue::Int(i) => write!(f, "{i}")?,
1395 CqlValue::BigInt(bi) => write!(f, "{bi}")?,
1396 CqlValue::Inet(i) => write!(f, "'{i}'")?,
1397 CqlValue::SmallInt(si) => write!(f, "{si}")?,
1398 CqlValue::TinyInt(ti) => write!(f, "{ti}")?,
1399 CqlValue::Varint(vi) => write!(
1400 f,
1401 "blobAsVarint(0x{:x})",
1402 HexBytes(vi.as_signed_bytes_be_slice())
1403 )?,
1404 CqlValue::Counter(c) => write!(f, "{}", c.0)?,
1405 CqlValue::Date(d) => {
1406 match d.try_to_chrono_04_naive_date() {
1409 Ok(d) => write!(f, "'{d}'")?,
1410 Err(_) => f.write_str("<date out of representable range>")?,
1411 }
1412 }
1413 CqlValue::Duration(d) => write!(f, "{}mo{}d{}ns", d.months, d.days, d.nanoseconds)?,
1414 CqlValue::Time(CqlTime(t)) => {
1415 write!(
1416 f,
1417 "'{:02}:{:02}:{:02}.{:09}'",
1418 t / 3_600_000_000_000,
1419 t / 60_000_000_000 % 60,
1420 t / 1_000_000_000 % 60,
1421 t % 1_000_000_000,
1422 )?;
1423 }
1424 CqlValue::Timestamp(ts) => match ts.try_to_chrono_04_datetime_utc() {
1425 Ok(d) => write!(f, "{}", d.format("'%Y-%m-%d %H:%M:%S%.3f%z'"))?,
1426 Err(_) => f.write_str("<timestamp out of representable range>")?,
1427 },
1428 CqlValue::Timeuuid(t) => write!(f, "{t}")?,
1429 CqlValue::Uuid(u) => write!(f, "{u}")?,
1430
1431 CqlValue::Tuple(t) => {
1433 f.write_str("(")?;
1434 t.iter()
1435 .map(|x| MaybeNullDisplayer(x.as_ref()))
1436 .safe_format(",")
1437 .fmt(f)?;
1438 f.write_str(")")?;
1439 }
1440 CqlValue::List(v) | CqlValue::Vector(v) => {
1441 f.write_str("[")?;
1442 v.iter().safe_format(",").fmt(f)?;
1443 f.write_str("]")?;
1444 }
1445 CqlValue::Set(v) => {
1446 f.write_str("{")?;
1447 v.iter().safe_format(",").fmt(f)?;
1448 f.write_str("}")?;
1449 }
1450 CqlValue::Map(m) => {
1451 f.write_str("{")?;
1452 m.iter()
1453 .map(|(k, v)| PairDisplayer(k, v))
1454 .safe_format(",")
1455 .fmt(f)?;
1456 f.write_str("}")?;
1457 }
1458 CqlValue::UserDefinedType {
1459 keyspace: _,
1460 name: _,
1461 fields,
1462 } => {
1463 f.write_str("{")?;
1464 fields
1465 .iter()
1466 .map(|(k, v)| PairDisplayer(k, MaybeNullDisplayer(v.as_ref())))
1467 .safe_format(",")
1468 .fmt(f)?;
1469 f.write_str("}")?;
1470 }
1471 }
1472 Ok(())
1473 }
1474}
1475
1476#[derive(Debug, Default, PartialEq)]
1487pub struct Row {
1488 pub columns: Vec<Option<CqlValue>>,
1492}
1493
1494#[cfg(test)]
1495mod tests {
1496 use std::str::FromStr as _;
1497 use std::time::Duration;
1498
1499 use super::*;
1500
1501 #[test]
1502 fn timeuuid_msb_byte_order() {
1503 let uuid = CqlTimeuuid::from_str("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
1504
1505 assert_eq!(0x0607040500010203, uuid.msb());
1506 }
1507
1508 #[test]
1509 fn timeuuid_msb_clears_version_bits() {
1510 let uuid = CqlTimeuuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
1512
1513 assert_eq!(0x0fffffffffffffff, uuid.msb());
1514 }
1515
1516 #[test]
1517 fn timeuuid_lsb_byte_order() {
1518 let uuid = CqlTimeuuid::from_str("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap();
1519
1520 assert_eq!(0x08090a0b0c0d0e0f, uuid.lsb());
1521 }
1522
1523 #[test]
1524 fn timeuuid_lsb_modifies_no_bits() {
1525 let uuid = CqlTimeuuid::from_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
1526
1527 assert_eq!(0xffffffffffffffff, uuid.lsb());
1528 }
1529
1530 #[test]
1531 fn timeuuid_nil() {
1532 let uuid = CqlTimeuuid::nil();
1533
1534 assert_eq!(0x0000000000000000, uuid.msb());
1535 assert_eq!(0x0000000000000000, uuid.lsb());
1536 }
1537
1538 #[test]
1539 fn test_cql_value_displayer() {
1540 assert_eq!(format!("{}", CqlValue::Boolean(true)), "true");
1541 assert_eq!(format!("{}", CqlValue::Int(123)), "123");
1542 assert_eq!(
1543 format!(
1544 "{}",
1545 CqlValue::Decimal(CqlDecimal::from_signed_be_bytes_and_exponent(
1547 vec![0x01, 0xE2, 0x40],
1548 3
1549 ))
1550 ),
1551 "blobAsDecimal(0x0000000301e240)"
1552 );
1553 assert_eq!(format!("{}", CqlValue::Float(12.75)), "12.75");
1554 assert_eq!(
1555 format!("{}", CqlValue::Text("Ala ma kota".to_owned())),
1556 "'Ala ma kota'"
1557 );
1558 assert_eq!(
1559 format!("{}", CqlValue::Text("Foo's".to_owned())),
1560 "'Foo''s'"
1561 );
1562
1563 assert_eq!(
1565 format!("{}", CqlValue::Date(CqlDate(40 + (1 << 31)))),
1566 "'1970-02-10'"
1567 );
1568 assert_eq!(
1569 format!(
1570 "{}",
1571 CqlValue::Duration(CqlDuration {
1572 months: 1,
1573 days: 2,
1574 nanoseconds: 3,
1575 })
1576 ),
1577 "1mo2d3ns"
1578 );
1579 let t = chrono_04::NaiveTime::from_hms_nano_opt(6, 5, 4, 123)
1580 .unwrap()
1581 .signed_duration_since(chrono_04::NaiveTime::MIN);
1582 let t = t.num_nanoseconds().unwrap();
1583 assert_eq!(
1584 format!("{}", CqlValue::Time(CqlTime(t))),
1585 "'06:05:04.000000123'"
1586 );
1587
1588 let t = chrono_04::NaiveDate::from_ymd_opt(2005, 4, 2)
1589 .unwrap()
1590 .and_time(chrono_04::NaiveTime::from_hms_opt(19, 37, 42).unwrap());
1591 assert_eq!(
1592 format!(
1593 "{}",
1594 CqlValue::Timestamp(CqlTimestamp(
1595 t.signed_duration_since(chrono_04::NaiveDateTime::default())
1596 .num_milliseconds()
1597 ))
1598 ),
1599 "'2005-04-02 19:37:42.000+0000'"
1600 );
1601
1602 let list_or_set = vec![CqlValue::Int(1), CqlValue::Int(3), CqlValue::Int(2)];
1604 assert_eq!(
1605 format!("{}", CqlValue::List(list_or_set.clone())),
1606 "[1,3,2]"
1607 );
1608 assert_eq!(format!("{}", CqlValue::Set(list_or_set.clone())), "{1,3,2}");
1609
1610 let tuple: Vec<_> = list_or_set
1611 .into_iter()
1612 .map(Some)
1613 .chain(std::iter::once(None))
1614 .collect();
1615 assert_eq!(format!("{}", CqlValue::Tuple(tuple)), "(1,3,2,null)");
1616
1617 let map = vec![
1618 (CqlValue::Text("foo".to_owned()), CqlValue::Int(123)),
1619 (CqlValue::Text("bar".to_owned()), CqlValue::Int(321)),
1620 ];
1621 assert_eq!(format!("{}", CqlValue::Map(map)), "{'foo':123,'bar':321}");
1622
1623 let fields = vec![
1624 ("foo".to_owned(), Some(CqlValue::Int(123))),
1625 ("bar".to_owned(), Some(CqlValue::Int(321))),
1626 ];
1627 assert_eq!(
1628 format!(
1629 "{}",
1630 CqlValue::UserDefinedType {
1631 keyspace: "ks".to_owned(),
1632 name: "typ".to_owned(),
1633 fields,
1634 }
1635 ),
1636 "{foo:123,bar:321}"
1637 );
1638 }
1639
1640 #[test]
1641 fn cql_timestamp_sentinels() {
1642 assert_eq!(CqlTimestamp::MIN.0, i64::MIN);
1643 assert_eq!(CqlTimestamp::MAX.0, i64::MAX);
1644 }
1645
1646 #[test]
1647 fn cql_timestamp_add_duration() {
1648 let epoch = CqlTimestamp(0);
1649 assert_eq!(epoch + Duration::from_millis(1_000), CqlTimestamp(1_000));
1650 assert_eq!(epoch + Duration::from_secs(1), CqlTimestamp(1_000));
1651
1652 let t = CqlTimestamp(1_000);
1653 assert_eq!(t + Duration::from_millis(500), CqlTimestamp(1_500));
1654 }
1655
1656 #[test]
1657 #[should_panic]
1658 fn cql_timestamp_add_duration_panics_on_overflow() {
1659 let _ = CqlTimestamp::MAX + Duration::from_millis(1);
1660 }
1661
1662 #[test]
1663 fn cql_timestamp_add_duration_does_not_panic_when_result_fits() {
1664 assert_eq!(
1665 CqlTimestamp::MIN + Duration::from_millis(u64::MAX),
1666 CqlTimestamp::MAX
1667 );
1668 }
1669
1670 #[test]
1671 fn cql_timestamp_sub_duration() {
1672 let t = CqlTimestamp(2_000);
1673 assert_eq!(t - Duration::from_millis(500), CqlTimestamp(1_500));
1674 assert_eq!(t - Duration::from_secs(1), CqlTimestamp(1_000));
1675 assert_eq!(t - Duration::from_millis(2_000), CqlTimestamp(0));
1676 }
1677
1678 #[test]
1679 #[should_panic]
1680 fn cql_timestamp_sub_duration_panics_on_overflow() {
1681 let _ = CqlTimestamp::MIN - Duration::from_millis(1);
1682 }
1683
1684 #[test]
1685 fn cql_timestamp_sub_duration_does_not_panic_when_result_fits() {
1686 assert_eq!(
1687 CqlTimestamp::MAX - Duration::from_millis(u64::MAX),
1688 CqlTimestamp::MIN
1689 );
1690 }
1691
1692 #[test]
1693 fn cql_timestamp_add_assign_and_sub_assign() {
1694 let mut t = CqlTimestamp(1_000);
1695 t += Duration::from_millis(500);
1696 assert_eq!(t, CqlTimestamp(1_500));
1697 t -= Duration::from_millis(1_500);
1698 assert_eq!(t, CqlTimestamp(0));
1699 }
1700
1701 #[test]
1702 fn cql_timestamp_checked_duration_since() {
1703 let later = CqlTimestamp(3_000);
1704 let earlier = CqlTimestamp(1_000);
1705 assert_eq!(
1706 later.checked_duration_since(earlier),
1707 Some(Duration::from_millis(2_000))
1708 );
1709 assert_eq!(
1710 later.checked_duration_since(CqlTimestamp(0)),
1711 Some(Duration::from_millis(3_000))
1712 );
1713 }
1714
1715 #[test]
1716 fn cql_timestamp_checked_duration_since_none_when_earlier_is_later() {
1717 let earlier = CqlTimestamp(1_000);
1718 let later = CqlTimestamp(3_000);
1719 assert_eq!(earlier.checked_duration_since(later), None);
1720 }
1721
1722 #[test]
1723 fn cql_timestamp_checked_duration_since_no_overflow_on_extreme_range() {
1724 let diff = CqlTimestamp::MAX
1725 .checked_duration_since(CqlTimestamp::MIN)
1726 .unwrap();
1727 assert_eq!(diff, Duration::from_millis(u64::MAX));
1730 }
1731}