1use std::cmp::Ordering;
21use std::fmt;
22use std::hash::{Hash, Hasher};
23use std::sync::Arc;
24
25use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc};
26use uuid::Uuid;
27
28use super::error::{Error, Result};
29use super::types::{DataType, ExternalTypeRef, LogicalTypeRef};
30use crate::{CompactArc, SmartString};
31
32const EXTERNAL_VALUE_MARKER: u8 = 0xff;
33const EXTERNAL_VALUE_HEADER_BYTES: usize = 1 + 16 + 4;
34pub const MAX_EXTERNAL_VALUE_BYTES: usize = 16 * 1024 * 1024;
35const NANOS_PER_SECOND: i64 = 1_000_000_000;
36const NANOS_PER_DAY: i64 = 86_400 * NANOS_PER_SECOND;
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct ExternalValueRef<'a> {
41 type_ref: ExternalTypeRef,
42 payload: &'a [u8],
43}
44
45impl<'a> ExternalValueRef<'a> {
46 pub const fn type_ref(self) -> ExternalTypeRef {
47 self.type_ref
48 }
49
50 pub const fn payload(self) -> &'a [u8] {
51 self.payload
52 }
53}
54
55const TIMESTAMP_FORMATS: &[&str] = &[
58 "%Y-%m-%dT%H:%M:%S%.f%:z", "%Y-%m-%dT%H:%M:%S%:z", "%Y-%m-%dT%H:%M:%S%.fZ", "%Y-%m-%dT%H:%M:%SZ", "%Y-%m-%d %H:%M:%S%.f%:z", "%Y-%m-%d %H:%M:%S%:z", "%Y-%m-%d %H:%M:%S%.fZ", "%Y-%m-%d %H:%M:%SZ", "%Y-%m-%dT%H:%M:%S%.f", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S%.f", "%Y-%m-%d %H:%M:%S", "%Y-%m-%d", "%Y/%m/%d %H:%M:%S", "%Y/%m/%d", "%m/%d/%Y", "%d/%m/%Y", ];
76
77const TIME_FORMATS: &[&str] = &[
78 "%H:%M:%S%.f", "%H:%M:%S", "%H:%M", ];
82
83const CIVIL_TIMESTAMP_FORMATS: &[&str] = &[
84 "%Y-%m-%dT%H:%M:%S%.f",
85 "%Y-%m-%dT%H:%M:%S",
86 "%Y-%m-%d %H:%M:%S%.f",
87 "%Y-%m-%d %H:%M:%S",
88 "%Y/%m/%d %H:%M:%S",
89];
90
91#[derive(Debug, Clone)]
113pub enum Value {
114 Null(DataType),
116
117 Integer(i64),
119
120 Float(f64),
122
123 Text(SmartString),
125
126 Boolean(bool),
128
129 Timestamp(DateTime<Utc>),
131
132 Extension(CompactArc<[u8]>),
137}
138
139pub const NULL_VALUE: Value = Value::Null(DataType::Null);
141
142impl Value {
143 #[inline]
149 pub fn null(data_type: DataType) -> Self {
150 Value::Null(data_type)
151 }
152
153 #[inline(always)]
155 pub fn null_unknown() -> Self {
156 Value::Null(DataType::Null)
157 }
158
159 pub fn integer(value: i64) -> Self {
161 Value::Integer(value)
162 }
163
164 pub fn float(value: f64) -> Self {
166 Value::Float(value)
167 }
168
169 pub fn text(value: impl Into<String>) -> Self {
175 Value::Text(SmartString::from_string_shared(value.into()))
176 }
177
178 pub fn text_arc(value: Arc<str>) -> Self {
182 Value::Text(SmartString::from(value))
183 }
184
185 pub fn boolean(value: bool) -> Self {
187 Value::Boolean(value)
188 }
189
190 pub fn timestamp(value: DateTime<Utc>) -> Self {
192 Value::Timestamp(value)
193 }
194
195 pub fn civil_timestamp(value: NaiveDateTime) -> Result<Self> {
197 let nanos = value.and_utc().timestamp_nanos_opt().ok_or_else(|| {
198 Error::invalid_argument("civil timestamp is outside the persisted i64 nanosecond range")
199 })?;
200 Ok(Self::temporal_extension(DataType::CivilTimestamp, nanos))
201 }
202
203 pub fn time(value: NaiveTime) -> Self {
205 let nanos = i64::from(value.num_seconds_from_midnight()) * NANOS_PER_SECOND
206 + i64::from(value.nanosecond());
207 Self::temporal_extension(DataType::Time, nanos)
208 }
209
210 #[doc(hidden)]
212 pub fn from_temporal_nanos(data_type: DataType, nanos: i64) -> Result<Self> {
213 match data_type {
214 DataType::Timestamp => datetime_from_epoch_nanos(nanos)
215 .map(Value::Timestamp)
216 .ok_or_else(|| Error::invalid_argument("TIMESTAMPTZ nanoseconds are out of range")),
217 DataType::CivilTimestamp => {
218 let value = datetime_from_epoch_nanos(nanos)
219 .map(|value| value.naive_utc())
220 .ok_or_else(|| {
221 Error::invalid_argument("TIMESTAMP nanoseconds are out of range")
222 })?;
223 Self::civil_timestamp(value)
224 }
225 DataType::Time if (0..NANOS_PER_DAY).contains(&nanos) => {
226 Ok(Self::temporal_extension(DataType::Time, nanos))
227 }
228 DataType::Time => Err(Error::invalid_argument(
229 "TIME nanoseconds must be inside one civil day",
230 )),
231 _ => Err(Error::invalid_argument(format!(
232 "data type {data_type} is not a temporal i64 type"
233 ))),
234 }
235 }
236
237 fn temporal_extension(data_type: DataType, nanos: i64) -> Self {
238 let mut data = Vec::with_capacity(9);
239 data.push(data_type as u8);
240 data.extend_from_slice(&nanos.to_le_bytes());
241 Value::Extension(CompactArc::from(data))
242 }
243
244 pub fn try_json(value: impl Into<String>) -> Result<Self> {
246 let value = value.into();
247 serde_json::from_str::<serde_json::Value>(&value)
248 .map_err(|error| Error::invalid_argument(format!("invalid JSON value: {error}")))?;
249 Ok(Self::json_unchecked(value))
250 }
251
252 fn json_unchecked(value: impl Into<String>) -> Self {
254 let s_bytes = value.into().into_bytes();
255 let mut bytes = Vec::with_capacity(1 + s_bytes.len());
256 bytes.push(DataType::Json as u8);
257 bytes.extend_from_slice(&s_bytes);
258 Value::Extension(CompactArc::from(bytes))
259 }
260
261 #[inline]
262 #[doc(hidden)]
263 pub fn json(value: impl Into<String>) -> Self {
264 Self::json_unchecked(value)
265 }
266
267 pub fn vector(data: Vec<f32>) -> Self {
269 let mut bytes = Vec::with_capacity(1 + data.len() * 4);
270 bytes.push(DataType::Vector as u8);
271 for f in &data {
272 bytes.extend_from_slice(&f.to_le_bytes());
273 }
274 Value::Extension(CompactArc::from(bytes))
275 }
276
277 pub fn try_vector_from_bytes(raw_f32_bytes: CompactArc<[u8]>) -> Result<Self> {
279 if !raw_f32_bytes
280 .len()
281 .is_multiple_of(std::mem::size_of::<f32>())
282 {
283 return Err(Error::invalid_argument(format!(
284 "VECTOR payload has {} bytes, expected a multiple of 4",
285 raw_f32_bytes.len()
286 )));
287 }
288 Ok(Self::vector_from_bytes_unchecked(raw_f32_bytes))
289 }
290
291 fn vector_from_bytes_unchecked(raw_f32_bytes: CompactArc<[u8]>) -> Self {
292 let mut bytes = Vec::with_capacity(1 + raw_f32_bytes.len());
293 bytes.push(DataType::Vector as u8);
294 bytes.extend_from_slice(&raw_f32_bytes);
295 Value::Extension(CompactArc::from(bytes))
296 }
297
298 pub fn uuid(bytes: [u8; 16]) -> Self {
300 let mut data = Vec::with_capacity(17);
301 data.push(DataType::Uuid as u8);
302 data.extend_from_slice(&bytes);
303 Value::Extension(CompactArc::from(data))
304 }
305
306 pub fn uuid_v7() -> Self {
311 Value::uuid(*Uuid::now_v7().as_bytes())
312 }
313
314 pub fn try_decimal(unscaled: i128, precision: u8, scale: u8) -> Result<Self> {
322 validate_decimal_shape(unscaled, precision, scale)?;
323 Ok(Self::decimal_unchecked(unscaled, precision, scale))
324 }
325
326 fn decimal_unchecked(unscaled: i128, precision: u8, scale: u8) -> Self {
327 let mut data = Vec::with_capacity(19);
328 data.push(DataType::Decimal as u8);
329 data.extend_from_slice(&unscaled.to_le_bytes());
330 data.push(precision);
331 data.push(scale);
332 Value::Extension(CompactArc::from(data))
333 }
334
335 #[inline]
336 #[doc(hidden)]
337 pub fn decimal(unscaled: i128, precision: u8, scale: u8) -> Self {
338 Self::decimal_unchecked(unscaled, precision, scale)
339 }
340
341 pub fn date(days_since_unix_epoch: i32) -> Self {
343 let mut data = Vec::with_capacity(5);
344 data.push(DataType::Date as u8);
345 data.extend_from_slice(&days_since_unix_epoch.to_le_bytes());
346 Value::Extension(CompactArc::from(data))
347 }
348
349 pub fn bytes(bytes: Vec<u8>) -> Self {
351 let mut data = Vec::with_capacity(1 + bytes.len());
352 data.push(DataType::Bytes as u8);
353 data.extend_from_slice(&bytes);
354 Value::Extension(CompactArc::from(data))
355 }
356
357 pub fn try_external(type_ref: ExternalTypeRef, payload: impl AsRef<[u8]>) -> Result<Self> {
363 let payload = payload.as_ref();
364 if payload.len() > MAX_EXTERNAL_VALUE_BYTES {
365 return Err(Error::invalid_argument(format!(
366 "external value payload has {} bytes, limit is {}",
367 payload.len(),
368 MAX_EXTERNAL_VALUE_BYTES
369 )));
370 }
371 let mut data = Vec::with_capacity(EXTERNAL_VALUE_HEADER_BYTES + payload.len());
372 data.push(EXTERNAL_VALUE_MARKER);
373 data.extend_from_slice(&type_ref.type_object_id());
374 data.extend_from_slice(&type_ref.codec_version().to_le_bytes());
375 data.extend_from_slice(payload);
376 Ok(Value::Extension(CompactArc::from(data)))
377 }
378
379 pub fn data_type(&self) -> DataType {
385 match self {
386 Value::Null(dt) => *dt,
387 Value::Integer(_) => DataType::Integer,
388 Value::Float(_) => DataType::Float,
389 Value::Text(_) => DataType::Text,
390 Value::Boolean(_) => DataType::Boolean,
391 Value::Timestamp(_) => DataType::Timestamp,
392 Value::Extension(data) => data
393 .first()
394 .and_then(|&b| DataType::from_u8(b))
395 .unwrap_or(DataType::Null),
396 }
397 }
398
399 pub fn logical_type(&self) -> LogicalTypeRef {
401 self.as_external()
402 .map(|value| LogicalTypeRef::External(value.type_ref()))
403 .unwrap_or_else(|| LogicalTypeRef::Builtin(self.data_type()))
404 }
405
406 #[inline]
411 pub fn is_external(&self) -> bool {
412 matches!(self, Value::Extension(data) if data.first() == Some(&EXTERNAL_VALUE_MARKER))
413 }
414
415 pub fn as_external(&self) -> Option<ExternalValueRef<'_>> {
417 let Value::Extension(data) = self else {
418 return None;
419 };
420 if data.first() != Some(&EXTERNAL_VALUE_MARKER) || data.len() < EXTERNAL_VALUE_HEADER_BYTES
421 {
422 return None;
423 }
424 let type_object_id = data[1..17].try_into().ok()?;
425 let codec_version = u32::from_le_bytes(data[17..21].try_into().ok()?);
426 let type_ref = ExternalTypeRef::new(type_object_id, codec_version).ok()?;
427 Some(ExternalValueRef {
428 type_ref,
429 payload: &data[EXTERNAL_VALUE_HEADER_BYTES..],
430 })
431 }
432
433 pub fn validate_shape(&self) -> Result<()> {
436 let Value::Extension(data) = self else {
437 return Ok(());
438 };
439 if data.first() == Some(&EXTERNAL_VALUE_MARKER) {
440 let external = self.as_external().ok_or_else(|| {
441 Error::invalid_argument("external value has an invalid typed envelope")
442 })?;
443 if external.payload().len() > MAX_EXTERNAL_VALUE_BYTES {
444 return Err(Error::invalid_argument(
445 "external value payload exceeds 16 MiB",
446 ));
447 }
448 return Ok(());
449 }
450 let Some(tag) = data.first().and_then(|tag| DataType::from_u8(*tag)) else {
451 return Err(Error::invalid_argument(
452 "extension value has an unknown or missing tag",
453 ));
454 };
455 Self::validate_extension_payload(tag, &data[1..])
456 }
457
458 #[doc(hidden)]
460 pub fn validate_extension_payload(tag: DataType, payload: &[u8]) -> Result<()> {
461 match tag {
462 DataType::Json => {
463 let json = std::str::from_utf8(payload).map_err(|error| {
464 Error::invalid_argument(format!("invalid JSON UTF-8: {error}"))
465 })?;
466 serde_json::from_str::<serde_json::Value>(json).map_err(|error| {
467 Error::invalid_argument(format!("invalid JSON document: {error}"))
468 })?;
469 }
470 DataType::Vector => {
471 if !payload.len().is_multiple_of(std::mem::size_of::<f32>()) {
472 return Err(Error::invalid_argument(format!(
473 "VECTOR payload has {} bytes, expected a multiple of 4",
474 payload.len()
475 )));
476 }
477 }
478 DataType::Uuid => {
479 if payload.len() != 16 {
480 return Err(Error::invalid_argument(
481 "UUID payload must contain exactly 16 bytes",
482 ));
483 }
484 }
485 DataType::Decimal => {
486 if payload.len() != 18 {
487 return Err(Error::invalid_argument(
488 "DECIMAL payload must contain exactly 18 bytes",
489 ));
490 }
491 let unscaled = i128::from_le_bytes(
492 payload[..16]
493 .try_into()
494 .map_err(|_| Error::invalid_argument("invalid DECIMAL coefficient"))?,
495 );
496 validate_decimal_shape(unscaled, payload[16], payload[17])?;
497 }
498 DataType::Date => {
499 if payload.len() != 4 {
500 return Err(Error::invalid_argument(
501 "DATE payload must contain exactly 4 bytes",
502 ));
503 }
504 }
505 DataType::Bytes => {}
506 DataType::CivilTimestamp => {
507 let nanos = temporal_payload_nanos(payload, "TIMESTAMP")?;
508 if datetime_from_epoch_nanos(nanos).is_none() {
509 return Err(Error::invalid_argument(
510 "TIMESTAMP payload is outside the supported civil range",
511 ));
512 }
513 }
514 DataType::Time => {
515 let nanos = temporal_payload_nanos(payload, "TIME")?;
516 if !(0..NANOS_PER_DAY).contains(&nanos) {
517 return Err(Error::invalid_argument(
518 "TIME payload must be inside one civil day",
519 ));
520 }
521 }
522 _ => {
523 return Err(Error::invalid_argument(format!(
524 "data type {tag} is not a valid extension payload tag"
525 )));
526 }
527 }
528 Ok(())
529 }
530
531 #[inline(always)]
533 pub fn is_null(&self) -> bool {
534 matches!(self, Value::Null(_))
535 }
536
537 pub fn as_int64(&self) -> Option<i64> {
547 match self {
548 Value::Null(_) => None,
549 Value::Integer(v) => Some(*v),
550 Value::Float(v) => checked_float_to_i64(*v),
551 Value::Text(s) => parse_text_to_i64(s),
552 Value::Boolean(b) => Some(if *b { 1 } else { 0 }),
553 Value::Timestamp(t) => t.timestamp_nanos_opt(),
554 Value::Extension(_) => None,
555 }
556 }
557
558 #[doc(hidden)]
565 pub fn exact_integer_identity(&self) -> Option<i64> {
566 match self {
567 Value::Integer(integer) => Some(*integer),
568 Value::Float(float) if float.is_finite() && float.fract() == 0.0 => {
569 let integer = *float as i64;
570 (Value::Integer(integer) == *self).then_some(integer)
571 }
572 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
573 let (unscaled, _, scale) = self.as_decimal_parts()?;
574 DecimalIdentity::from_parts(unscaled, scale).exact_i64()
575 }
576 _ => None,
577 }
578 }
579
580 pub fn as_float64(&self) -> Option<f64> {
582 match self {
583 Value::Null(_) => None,
584 Value::Integer(v) => Some(*v as f64),
585 Value::Float(v) => Some(*v),
586 Value::Text(s) => s.parse::<f64>().ok(),
587 Value::Boolean(b) => Some(if *b { 1.0 } else { 0.0 }),
588 Value::Timestamp(_) | Value::Extension(_) => None,
589 }
590 }
591
592 pub fn as_boolean(&self) -> Option<bool> {
594 match self {
595 Value::Null(_) => None,
596 Value::Integer(v) => Some(*v != 0),
597 Value::Float(v) => Some(*v != 0.0),
598 Value::Text(s) => {
599 let s_ref: &str = s.as_ref();
601 if s_ref.eq_ignore_ascii_case("true")
602 || s_ref.eq_ignore_ascii_case("t")
603 || s_ref.eq_ignore_ascii_case("yes")
604 || s_ref.eq_ignore_ascii_case("y")
605 || s_ref == "1"
606 {
607 Some(true)
608 } else if s_ref.eq_ignore_ascii_case("false")
609 || s_ref.eq_ignore_ascii_case("f")
610 || s_ref.eq_ignore_ascii_case("no")
611 || s_ref.eq_ignore_ascii_case("n")
612 || s_ref == "0"
613 || s_ref.is_empty()
614 {
615 Some(false)
616 } else {
617 s_ref.parse::<f64>().ok().map(|f| f != 0.0)
618 }
619 }
620 Value::Boolean(b) => Some(*b),
621 Value::Timestamp(_) | Value::Extension(_) => None,
622 }
623 }
624
625 pub fn as_string(&self) -> Option<String> {
627 match self {
628 Value::Null(_) => None,
629 Value::Integer(v) => Some(v.to_string()),
630 Value::Float(v) => Some(format_float(*v)),
631 Value::Text(s) => Some(s.to_string()),
632 Value::Boolean(b) => Some(if *b { "true" } else { "false" }.to_string()),
633 Value::Timestamp(t) => Some(t.to_rfc3339()),
634 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
635 Some(std::str::from_utf8(&data[1..]).unwrap_or("").to_string())
637 }
638 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
639 Some(format_vector_bytes(&data[1..]))
640 }
641 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
642 format_uuid_bytes(&data[1..])
643 }
644 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => self
645 .as_decimal_parts()
646 .map(|(unscaled, _, scale)| format_decimal_parts(unscaled, scale)),
647 Value::Extension(data) if data.first() == Some(&(DataType::Date as u8)) => self
648 .as_date_days()
649 .and_then(format_date_days_since_unix_epoch),
650 Value::Extension(data) if data.first() == Some(&(DataType::CivilTimestamp as u8)) => {
651 self.as_civil_timestamp().map(format_civil_timestamp)
652 }
653 Value::Extension(data) if data.first() == Some(&(DataType::Time as u8)) => {
654 self.as_time().map(format_time)
655 }
656 Value::Extension(data) if data.first() == Some(&(DataType::Bytes as u8)) => {
657 Some(format_bytes_hex(&data[1..]))
658 }
659 Value::Extension(data) => {
660 if data.len() > 1 {
662 std::str::from_utf8(&data[1..]).ok().map(|s| s.to_string())
663 } else {
664 None
665 }
666 }
667 }
668 }
669
670 pub fn as_str(&self) -> Option<&str> {
672 match self {
673 Value::Text(s) => Some(s.as_str()),
674 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
675 let json = std::str::from_utf8(&data[1..]).ok()?;
676 serde_json::from_str::<serde_json::Value>(json).ok()?;
677 Some(json)
678 }
679 _ => None,
680 }
681 }
682
683 pub fn as_timestamp(&self) -> Option<DateTime<Utc>> {
685 match self {
686 Value::Null(_) => None,
687 Value::Timestamp(t) => Some(*t),
688 Value::Text(s) => parse_timestamp(s).ok(),
689 Value::Integer(nanos) => {
690 datetime_from_epoch_nanos(*nanos)
692 }
693 _ => None,
694 }
695 }
696
697 #[inline]
703 #[doc(hidden)]
704 pub fn artifact_timestamp_nanos(&self) -> Option<i64> {
705 match self {
706 Value::Timestamp(timestamp) => timestamp.timestamp_nanos_opt(),
707 _ => None,
708 }
709 }
710
711 pub fn as_civil_timestamp(&self) -> Option<NaiveDateTime> {
713 let nanos = self.as_temporal_nanos(DataType::CivilTimestamp)?;
714 datetime_from_epoch_nanos(nanos).map(|value| value.naive_utc())
715 }
716
717 pub fn as_time(&self) -> Option<NaiveTime> {
719 let nanos = self.as_temporal_nanos(DataType::Time)?;
720 let seconds = u32::try_from(nanos / NANOS_PER_SECOND).ok()?;
721 let subsecond = u32::try_from(nanos % NANOS_PER_SECOND).ok()?;
722 NaiveTime::from_num_seconds_from_midnight_opt(seconds, subsecond)
723 }
724
725 #[doc(hidden)]
727 pub fn artifact_temporal_nanos(&self) -> Option<i64> {
728 match self {
729 Value::Timestamp(timestamp) => timestamp.timestamp_nanos_opt(),
730 Value::Extension(data)
731 if matches!(
732 data.first().and_then(|tag| DataType::from_u8(*tag)),
733 Some(DataType::CivilTimestamp | DataType::Time)
734 ) && data.len() == 9 =>
735 {
736 Some(i64::from_le_bytes(data[1..9].try_into().ok()?))
737 }
738 _ => None,
739 }
740 }
741
742 fn as_temporal_nanos(&self, expected: DataType) -> Option<i64> {
743 match self {
744 Value::Extension(data)
745 if data.first() == Some(&(expected as u8)) && data.len() == 9 =>
746 {
747 Some(i64::from_le_bytes(data[1..9].try_into().ok()?))
748 }
749 _ => None,
750 }
751 }
752
753 pub fn as_json(&self) -> Option<&str> {
755 match self {
756 Value::Null(_) => None,
757 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
759 let json = std::str::from_utf8(&data[1..]).ok()?;
760 serde_json::from_str::<serde_json::Value>(json).ok()?;
761 Some(json)
762 }
763 _ => None,
764 }
765 }
766
767 pub fn as_vector_f32(&self) -> Option<Vec<f32>> {
769 match self {
770 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
771 let payload = &data[1..];
772 if payload.len() % std::mem::size_of::<f32>() != 0 {
773 return None;
774 }
775 let len = payload.len() / 4;
776 let mut result = Vec::with_capacity(len);
777 for i in 0..len {
778 let bytes = [
779 payload[i * 4],
780 payload[i * 4 + 1],
781 payload[i * 4 + 2],
782 payload[i * 4 + 3],
783 ];
784 result.push(f32::from_le_bytes(bytes));
785 }
786 Some(result)
787 }
788 _ => None,
789 }
790 }
791
792 pub fn as_uuid_bytes(&self) -> Option<[u8; 16]> {
794 match self {
795 Value::Extension(data)
796 if data.first() == Some(&(DataType::Uuid as u8)) && data.len() == 17 =>
797 {
798 data[1..].try_into().ok()
799 }
800 _ => None,
801 }
802 }
803
804 pub fn as_decimal_parts(&self) -> Option<(i128, u8, u8)> {
806 match self {
807 Value::Extension(data)
808 if data.first() == Some(&(DataType::Decimal as u8)) && data.len() == 19 =>
809 {
810 let unscaled = i128::from_le_bytes(data[1..17].try_into().ok()?);
811 validate_decimal_shape(unscaled, data[17], data[18]).ok()?;
812 Some((unscaled, data[17], data[18]))
813 }
814 _ => None,
815 }
816 }
817
818 pub fn as_date_days(&self) -> Option<i32> {
820 match self {
821 Value::Extension(data)
822 if data.first() == Some(&(DataType::Date as u8)) && data.len() == 5 =>
823 {
824 Some(i32::from_le_bytes(data[1..5].try_into().ok()?))
825 }
826 _ => None,
827 }
828 }
829
830 pub fn as_bytes_value(&self) -> Option<&[u8]> {
832 match self {
833 Value::Extension(data) if data.first() == Some(&(DataType::Bytes as u8)) => {
834 Some(&data[1..])
835 }
836 _ => None,
837 }
838 }
839
840 pub fn compare(&self, other: &Value) -> Result<Ordering> {
852 if self.is_null() || other.is_null() {
854 if self.is_null() && other.is_null() {
855 return Ok(Ordering::Equal);
856 }
857 return Err(Error::NullComparison);
858 }
859
860 if let Some(ordering) = compare_canonical_numeric(self, other) {
864 return Ok(ordering);
865 }
866
867 if self.data_type() == other.data_type() {
869 return self.compare_same_type(other);
870 }
871
872 Err(Error::IncomparableTypes)
874 }
875
876 fn compare_same_type(&self, other: &Value) -> Result<Ordering> {
878 match (self, other) {
879 (Value::Integer(a), Value::Integer(b)) => Ok(a.cmp(b)),
880 (Value::Float(a), Value::Float(b)) => Ok(compare_floats(*a, *b)),
881 (Value::Text(a), Value::Text(b)) => Ok(a.cmp(b)),
882 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
883 (Value::Timestamp(a), Value::Timestamp(b)) => Ok(a.cmp(b)),
884 (Value::Extension(a), Value::Extension(b)) => {
885 if a.first() == Some(&EXTERNAL_VALUE_MARKER)
889 || b.first() == Some(&EXTERNAL_VALUE_MARKER)
890 {
891 return Err(Error::IncomparableTypes);
892 }
893 if a.first() != b.first() {
895 return Err(Error::IncomparableTypes);
896 }
897 if a.first() == Some(&(DataType::Uuid as u8)) {
898 return if a.len() == 17 && b.len() == 17 {
899 Ok(a[1..].cmp(&b[1..]))
900 } else {
901 Err(Error::IncomparableTypes)
902 };
903 }
904 if a.first() == Some(&(DataType::Decimal as u8)) {
905 return match (self.as_decimal_parts(), other.as_decimal_parts()) {
906 (
907 Some((left_unscaled, _, left_scale)),
908 Some((right_unscaled, _, right_scale)),
909 ) => Ok(compare_decimal_parts(
910 left_unscaled,
911 left_scale,
912 right_unscaled,
913 right_scale,
914 )),
915 _ => Err(Error::IncomparableTypes),
916 };
917 }
918 if a.first() == Some(&(DataType::Date as u8)) {
919 return match (self.as_date_days(), other.as_date_days()) {
920 (Some(left), Some(right)) => Ok(left.cmp(&right)),
921 _ => Err(Error::IncomparableTypes),
922 };
923 }
924 if matches!(
925 a.first().and_then(|tag| DataType::from_u8(*tag)),
926 Some(DataType::CivilTimestamp | DataType::Time)
927 ) {
928 return match (
929 self.artifact_temporal_nanos(),
930 other.artifact_temporal_nanos(),
931 ) {
932 (Some(left), Some(right)) => Ok(left.cmp(&right)),
933 _ => Err(Error::IncomparableTypes),
934 };
935 }
936 if a.first() == Some(&(DataType::Bytes as u8)) {
937 return Ok(a[1..].cmp(&b[1..]));
938 }
939 if a == b {
941 Ok(Ordering::Equal)
942 } else {
943 Err(Error::IncomparableTypes)
944 }
945 }
946 _ => Err(Error::IncomparableTypes),
947 }
948 }
949
950 pub fn from_typed(value: Option<&dyn std::any::Any>, data_type: DataType) -> Result<Self> {
956 let has_value = value.is_some();
957 let result = match value {
958 None => Value::Null(data_type),
959 Some(v) => {
960 match data_type {
962 DataType::Integer => {
963 if let Some(&i) = v.downcast_ref::<i64>() {
964 Value::Integer(i)
965 } else if let Some(&i) = v.downcast_ref::<i32>() {
966 Value::Integer(i as i64)
967 } else if let Some(s) = v.downcast_ref::<String>() {
968 s.parse::<i64>()
969 .map(Value::Integer)
970 .unwrap_or(Value::Null(data_type))
971 } else {
972 Value::Null(data_type)
973 }
974 }
975 DataType::Float => {
976 if let Some(&f) = v.downcast_ref::<f64>() {
977 Value::Float(f)
978 } else if let Some(&i) = v.downcast_ref::<i64>() {
979 Value::Float(i as f64)
980 } else if let Some(s) = v.downcast_ref::<String>() {
981 s.parse::<f64>()
982 .map(Value::Float)
983 .unwrap_or(Value::Null(data_type))
984 } else {
985 Value::Null(data_type)
986 }
987 }
988 DataType::Text => {
989 if let Some(s) = v.downcast_ref::<String>() {
990 Value::Text(SmartString::new(s))
991 } else if let Some(&s) = v.downcast_ref::<&str>() {
992 Value::Text(SmartString::from(s))
993 } else {
994 Value::Null(data_type)
995 }
996 }
997 DataType::Boolean => {
998 if let Some(&b) = v.downcast_ref::<bool>() {
999 Value::Boolean(b)
1000 } else if let Some(&i) = v.downcast_ref::<i64>() {
1001 Value::Boolean(i != 0)
1002 } else {
1003 Value::Null(data_type)
1004 }
1005 }
1006 DataType::Timestamp => {
1007 if let Some(&t) = v.downcast_ref::<DateTime<Utc>>() {
1008 Value::Timestamp(t)
1009 } else if let Some(s) = v.downcast_ref::<String>() {
1010 parse_timestamp(s)
1011 .map(Value::Timestamp)
1012 .unwrap_or(Value::Null(data_type))
1013 } else {
1014 Value::Null(data_type)
1015 }
1016 }
1017 DataType::CivilTimestamp => {
1018 if let Some(&value) = v.downcast_ref::<NaiveDateTime>() {
1019 Value::civil_timestamp(value)?
1020 } else if let Some(s) = v.downcast_ref::<String>() {
1021 parse_civil_timestamp(s)
1022 .and_then(Value::civil_timestamp)
1023 .unwrap_or(Value::Null(data_type))
1024 } else if let Some(&s) = v.downcast_ref::<&str>() {
1025 parse_civil_timestamp(s)
1026 .and_then(Value::civil_timestamp)
1027 .unwrap_or(Value::Null(data_type))
1028 } else {
1029 Value::Null(data_type)
1030 }
1031 }
1032 DataType::Time => {
1033 if let Some(&value) = v.downcast_ref::<NaiveTime>() {
1034 Value::time(value)
1035 } else if let Some(s) = v.downcast_ref::<String>() {
1036 parse_time(s)
1037 .map(Value::time)
1038 .unwrap_or(Value::Null(data_type))
1039 } else if let Some(&s) = v.downcast_ref::<&str>() {
1040 parse_time(s)
1041 .map(Value::time)
1042 .unwrap_or(Value::Null(data_type))
1043 } else {
1044 Value::Null(data_type)
1045 }
1046 }
1047 DataType::Json => {
1048 if let Some(s) = v.downcast_ref::<String>() {
1049 if serde_json::from_str::<serde_json::Value>(s).is_ok() {
1051 Value::json_unchecked(s)
1052 } else {
1053 Value::Null(data_type)
1054 }
1055 } else {
1056 Value::Null(data_type)
1057 }
1058 }
1059 DataType::Uuid => {
1060 if let Some(&bytes) = v.downcast_ref::<[u8; 16]>() {
1061 Value::uuid(bytes)
1062 } else if let Some(s) = v.downcast_ref::<String>() {
1063 parse_uuid_str(s)
1064 .map(Value::uuid)
1065 .unwrap_or(Value::Null(data_type))
1066 } else if let Some(&s) = v.downcast_ref::<&str>() {
1067 parse_uuid_str(s)
1068 .map(Value::uuid)
1069 .unwrap_or(Value::Null(data_type))
1070 } else {
1071 Value::Null(data_type)
1072 }
1073 }
1074 DataType::Vector => {
1075 if let Some(vec) = v.downcast_ref::<Vec<f32>>() {
1076 Value::vector(vec.clone())
1077 } else {
1078 Value::Null(data_type)
1079 }
1080 }
1081 DataType::Decimal => {
1082 if let Some(&(unscaled, precision, scale)) =
1083 v.downcast_ref::<(i128, u8, u8)>()
1084 {
1085 Value::decimal_unchecked(unscaled, precision, scale)
1086 } else if let Some(&i) = v.downcast_ref::<i64>() {
1087 Value::decimal_unchecked(
1088 i as i128,
1089 decimal_precision_for_unscaled(i),
1090 0,
1091 )
1092 } else if let Some(s) = v.downcast_ref::<String>() {
1093 parse_decimal_str(s)
1094 .map(|(unscaled, precision, scale)| {
1095 Value::decimal_unchecked(unscaled, precision, scale)
1096 })
1097 .unwrap_or(Value::Null(data_type))
1098 } else if let Some(&s) = v.downcast_ref::<&str>() {
1099 parse_decimal_str(s)
1100 .map(|(unscaled, precision, scale)| {
1101 Value::decimal_unchecked(unscaled, precision, scale)
1102 })
1103 .unwrap_or(Value::Null(data_type))
1104 } else {
1105 Value::Null(data_type)
1106 }
1107 }
1108 DataType::Date => {
1109 if let Some(&days) = v.downcast_ref::<i32>() {
1110 Value::date(days)
1111 } else if let Some(s) = v.downcast_ref::<String>() {
1112 parse_date_days_since_unix_epoch(s)
1113 .map(Value::date)
1114 .unwrap_or(Value::Null(data_type))
1115 } else if let Some(&s) = v.downcast_ref::<&str>() {
1116 parse_date_days_since_unix_epoch(s)
1117 .map(Value::date)
1118 .unwrap_or(Value::Null(data_type))
1119 } else {
1120 Value::Null(data_type)
1121 }
1122 }
1123 DataType::Bytes => {
1124 if let Some(bytes) = v.downcast_ref::<Vec<u8>>() {
1125 Value::bytes(bytes.clone())
1126 } else if let Some(s) = v.downcast_ref::<String>() {
1127 Value::bytes(s.as_bytes().to_vec())
1128 } else if let Some(&s) = v.downcast_ref::<&str>() {
1129 Value::bytes(s.as_bytes().to_vec())
1130 } else {
1131 Value::Null(data_type)
1132 }
1133 }
1134 DataType::Null => Value::Null(DataType::Null),
1135 }
1136 }
1137 };
1138 result.validate_shape()?;
1139 if has_value && result.is_null() && data_type != DataType::Null {
1140 return Err(Error::type_conversion("typed value", data_type.to_string()));
1141 }
1142 Ok(result)
1143 }
1144
1145 pub fn coerce_to_type(&self, target_type: DataType) -> Value {
1161 if self.is_null() {
1163 return Value::Null(target_type);
1164 }
1165
1166 if self.validate_shape().is_err() {
1167 return Value::Null(target_type);
1168 }
1169
1170 if self.data_type() == target_type {
1172 return self.clone();
1173 }
1174
1175 match target_type {
1176 DataType::Integer => {
1177 match self {
1179 Value::Integer(v) => Value::Integer(*v),
1180 Value::Float(v) => checked_float_to_i64(*v)
1181 .map(Value::Integer)
1182 .unwrap_or(Value::Null(target_type)),
1183 Value::Text(s) => parse_text_to_i64(s)
1184 .map(Value::Integer)
1185 .unwrap_or(Value::Null(target_type)),
1186 Value::Boolean(b) => Value::Integer(if *b { 1 } else { 0 }),
1187 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1188 self.as_decimal_parts()
1189 .and_then(|(unscaled, _, scale)| {
1190 decimal_scale_factor(scale)
1191 .and_then(|factor| i64::try_from(unscaled / factor).ok())
1192 })
1193 .map(Value::Integer)
1194 .unwrap_or(Value::Null(target_type))
1195 }
1196 Value::Extension(data)
1197 if matches!(
1198 data.first().and_then(|tag| DataType::from_u8(*tag)),
1199 Some(DataType::CivilTimestamp | DataType::Time)
1200 ) =>
1201 {
1202 self.as_string()
1203 .map(|value| Value::Text(SmartString::from_string(value)))
1204 .unwrap_or(Value::Null(target_type))
1205 }
1206 _ => Value::Null(target_type),
1207 }
1208 }
1209 DataType::Float => {
1210 match self {
1212 Value::Float(v) => Value::Float(*v),
1213 Value::Integer(v) => Value::Float(*v as f64),
1214 Value::Text(s) => s
1215 .parse::<f64>()
1216 .map(Value::Float)
1217 .unwrap_or(Value::Null(target_type)),
1218 Value::Boolean(b) => Value::Float(if *b { 1.0 } else { 0.0 }),
1219 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1220 self.as_string()
1221 .and_then(|value| value.parse::<f64>().ok())
1222 .map(Value::Float)
1223 .unwrap_or(Value::Null(target_type))
1224 }
1225 _ => Value::Null(target_type),
1226 }
1227 }
1228 DataType::Text => {
1229 match self {
1231 Value::Text(s) => Value::Text(s.clone()),
1232 Value::Integer(v) => Value::Text(SmartString::from_string(v.to_string())),
1233 Value::Float(v) => Value::Text(SmartString::from_string(format_float(*v))),
1234 Value::Boolean(b) => {
1235 Value::Text(SmartString::new(if *b { "true" } else { "false" }))
1236 }
1237 Value::Timestamp(t) => Value::Text(SmartString::from_string(t.to_rfc3339())),
1238 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
1239 Value::Text(SmartString::new(
1240 std::str::from_utf8(&data[1..]).unwrap_or(""),
1241 ))
1242 }
1243 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
1244 Value::Text(SmartString::from_string(format_vector_bytes(&data[1..])))
1245 }
1246 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1247 format_uuid_bytes(&data[1..])
1248 .map(|s| Value::Text(SmartString::from_string(s)))
1249 .unwrap_or(Value::Null(target_type))
1250 }
1251 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1252 self.as_string()
1253 .map(|value| Value::Text(SmartString::from_string(value)))
1254 .unwrap_or(Value::Null(target_type))
1255 }
1256 Value::Extension(data)
1257 if matches!(
1258 data.first().and_then(|tag| DataType::from_u8(*tag)),
1259 Some(DataType::CivilTimestamp | DataType::Time)
1260 ) =>
1261 {
1262 self.as_string()
1263 .map(|value| Value::Text(SmartString::from_string(value)))
1264 .unwrap_or(Value::Null(target_type))
1265 }
1266 Value::Extension(_) => Value::Null(target_type),
1267 Value::Null(_) => Value::Null(target_type),
1268 }
1269 }
1270 DataType::Boolean => {
1271 match self {
1273 Value::Boolean(b) => Value::Boolean(*b),
1274 Value::Integer(v) => Value::Boolean(*v != 0),
1275 Value::Float(v) => Value::Boolean(*v != 0.0),
1276 Value::Text(s) => {
1277 let s_ref: &str = s.as_ref();
1279 if s_ref.eq_ignore_ascii_case("true")
1280 || s_ref.eq_ignore_ascii_case("t")
1281 || s_ref.eq_ignore_ascii_case("yes")
1282 || s_ref.eq_ignore_ascii_case("y")
1283 || s_ref == "1"
1284 {
1285 Value::Boolean(true)
1286 } else if s_ref.eq_ignore_ascii_case("false")
1287 || s_ref.eq_ignore_ascii_case("f")
1288 || s_ref.eq_ignore_ascii_case("no")
1289 || s_ref.eq_ignore_ascii_case("n")
1290 || s_ref == "0"
1291 {
1292 Value::Boolean(false)
1293 } else {
1294 Value::Null(target_type)
1295 }
1296 }
1297 _ => Value::Null(target_type),
1298 }
1299 }
1300 DataType::Timestamp => {
1301 match self {
1303 Value::Timestamp(t) => Value::Timestamp(*t),
1304 Value::Extension(data)
1305 if data.first() == Some(&(DataType::Date as u8)) && data.len() == 5 =>
1306 {
1307 self.as_date_days()
1308 .and_then(|days| {
1309 NaiveDate::from_ymd_opt(1970, 1, 1)?
1310 .checked_add_signed(chrono::Duration::days(i64::from(days)))?
1311 .and_hms_opt(0, 0, 0)
1312 })
1313 .map(|value| {
1314 Value::Timestamp(DateTime::<Utc>::from_naive_utc_and_offset(
1315 value, Utc,
1316 ))
1317 })
1318 .unwrap_or(Value::Null(target_type))
1319 }
1320 Value::Text(s) => parse_timestamp(s)
1321 .map(Value::Timestamp)
1322 .unwrap_or(Value::Null(target_type)),
1323 Value::Integer(nanos) => {
1324 datetime_from_epoch_nanos(*nanos)
1326 .map(Value::Timestamp)
1327 .unwrap_or(Value::Null(target_type))
1328 }
1329 _ => Value::Null(target_type),
1330 }
1331 }
1332 DataType::CivilTimestamp => match self {
1333 Value::Text(value) => parse_civil_timestamp(value)
1334 .and_then(Value::civil_timestamp)
1335 .unwrap_or(Value::Null(target_type)),
1336 Value::Extension(data)
1337 if data.first() == Some(&(DataType::Date as u8)) && data.len() == 5 =>
1338 {
1339 self.as_date_days()
1340 .and_then(civil_midnight_from_epoch_days)
1341 .and_then(|value| Value::civil_timestamp(value).ok())
1342 .unwrap_or(Value::Null(target_type))
1343 }
1344 Value::Integer(nanos) => Value::from_temporal_nanos(target_type, *nanos)
1345 .unwrap_or(Value::Null(target_type)),
1346 _ => Value::Null(target_type),
1347 },
1348 DataType::Time => match self {
1349 Value::Text(value) => parse_time(value)
1350 .map(Value::time)
1351 .unwrap_or(Value::Null(target_type)),
1352 Value::Integer(nanos) => Value::from_temporal_nanos(target_type, *nanos)
1353 .unwrap_or(Value::Null(target_type)),
1354 _ => Value::Null(target_type),
1355 },
1356 DataType::Json => {
1357 match self {
1359 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
1360 self.clone()
1361 }
1362 Value::Text(s) => {
1363 if serde_json::from_str::<serde_json::Value>(s.as_str()).is_ok() {
1365 Value::json_unchecked(s.as_str())
1366 } else {
1367 Value::Null(target_type)
1368 }
1369 }
1370 Value::Integer(v) => Value::json_unchecked(v.to_string()),
1372 Value::Float(v) if v.is_finite() => Value::json_unchecked(format_float(*v)),
1373 Value::Boolean(b) => Value::json_unchecked(if *b { "true" } else { "false" }),
1374 Value::Timestamp(timestamp) => {
1375 Value::json_unchecked(format!("\"{}\"", timestamp.to_rfc3339()))
1376 }
1377 _ => Value::Null(target_type),
1378 }
1379 }
1380 DataType::Vector => match self {
1381 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
1382 self.clone()
1383 }
1384 Value::Text(s) => {
1385 if let Some(floats) = parse_vector_str(s.as_str()) {
1386 Value::vector(floats)
1387 } else {
1388 Value::Null(target_type)
1389 }
1390 }
1391 _ => Value::Null(target_type),
1392 },
1393 DataType::Uuid => match self {
1394 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1395 if data.len() == 17 {
1396 self.clone()
1397 } else {
1398 Value::Null(target_type)
1399 }
1400 }
1401 Value::Text(s) => parse_uuid_str(s.as_str())
1402 .map(Value::uuid)
1403 .unwrap_or(Value::Null(target_type)),
1404 _ => Value::Null(target_type),
1405 },
1406 DataType::Decimal => match self {
1407 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1408 if self.as_decimal_parts().is_some() {
1409 self.clone()
1410 } else {
1411 Value::Null(target_type)
1412 }
1413 }
1414 Value::Integer(value) => {
1415 let digits = decimal_precision_for_unscaled(*value);
1416 Value::decimal_unchecked(*value as i128, digits, 0)
1417 }
1418 Value::Float(value) => parse_decimal_f64(*value)
1419 .map(|(unscaled, precision, scale)| {
1420 Value::decimal_unchecked(unscaled, precision, scale)
1421 })
1422 .unwrap_or(Value::Null(target_type)),
1423 Value::Text(s) => parse_decimal_str(s.as_str())
1424 .map(|(unscaled, precision, scale)| {
1425 Value::decimal_unchecked(unscaled, precision, scale)
1426 })
1427 .unwrap_or(Value::Null(target_type)),
1428 _ => Value::Null(target_type),
1429 },
1430 DataType::Date => match self {
1431 Value::Extension(data) if data.first() == Some(&(DataType::Date as u8)) => {
1432 if data.len() == 5 {
1433 self.clone()
1434 } else {
1435 Value::Null(target_type)
1436 }
1437 }
1438 Value::Text(s) => parse_date_days_since_unix_epoch(s.as_str())
1439 .map(Value::date)
1440 .unwrap_or(Value::Null(target_type)),
1441 Value::Timestamp(timestamp) => date_days_since_unix_epoch(timestamp.date_naive())
1442 .map(Value::date)
1443 .unwrap_or(Value::Null(target_type)),
1444 Value::Extension(data)
1445 if data.first() == Some(&(DataType::CivilTimestamp as u8)) =>
1446 {
1447 self.as_civil_timestamp()
1448 .and_then(|timestamp| date_days_since_unix_epoch(timestamp.date()))
1449 .map(Value::date)
1450 .unwrap_or(Value::Null(target_type))
1451 }
1452 _ => Value::Null(target_type),
1453 },
1454 DataType::Bytes => match self {
1455 Value::Extension(data) if data.first() == Some(&(DataType::Bytes as u8)) => {
1456 self.clone()
1457 }
1458 Value::Text(s) => Value::bytes(s.as_bytes().to_vec()),
1459 _ => Value::Null(target_type),
1460 },
1461 DataType::Null => Value::Null(DataType::Null),
1462 }
1463 }
1464
1465 pub fn try_coerce_to_type(&self, target_type: DataType) -> Result<Value> {
1473 self.validate_shape()?;
1474 let coerced = self.coerce_to_type(target_type);
1475 if !self.is_null() && coerced.is_null() && target_type != DataType::Null {
1476 return Err(Error::Type(format!(
1477 "cannot convert value '{}' from {:?} to {:?}",
1478 self,
1479 self.data_type(),
1480 target_type
1481 )));
1482 }
1483 Ok(coerced)
1484 }
1485
1486 #[inline]
1489 pub fn into_coerce_to_type(self, target_type: DataType) -> Value {
1490 if self.is_null() {
1492 return Value::Null(target_type);
1493 }
1494
1495 if self.validate_shape().is_err() {
1496 return Value::Null(target_type);
1497 }
1498
1499 if self.data_type() == target_type {
1501 return self;
1502 }
1503
1504 match target_type {
1505 DataType::Integer => match &self {
1506 Value::Integer(v) => Value::Integer(*v),
1507 Value::Float(v) => checked_float_to_i64(*v)
1508 .map(Value::Integer)
1509 .unwrap_or(Value::Null(target_type)),
1510 Value::Text(s) => parse_text_to_i64(s)
1511 .map(Value::Integer)
1512 .unwrap_or(Value::Null(target_type)),
1513 Value::Boolean(b) => Value::Integer(if *b { 1 } else { 0 }),
1514 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1515 self.as_decimal_parts()
1516 .and_then(|(unscaled, _, scale)| {
1517 decimal_scale_factor(scale)
1518 .and_then(|factor| i64::try_from(unscaled / factor).ok())
1519 })
1520 .map(Value::Integer)
1521 .unwrap_or(Value::Null(target_type))
1522 }
1523 Value::Extension(ref data)
1524 if matches!(
1525 data.first().and_then(|tag| DataType::from_u8(*tag)),
1526 Some(DataType::CivilTimestamp | DataType::Time)
1527 ) =>
1528 {
1529 self.as_string()
1530 .map(|value| Value::Text(SmartString::from_string(value)))
1531 .unwrap_or(Value::Null(target_type))
1532 }
1533 _ => Value::Null(target_type),
1534 },
1535 DataType::Float => match &self {
1536 Value::Float(v) => Value::Float(*v),
1537 Value::Integer(v) => Value::Float(*v as f64),
1538 Value::Text(s) => s
1539 .parse::<f64>()
1540 .map(Value::Float)
1541 .unwrap_or(Value::Null(target_type)),
1542 Value::Boolean(b) => Value::Float(if *b { 1.0 } else { 0.0 }),
1543 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1544 self.as_string()
1545 .and_then(|value| value.parse::<f64>().ok())
1546 .map(Value::Float)
1547 .unwrap_or(Value::Null(target_type))
1548 }
1549 _ => Value::Null(target_type),
1550 },
1551 DataType::Text => match self {
1552 Value::Text(s) => Value::Text(s),
1553 Value::Integer(v) => Value::Text(SmartString::from_string(v.to_string())),
1554 Value::Float(v) => Value::Text(SmartString::from_string(format_float(v))),
1555 Value::Boolean(b) => {
1556 Value::Text(SmartString::new(if b { "true" } else { "false" }))
1557 }
1558 Value::Timestamp(t) => Value::Text(SmartString::from_string(t.to_rfc3339())),
1559 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
1560 Value::Text(SmartString::new(
1561 std::str::from_utf8(&data[1..]).unwrap_or(""),
1562 ))
1563 }
1564 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
1565 Value::Text(SmartString::from_string(format_vector_bytes(&data[1..])))
1566 }
1567 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1568 format_uuid_bytes(&data[1..])
1569 .map(|s| Value::Text(SmartString::from_string(s)))
1570 .unwrap_or(Value::Null(target_type))
1571 }
1572 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1573 self.as_string()
1574 .map(|value| Value::Text(SmartString::from_string(value)))
1575 .unwrap_or(Value::Null(target_type))
1576 }
1577 Value::Extension(ref data)
1578 if matches!(
1579 data.first().and_then(|tag| DataType::from_u8(*tag)),
1580 Some(DataType::CivilTimestamp | DataType::Time)
1581 ) =>
1582 {
1583 self.as_string()
1584 .map(|value| Value::Text(SmartString::from_string(value)))
1585 .unwrap_or(Value::Null(target_type))
1586 }
1587 Value::Extension(_) | Value::Null(_) => Value::Null(target_type),
1588 },
1589 DataType::Boolean => match &self {
1590 Value::Boolean(b) => Value::Boolean(*b),
1591 Value::Integer(v) => Value::Boolean(*v != 0),
1592 Value::Float(v) => Value::Boolean(*v != 0.0),
1593 Value::Text(s) => {
1594 let s_ref: &str = s.as_ref();
1596 if s_ref.eq_ignore_ascii_case("true")
1597 || s_ref.eq_ignore_ascii_case("t")
1598 || s_ref.eq_ignore_ascii_case("yes")
1599 || s_ref.eq_ignore_ascii_case("y")
1600 || s_ref == "1"
1601 {
1602 Value::Boolean(true)
1603 } else if s_ref.eq_ignore_ascii_case("false")
1604 || s_ref.eq_ignore_ascii_case("f")
1605 || s_ref.eq_ignore_ascii_case("no")
1606 || s_ref.eq_ignore_ascii_case("n")
1607 || s_ref == "0"
1608 {
1609 Value::Boolean(false)
1610 } else {
1611 Value::Null(target_type)
1612 }
1613 }
1614 _ => Value::Null(target_type),
1615 },
1616 DataType::Timestamp => match self {
1617 Value::Timestamp(t) => Value::Timestamp(t),
1618 Value::Text(s) => parse_timestamp(&s)
1619 .map(Value::Timestamp)
1620 .unwrap_or(Value::Null(target_type)),
1621 Value::Integer(nanos) => datetime_from_epoch_nanos(nanos)
1622 .map(Value::Timestamp)
1623 .unwrap_or(Value::Null(target_type)),
1624 _ => Value::Null(target_type),
1625 },
1626 DataType::CivilTimestamp => match self {
1627 Value::Text(value) => parse_civil_timestamp(&value)
1628 .and_then(Value::civil_timestamp)
1629 .unwrap_or(Value::Null(target_type)),
1630 Value::Integer(nanos) => Value::from_temporal_nanos(target_type, nanos)
1631 .unwrap_or(Value::Null(target_type)),
1632 _ => Value::Null(target_type),
1633 },
1634 DataType::Time => match self {
1635 Value::Text(value) => parse_time(&value)
1636 .map(Value::time)
1637 .unwrap_or(Value::Null(target_type)),
1638 Value::Integer(nanos) => Value::from_temporal_nanos(target_type, nanos)
1639 .unwrap_or(Value::Null(target_type)),
1640 _ => Value::Null(target_type),
1641 },
1642 DataType::Json => match self {
1643 Value::Extension(ref data) if data.first() == Some(&(DataType::Json as u8)) => self,
1644 Value::Text(s) => {
1645 if serde_json::from_str::<serde_json::Value>(s.as_str()).is_ok() {
1646 Value::json_unchecked(s.as_str())
1647 } else {
1648 Value::Null(target_type)
1649 }
1650 }
1651 Value::Integer(v) => Value::json_unchecked(v.to_string()),
1652 Value::Float(v) if v.is_finite() => Value::json_unchecked(format_float(v)),
1653 Value::Boolean(b) => Value::json_unchecked(if b { "true" } else { "false" }),
1654 Value::Timestamp(timestamp) => {
1655 Value::json_unchecked(format!("\"{}\"", timestamp.to_rfc3339()))
1656 }
1657 _ => Value::Null(target_type),
1658 },
1659 DataType::Vector => match self {
1660 Value::Extension(ref data) if data.first() == Some(&(DataType::Vector as u8)) => {
1661 self
1662 }
1663 Value::Text(s) => {
1664 if let Some(floats) = parse_vector_str(s.as_str()) {
1665 Value::vector(floats)
1666 } else {
1667 Value::Null(target_type)
1668 }
1669 }
1670 _ => Value::Null(target_type),
1671 },
1672 DataType::Uuid => match self {
1673 Value::Extension(ref data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1674 if data.len() == 17 {
1675 self
1676 } else {
1677 Value::Null(target_type)
1678 }
1679 }
1680 Value::Text(s) => parse_uuid_str(s.as_str())
1681 .map(Value::uuid)
1682 .unwrap_or(Value::Null(target_type)),
1683 _ => Value::Null(target_type),
1684 },
1685 DataType::Decimal => match self {
1686 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1687 if self.as_decimal_parts().is_some() {
1688 self
1689 } else {
1690 Value::Null(target_type)
1691 }
1692 }
1693 Value::Integer(value) => {
1694 let digits = decimal_precision_for_unscaled(value);
1695 Value::decimal_unchecked(value as i128, digits, 0)
1696 }
1697 Value::Float(value) => parse_decimal_f64(value)
1698 .map(|(unscaled, precision, scale)| {
1699 Value::decimal_unchecked(unscaled, precision, scale)
1700 })
1701 .unwrap_or(Value::Null(target_type)),
1702 Value::Text(s) => parse_decimal_str(s.as_str())
1703 .map(|(unscaled, precision, scale)| {
1704 Value::decimal_unchecked(unscaled, precision, scale)
1705 })
1706 .unwrap_or(Value::Null(target_type)),
1707 _ => Value::Null(target_type),
1708 },
1709 DataType::Date => match self {
1710 Value::Extension(ref data) if data.first() == Some(&(DataType::Date as u8)) => {
1711 if data.len() == 5 {
1712 self
1713 } else {
1714 Value::Null(target_type)
1715 }
1716 }
1717 Value::Text(s) => parse_date_days_since_unix_epoch(s.as_str())
1718 .map(Value::date)
1719 .unwrap_or(Value::Null(target_type)),
1720 Value::Timestamp(timestamp) => date_days_since_unix_epoch(timestamp.date_naive())
1721 .map(Value::date)
1722 .unwrap_or(Value::Null(target_type)),
1723 Value::Extension(ref data)
1724 if data.first() == Some(&(DataType::CivilTimestamp as u8)) =>
1725 {
1726 self.as_civil_timestamp()
1727 .and_then(|timestamp| date_days_since_unix_epoch(timestamp.date()))
1728 .map(Value::date)
1729 .unwrap_or(Value::Null(target_type))
1730 }
1731 _ => Value::Null(target_type),
1732 },
1733 DataType::Bytes => match self {
1734 Value::Extension(ref data) if data.first() == Some(&(DataType::Bytes as u8)) => {
1735 self
1736 }
1737 Value::Text(s) => Value::bytes(s.as_bytes().to_vec()),
1738 _ => Value::Null(target_type),
1739 },
1740 DataType::Null => Value::Null(DataType::Null),
1741 }
1742 }
1743}
1744
1745impl Default for Value {
1750 fn default() -> Self {
1751 Value::Null(DataType::Null)
1752 }
1753}
1754
1755impl fmt::Display for Value {
1756 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1757 match self {
1758 Value::Null(_) => write!(f, "NULL"),
1759 Value::Integer(v) => write!(f, "{}", v),
1760 Value::Float(v) => write!(f, "{}", format_float(*v)),
1761 Value::Text(s) => write!(f, "{}", s),
1762 Value::Boolean(b) => write!(f, "{}", if *b { "true" } else { "false" }),
1763 Value::Timestamp(t) => write!(f, "{}", t.to_rfc3339()),
1764 Value::Extension(data) => {
1765 let tag = data.first().copied().unwrap_or(0);
1766 if tag == DataType::Json as u8 {
1767 write!(f, "{}", std::str::from_utf8(&data[1..]).unwrap_or(""))
1768 } else if tag == DataType::Vector as u8 {
1769 write!(f, "{}", format_vector_bytes(&data[1..]))
1770 } else if tag == DataType::Uuid as u8 {
1771 match format_uuid_bytes(&data[1..]) {
1772 Some(uuid) => write!(f, "{}", uuid),
1773 None => write!(f, "<invalid-uuid>"),
1774 }
1775 } else if tag == DataType::Decimal as u8 {
1776 match self.as_decimal_parts() {
1777 Some((unscaled, _, scale)) => {
1778 write!(f, "{}", format_decimal_parts(unscaled, scale))
1779 }
1780 None => write!(f, "<invalid-decimal>"),
1781 }
1782 } else if tag == DataType::Date as u8 {
1783 match self
1784 .as_date_days()
1785 .and_then(format_date_days_since_unix_epoch)
1786 {
1787 Some(date) => write!(f, "{}", date),
1788 None => write!(f, "<invalid-date>"),
1789 }
1790 } else if tag == DataType::CivilTimestamp as u8 {
1791 match self.as_civil_timestamp() {
1792 Some(value) => write!(f, "{}", format_civil_timestamp(value)),
1793 None => write!(f, "<invalid-timestamp>"),
1794 }
1795 } else if tag == DataType::Time as u8 {
1796 match self.as_time() {
1797 Some(value) => write!(f, "{}", format_time(value)),
1798 None => write!(f, "<invalid-time>"),
1799 }
1800 } else if tag == DataType::Bytes as u8 {
1801 write!(f, "{}", format_bytes_hex(&data[1..]))
1802 } else {
1803 write!(f, "<extension:{}>", tag)
1804 }
1805 }
1806 }
1807 }
1808}
1809
1810impl PartialEq for Value {
1811 #[inline]
1812 fn eq(&self, other: &Self) -> bool {
1813 if let Some(ordering) = compare_canonical_numeric(self, other) {
1814 return ordering == Ordering::Equal;
1815 }
1816
1817 match (self, other) {
1819 (Value::Null(_), Value::Null(_)) => true,
1821 (Value::Null(_), _) | (_, Value::Null(_)) => false,
1823 (Value::Text(a), Value::Text(b)) => a == b,
1824 (Value::Boolean(a), Value::Boolean(b)) => a == b,
1825 (Value::Timestamp(a), Value::Timestamp(b)) => a == b,
1826 (Value::Extension(a), Value::Extension(b)) => a == b,
1827 _ => false,
1828 }
1829 }
1830}
1831
1832impl Eq for Value {}
1833
1834#[inline]
1840fn compare_integer_float(integer: i64, float: f64) -> Ordering {
1841 const I64_EXCLUSIVE_UPPER_F64: f64 = 9_223_372_036_854_775_808.0;
1842 const I64_INCLUSIVE_LOWER_F64: f64 = -9_223_372_036_854_775_808.0;
1843
1844 if float.is_nan() {
1845 return Ordering::Less;
1846 }
1847 if float >= I64_EXCLUSIVE_UPPER_F64 {
1848 return Ordering::Less;
1849 }
1850 if float < I64_INCLUSIVE_LOWER_F64 {
1851 return Ordering::Greater;
1852 }
1853
1854 let truncated = float as i64;
1858 match integer.cmp(&truncated) {
1859 Ordering::Equal => {
1860 let fraction = float.fract();
1861 if fraction == 0.0 {
1862 Ordering::Equal
1863 } else if fraction.is_sign_negative() {
1864 Ordering::Greater
1865 } else {
1866 Ordering::Less
1867 }
1868 }
1869 ordering => ordering,
1870 }
1871}
1872
1873#[inline(always)]
1878fn wymix(a: u64, b: u64) -> u64 {
1879 let r = (a as u128).wrapping_mul(b as u128);
1880 (r as u64) ^ ((r >> 64) as u64)
1881}
1882
1883const WY_P1: u64 = 0xa0761d6478bd642f;
1885const WY_P2: u64 = 0xe7037ed1a0b428db;
1886
1887#[inline(always)]
1888fn integer_hash_word(value: i64) -> u64 {
1889 wymix(1 ^ (value as u64), WY_P1)
1890}
1891
1892#[inline(always)]
1893fn float_hash_word(value: f64) -> u64 {
1894 if value.is_nan() {
1895 return wymix(6 ^ f64::NAN.to_bits(), WY_P1);
1896 }
1897
1898 let integer = value as i64;
1899 if compare_integer_float(integer, value) == Ordering::Equal {
1900 integer_hash_word(integer)
1903 } else {
1904 wymix(6 ^ value.to_bits(), WY_P1)
1905 }
1906}
1907
1908impl Hash for Value {
1909 #[inline(always)]
1910 fn hash<H: Hasher>(&self, state: &mut H) {
1911 match self {
1920 Value::Null(_) => {
1921 state.write_u64(0);
1923 }
1924 Value::Integer(v) => {
1925 state.write_u64(integer_hash_word(*v));
1927 }
1928 Value::Float(v) => {
1929 state.write_u64(float_hash_word(*v));
1930 }
1931 Value::Text(s) => {
1932 let bytes = s.as_bytes();
1934 let len = bytes.len();
1935 let mut h = wymix(2 ^ (len as u64), WY_P1);
1936
1937 let chunks = len / 8;
1939 let ptr = bytes.as_ptr();
1940 for i in 0..chunks {
1941 let chunk = unsafe { (ptr.add(i * 8) as *const u64).read_unaligned() };
1945 h = wymix(h ^ chunk, WY_P2);
1946 }
1947
1948 let tail_start = chunks * 8;
1950 if tail_start < len {
1951 let mut tail = 0u64;
1952 for (j, &b) in bytes[tail_start..].iter().enumerate() {
1953 tail |= (b as u64) << (j * 8);
1954 }
1955 h = wymix(h ^ tail, WY_P1);
1956 }
1957
1958 state.write_u64(h);
1959 }
1960 Value::Boolean(b) => {
1961 state.write_u64(wymix(if *b { 5 } else { 4 }, WY_P1));
1963 }
1964 Value::Timestamp(t) => {
1965 let nanos = t
1968 .timestamp_nanos_opt()
1969 .unwrap_or_else(|| t.timestamp().saturating_mul(1_000_000_000));
1970 state.write_u64(wymix(3 ^ (nanos as u64), WY_P1));
1971 }
1972 Value::Extension(data) => {
1973 if let Some((unscaled, _, scale)) = self.as_decimal_parts() {
1974 state.write_u64(decimal_hash_word(unscaled, scale));
1975 return;
1976 }
1977
1978 let bytes: &[u8] = data;
1981 let len = bytes.len();
1982 let mut h = wymix(10 ^ (len as u64), WY_P1);
1983
1984 let chunks = len / 8;
1985 let ptr = bytes.as_ptr();
1986 for i in 0..chunks {
1987 let chunk = unsafe { (ptr.add(i * 8) as *const u64).read_unaligned() };
1991 h = wymix(h ^ chunk, WY_P2);
1992 }
1993
1994 let tail_start = chunks * 8;
1995 if tail_start < len {
1996 let mut tail = 0u64;
1997 for (j, &b) in bytes[tail_start..].iter().enumerate() {
1998 tail |= (b as u64) << (j * 8);
1999 }
2000 h = wymix(h ^ tail, WY_P1);
2001 }
2002
2003 state.write_u64(h);
2004 }
2005 }
2006 }
2007}
2008
2009#[allow(clippy::non_canonical_partial_ord_impl)]
2013impl PartialOrd for Value {
2014 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2015 self.compare(other).ok()
2019 }
2020}
2021
2022impl Ord for Value {
2038 fn cmp(&self, other: &Self) -> Ordering {
2039 match (self.is_null(), other.is_null()) {
2041 (true, true) => return Ordering::Equal,
2042 (true, false) => return Ordering::Less,
2043 (false, true) => return Ordering::Greater,
2044 (false, false) => {} }
2046
2047 if let Some(ordering) = compare_canonical_numeric(self, other) {
2048 return ordering;
2049 }
2050
2051 fn type_discriminant(v: &Value) -> u8 {
2053 match v {
2054 Value::Null(_) => 0,
2055 Value::Boolean(_) => 1,
2056 Value::Integer(_) | Value::Float(_) => 2,
2058 Value::Extension(_) if v.as_decimal_parts().is_some() => 2,
2059 Value::Text(_) => 3,
2060 Value::Timestamp(_) => 4,
2061 Value::Extension(_) => 5,
2062 }
2063 }
2064
2065 let self_disc = type_discriminant(self);
2066 let other_disc = type_discriminant(other);
2067
2068 if self_disc != other_disc {
2070 return self_disc.cmp(&other_disc);
2071 }
2072
2073 match (self, other) {
2075 (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
2076 (Value::Float(a), Value::Float(b)) => {
2077 match (a.is_nan(), b.is_nan()) {
2079 (true, true) => Ordering::Equal,
2080 (true, false) => Ordering::Greater,
2081 (false, true) => Ordering::Less,
2082 (false, false) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
2083 }
2084 }
2085 (Value::Text(a), Value::Text(b)) => a.cmp(b),
2086 (Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
2087 (Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
2088 (Value::Extension(a), Value::Extension(b)) => {
2089 if a.first() == b.first()
2090 && matches!(
2091 a.first().and_then(|tag| DataType::from_u8(*tag)),
2092 Some(DataType::CivilTimestamp | DataType::Time)
2093 )
2094 {
2095 match (
2096 self.artifact_temporal_nanos(),
2097 other.artifact_temporal_nanos(),
2098 ) {
2099 (Some(left), Some(right)) => left.cmp(&right),
2100 _ => a.cmp(b),
2101 }
2102 } else {
2103 a.cmp(b)
2104 }
2105 }
2106 _ => Ordering::Equal, }
2108 }
2109}
2110
2111impl From<i64> for Value {
2116 fn from(v: i64) -> Self {
2117 Value::Integer(v)
2118 }
2119}
2120
2121impl From<i32> for Value {
2122 fn from(v: i32) -> Self {
2123 Value::Integer(v as i64)
2124 }
2125}
2126
2127impl From<i16> for Value {
2128 fn from(v: i16) -> Self {
2129 Value::Integer(v as i64)
2130 }
2131}
2132
2133impl From<i8> for Value {
2134 fn from(v: i8) -> Self {
2135 Value::Integer(v as i64)
2136 }
2137}
2138
2139impl From<u32> for Value {
2140 fn from(v: u32) -> Self {
2141 Value::Integer(v as i64)
2142 }
2143}
2144
2145impl From<u16> for Value {
2146 fn from(v: u16) -> Self {
2147 Value::Integer(v as i64)
2148 }
2149}
2150
2151impl From<u8> for Value {
2152 fn from(v: u8) -> Self {
2153 Value::Integer(v as i64)
2154 }
2155}
2156
2157impl From<f64> for Value {
2158 fn from(v: f64) -> Self {
2159 Value::Float(v)
2160 }
2161}
2162
2163impl From<f32> for Value {
2164 fn from(v: f32) -> Self {
2165 Value::Float(v as f64)
2166 }
2167}
2168
2169impl From<String> for Value {
2170 fn from(v: String) -> Self {
2171 Value::Text(SmartString::from_string(v))
2172 }
2173}
2174
2175impl From<&str> for Value {
2176 fn from(v: &str) -> Self {
2177 Value::Text(SmartString::from(v))
2178 }
2179}
2180
2181impl From<Arc<str>> for Value {
2182 fn from(v: Arc<str>) -> Self {
2183 Value::Text(SmartString::from(v.as_ref()))
2184 }
2185}
2186
2187impl From<bool> for Value {
2188 fn from(v: bool) -> Self {
2189 Value::Boolean(v)
2190 }
2191}
2192
2193impl From<DateTime<Utc>> for Value {
2194 fn from(v: DateTime<Utc>) -> Self {
2195 Value::Timestamp(v)
2196 }
2197}
2198
2199impl<T: Into<Value>> From<Option<T>> for Value {
2200 fn from(v: Option<T>) -> Self {
2201 match v {
2202 Some(val) => val.into(),
2203 None => Value::Null(DataType::Null),
2204 }
2205 }
2206}
2207
2208pub fn parse_timestamp(s: &str) -> Result<DateTime<Utc>> {
2214 let s = s.trim();
2215
2216 for format in TIMESTAMP_FORMATS {
2218 if let Ok(dt) = DateTime::parse_from_str(s, format) {
2219 return Ok(dt.with_timezone(&Utc));
2220 }
2221 if let Ok(ndt) = NaiveDateTime::parse_from_str(s, format) {
2223 return Ok(Utc.from_utc_datetime(&ndt));
2224 }
2225 }
2226
2227 if let Ok(date) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
2229 let datetime = date.and_hms_opt(0, 0, 0).unwrap();
2230 return Ok(Utc.from_utc_datetime(&datetime));
2231 }
2232
2233 for format in TIME_FORMATS {
2235 if let Ok(time) = NaiveTime::parse_from_str(s, format) {
2236 let today = Utc::now().date_naive();
2237 let datetime = today.and_time(time);
2238 return Ok(Utc.from_utc_datetime(&datetime));
2239 }
2240 }
2241
2242 Err(Error::parse(format!("invalid timestamp format: {}", s)))
2243}
2244
2245pub fn parse_civil_timestamp(s: &str) -> Result<NaiveDateTime> {
2247 let s = s.trim();
2248 for format in CIVIL_TIMESTAMP_FORMATS {
2249 if let Ok(value) = NaiveDateTime::parse_from_str(s, format) {
2250 return Ok(value);
2251 }
2252 }
2253 if let Ok(date) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
2254 return date
2255 .and_hms_opt(0, 0, 0)
2256 .ok_or_else(|| Error::parse(format!("invalid civil timestamp: {s}")));
2257 }
2258 Err(Error::parse(format!("invalid civil timestamp format: {s}")))
2259}
2260
2261pub fn parse_time(s: &str) -> Result<NaiveTime> {
2263 let s = s.trim();
2264 for format in TIME_FORMATS {
2265 if let Ok(value) = NaiveTime::parse_from_str(s, format) {
2266 return Ok(value);
2267 }
2268 }
2269 Err(Error::parse(format!("invalid time format: {s}")))
2270}
2271
2272fn temporal_payload_nanos(payload: &[u8], sql_type: &str) -> Result<i64> {
2273 let bytes: [u8; 8] = payload.try_into().map_err(|_| {
2274 Error::invalid_argument(format!("{sql_type} payload must contain exactly 8 bytes"))
2275 })?;
2276 Ok(i64::from_le_bytes(bytes))
2277}
2278
2279fn civil_midnight_from_epoch_days(days: i32) -> Option<NaiveDateTime> {
2280 NaiveDate::from_ymd_opt(1970, 1, 1)?
2281 .checked_add_signed(chrono::Duration::days(i64::from(days)))?
2282 .and_hms_opt(0, 0, 0)
2283}
2284
2285fn date_days_since_unix_epoch(date: NaiveDate) -> Option<i32> {
2286 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1)?;
2287 i32::try_from(date.signed_duration_since(epoch).num_days()).ok()
2288}
2289
2290fn format_civil_timestamp(value: NaiveDateTime) -> String {
2291 value.format("%Y-%m-%d %H:%M:%S%.f").to_string()
2292}
2293
2294fn format_time(value: NaiveTime) -> String {
2295 value.format("%H:%M:%S%.f").to_string()
2296}
2297
2298fn format_float(v: f64) -> String {
2300 if v.is_nan() {
2302 return "NaN".to_string();
2303 }
2304 if v.is_infinite() {
2305 return if v.is_sign_positive() {
2306 "Infinity"
2307 } else {
2308 "-Infinity"
2309 }
2310 .to_string();
2311 }
2312
2313 let abs_v = v.abs();
2314
2315 if abs_v != 0.0 && !(1e-4..1e15).contains(&abs_v) {
2317 let s = format!("{:e}", v);
2319 if let Some(e_pos) = s.find('e') {
2321 let (mantissa, exp) = s.split_at(e_pos);
2322 let clean_mantissa = if mantissa.contains('.') {
2323 mantissa
2324 .trim_end_matches('0')
2325 .trim_end_matches('.')
2326 .to_string()
2327 } else {
2328 mantissa.to_string()
2329 };
2330 return format!("{}{}", clean_mantissa, exp);
2331 }
2332 return s;
2333 }
2334
2335 if v.fract() == 0.0 {
2336 format!("{:.0}", v)
2338 } else {
2339 let s = format!("{:?}", v);
2341 if s.contains('.') && !s.contains('e') && !s.contains('E') {
2343 s.trim_end_matches('0').trim_end_matches('.').to_string()
2344 } else {
2345 s
2346 }
2347 }
2348}
2349
2350pub fn format_vector_bytes(data: &[u8]) -> String {
2352 let len = data.len() / 4;
2353 let mut s = String::with_capacity(len * 8 + 2);
2354 s.push('[');
2355 for i in 0..len {
2356 if i > 0 {
2357 s.push_str(", ");
2358 }
2359 let f = f32::from_le_bytes([
2360 data[i * 4],
2361 data[i * 4 + 1],
2362 data[i * 4 + 2],
2363 data[i * 4 + 3],
2364 ]);
2365 use std::fmt::Write;
2366 if f.fract() == 0.0 && f.is_finite() {
2367 let _ = write!(s, "{:.1}", f);
2368 } else {
2369 let _ = write!(s, "{}", f);
2370 }
2371 }
2372 s.push(']');
2373 s
2374}
2375
2376pub fn parse_uuid_str(s: &str) -> Option<[u8; 16]> {
2382 Uuid::parse_str(s.trim()).ok().map(|uuid| *uuid.as_bytes())
2383}
2384
2385pub fn format_uuid_bytes(data: &[u8]) -> Option<String> {
2387 let bytes: [u8; 16] = data.try_into().ok()?;
2388 Some(Uuid::from_bytes(bytes).hyphenated().to_string())
2389}
2390
2391pub const MAX_DECIMAL_PRECISION: u8 = 38;
2392
2393pub fn validate_decimal_shape(unscaled: i128, precision: u8, scale: u8) -> Result<()> {
2395 if !(1..=MAX_DECIMAL_PRECISION).contains(&precision) {
2396 return Err(Error::invalid_argument(format!(
2397 "DECIMAL precision {precision} is outside supported range 1..={MAX_DECIMAL_PRECISION}"
2398 )));
2399 }
2400 if scale > precision {
2401 return Err(Error::invalid_argument(format!(
2402 "DECIMAL scale {scale} exceeds declared precision {precision}"
2403 )));
2404 }
2405 let digits = unscaled.unsigned_abs().to_string().len().max(1);
2406 if digits > usize::from(precision) {
2407 return Err(Error::invalid_argument(format!(
2408 "DECIMAL coefficient has {digits} digits but precision is {precision}"
2409 )));
2410 }
2411 Ok(())
2412}
2413
2414#[inline]
2415fn checked_float_to_i64(value: f64) -> Option<i64> {
2416 const I64_EXCLUSIVE_UPPER_F64: f64 = 9_223_372_036_854_775_808.0;
2417 const I64_INCLUSIVE_LOWER_F64: f64 = -9_223_372_036_854_775_808.0;
2418 (value.is_finite() && (I64_INCLUSIVE_LOWER_F64..I64_EXCLUSIVE_UPPER_F64).contains(&value))
2419 .then_some(value as i64)
2420}
2421
2422#[inline]
2423fn parse_text_to_i64(value: &str) -> Option<i64> {
2424 value
2425 .parse::<i64>()
2426 .ok()
2427 .or_else(|| value.parse::<f64>().ok().and_then(checked_float_to_i64))
2428}
2429
2430#[inline]
2431fn datetime_from_epoch_nanos(nanos: i64) -> Option<DateTime<Utc>> {
2432 DateTime::from_timestamp(
2433 nanos.div_euclid(1_000_000_000),
2434 nanos.rem_euclid(1_000_000_000) as u32,
2435 )
2436}
2437
2438fn decimal_precision_for_unscaled(value: i64) -> u8 {
2440 decimal_precision_for_unscaled_i128(value as i128)
2441}
2442
2443fn decimal_precision_for_unscaled_i128(value: i128) -> u8 {
2444 let digits = value.unsigned_abs().to_string().len().max(1);
2445 digits.min(MAX_DECIMAL_PRECISION as usize) as u8
2446}
2447
2448#[inline]
2449fn decimal_scale_factor(scale: u8) -> Option<i128> {
2450 (scale <= MAX_DECIMAL_PRECISION)
2451 .then(|| 10_i128.checked_pow(scale as u32))
2452 .flatten()
2453}
2454
2455#[derive(Clone, Debug, Eq, PartialEq)]
2461struct DecimalIdentity {
2462 negative: bool,
2463 coefficient: u128,
2464 exponent: i32,
2465}
2466
2467impl DecimalIdentity {
2468 fn new(negative: bool, mut coefficient: u128, mut exponent: i32) -> Self {
2469 if coefficient == 0 {
2470 return Self {
2471 negative: false,
2472 coefficient: 0,
2473 exponent: 0,
2474 };
2475 }
2476
2477 while coefficient.is_multiple_of(10) {
2478 coefficient /= 10;
2479 exponent += 1;
2480 }
2481
2482 Self {
2483 negative,
2484 coefficient,
2485 exponent,
2486 }
2487 }
2488
2489 fn from_parts(unscaled: i128, scale: u8) -> Self {
2490 Self::new(
2491 unscaled.is_negative(),
2492 unscaled.unsigned_abs(),
2493 -i32::from(scale),
2494 )
2495 }
2496
2497 fn from_float(value: f64) -> Option<Self> {
2500 if !value.is_finite() {
2501 return None;
2502 }
2503
2504 let rendered = format!("{value:e}");
2507 let (mantissa, exponent) = rendered.split_once('e')?;
2508 let exponent = exponent.parse::<i32>().ok()?;
2509 let (negative, mantissa) = mantissa
2510 .strip_prefix('-')
2511 .map_or((false, mantissa), |unsigned| (true, unsigned));
2512 let (integer, fraction) = mantissa.split_once('.').unwrap_or((mantissa, ""));
2513 let digits = format!("{integer}{fraction}");
2514 let coefficient = digits.parse::<u128>().ok()?;
2515 let fraction_len = i32::try_from(fraction.len()).ok()?;
2516
2517 Some(Self::new(
2518 negative,
2519 coefficient,
2520 exponent.checked_sub(fraction_len)?,
2521 ))
2522 }
2523
2524 fn exact_i64(&self) -> Option<i64> {
2525 if self.coefficient == 0 {
2526 return Some(0);
2527 }
2528 let exponent = u32::try_from(self.exponent).ok()?;
2529 let magnitude = self
2530 .coefficient
2531 .checked_mul(10_u128.checked_pow(exponent)?)?;
2532 if self.negative {
2533 if magnitude == (i64::MAX as u128) + 1 {
2534 Some(i64::MIN)
2535 } else {
2536 i64::try_from(magnitude).ok().map(|value| -value)
2537 }
2538 } else {
2539 i64::try_from(magnitude).ok()
2540 }
2541 }
2542
2543 fn cmp_magnitude(&self, other: &Self) -> Ordering {
2544 debug_assert!(self.coefficient != 0 && other.coefficient != 0);
2545
2546 let left_digits = self.coefficient.to_string();
2547 let right_digits = other.coefficient.to_string();
2548 let left_order = i32::try_from(left_digits.len())
2549 .unwrap_or(i32::MAX)
2550 .saturating_add(self.exponent);
2551 let right_order = i32::try_from(right_digits.len())
2552 .unwrap_or(i32::MAX)
2553 .saturating_add(other.exponent);
2554 match left_order.cmp(&right_order) {
2555 Ordering::Equal => {}
2556 ordering => return ordering,
2557 }
2558
2559 let width = left_digits.len().max(right_digits.len());
2560 for index in 0..width {
2561 let left = left_digits.as_bytes().get(index).copied().unwrap_or(b'0');
2562 let right = right_digits.as_bytes().get(index).copied().unwrap_or(b'0');
2563 match left.cmp(&right) {
2564 Ordering::Equal => {}
2565 ordering => return ordering,
2566 }
2567 }
2568 Ordering::Equal
2569 }
2570
2571 fn cmp_numeric(&self, other: &Self) -> Ordering {
2572 if self == other {
2573 return Ordering::Equal;
2574 }
2575
2576 match (self.coefficient == 0, other.coefficient == 0) {
2577 (true, true) => return Ordering::Equal,
2578 (true, false) => {
2579 return if other.negative {
2580 Ordering::Greater
2581 } else {
2582 Ordering::Less
2583 };
2584 }
2585 (false, true) => {
2586 return if self.negative {
2587 Ordering::Less
2588 } else {
2589 Ordering::Greater
2590 };
2591 }
2592 (false, false) => {}
2593 }
2594
2595 match self.negative.cmp(&other.negative) {
2596 Ordering::Less => Ordering::Greater,
2597 Ordering::Greater => Ordering::Less,
2598 Ordering::Equal if self.negative => self.cmp_magnitude(other).reverse(),
2599 Ordering::Equal => self.cmp_magnitude(other),
2600 }
2601 }
2602}
2603
2604fn compare_decimal_float(decimal: &DecimalIdentity, float: f64) -> Ordering {
2605 if float.is_nan() || float == f64::INFINITY {
2606 return Ordering::Less;
2607 }
2608 if float == f64::NEG_INFINITY {
2609 return Ordering::Greater;
2610 }
2611
2612 decimal.cmp_numeric(
2613 &DecimalIdentity::from_float(float)
2614 .expect("every finite f64 has a shortest decimal identity"),
2615 )
2616}
2617
2618fn compare_canonical_numeric(left: &Value, right: &Value) -> Option<Ordering> {
2621 match (left, right) {
2622 (Value::Integer(left), Value::Integer(right)) => Some(left.cmp(right)),
2623 (Value::Float(left), Value::Float(right)) => Some(compare_floats(*left, *right)),
2624 (Value::Integer(integer), Value::Float(float)) => {
2625 Some(compare_integer_float(*integer, *float))
2626 }
2627 (Value::Float(float), Value::Integer(integer)) => {
2628 Some(compare_integer_float(*integer, *float).reverse())
2629 }
2630 _ => {
2631 let left_decimal = left
2632 .as_decimal_parts()
2633 .map(|(unscaled, _, scale)| DecimalIdentity::from_parts(unscaled, scale));
2634 let right_decimal = right
2635 .as_decimal_parts()
2636 .map(|(unscaled, _, scale)| DecimalIdentity::from_parts(unscaled, scale));
2637
2638 match (left_decimal, right_decimal, left, right) {
2639 (Some(left), Some(right), _, _) => Some(left.cmp_numeric(&right)),
2640 (Some(left), None, _, Value::Integer(right)) => {
2641 Some(left.cmp_numeric(&DecimalIdentity::from_parts(*right as i128, 0)))
2642 }
2643 (None, Some(right), Value::Integer(left), _) => {
2644 Some(DecimalIdentity::from_parts(*left as i128, 0).cmp_numeric(&right))
2645 }
2646 (Some(left), None, _, Value::Float(right)) => {
2647 Some(compare_decimal_float(&left, *right))
2648 }
2649 (None, Some(right), Value::Float(left), _) => {
2650 Some(compare_decimal_float(&right, *left).reverse())
2651 }
2652 _ => None,
2653 }
2654 }
2655 }
2656}
2657
2658fn decimal_hash_word(unscaled: i128, scale: u8) -> u64 {
2659 let identity = DecimalIdentity::from_parts(unscaled, scale);
2660 if let Some(integer) = identity.exact_i64() {
2661 return integer_hash_word(integer);
2662 }
2663
2664 if let Ok(float) = format_decimal_parts(unscaled, scale).parse::<f64>() {
2669 if float.is_finite() && DecimalIdentity::from_float(float).as_ref() == Some(&identity) {
2670 return float_hash_word(float);
2671 }
2672 }
2673
2674 let low = identity.coefficient as u64;
2675 let high = (identity.coefficient >> 64) as u64;
2676 let sign = u64::from(identity.negative);
2677 let exponent = identity.exponent as i64 as u64;
2678 let mut hash = wymix(7 ^ low, WY_P1);
2679 hash = wymix(hash ^ high, WY_P2);
2680 hash = wymix(hash ^ exponent, WY_P1);
2681 wymix(hash ^ sign, WY_P2)
2682}
2683
2684fn parse_decimal_f64(value: f64) -> Option<(i128, u8, u8)> {
2689 if !value.is_finite() {
2690 return None;
2691 }
2692
2693 let rendered = value.to_string();
2694 let Some(exponent_offset) = rendered.find(['e', 'E']) else {
2695 return parse_decimal_str(&rendered);
2696 };
2697
2698 let (mantissa, exponent_with_marker) = rendered.split_at(exponent_offset);
2699 let exponent = exponent_with_marker[1..].parse::<i32>().ok()?;
2700 let (mut unscaled, _, mantissa_scale) = parse_decimal_str(mantissa)?;
2701 let resulting_scale = i32::from(mantissa_scale).checked_sub(exponent)?;
2702
2703 let scale = if resulting_scale < 0 {
2704 let power = u8::try_from(resulting_scale.checked_neg()?).ok()?;
2705 unscaled = unscaled.checked_mul(decimal_scale_factor(power)?)?;
2706 0
2707 } else {
2708 u8::try_from(resulting_scale).ok()?
2709 };
2710 if scale > MAX_DECIMAL_PRECISION
2711 || unscaled.unsigned_abs().to_string().len() > MAX_DECIMAL_PRECISION as usize
2712 {
2713 return None;
2714 }
2715
2716 Some((
2717 unscaled,
2718 decimal_precision_for_unscaled_i128(unscaled),
2719 scale,
2720 ))
2721}
2722
2723pub fn parse_decimal_str(s: &str) -> Option<(i128, u8, u8)> {
2729 let trimmed = s.trim();
2730 if trimmed.is_empty() {
2731 return None;
2732 }
2733
2734 let (negative, body) = match trimmed.as_bytes()[0] {
2735 b'-' => (true, &trimmed[1..]),
2736 b'+' => (false, &trimmed[1..]),
2737 _ => (false, trimmed),
2738 };
2739 if body.is_empty() {
2740 return None;
2741 }
2742
2743 let mut parts = body.split('.');
2744 let int_part = parts.next().unwrap_or("");
2745 let frac_part = parts.next();
2746 if parts.next().is_some() {
2747 return None;
2748 }
2749
2750 let frac = frac_part.unwrap_or("");
2751 if int_part.is_empty() && frac.is_empty() {
2752 return None;
2753 }
2754 if !int_part.bytes().all(|b| b.is_ascii_digit()) || !frac.bytes().all(|b| b.is_ascii_digit()) {
2755 return None;
2756 }
2757
2758 let scale = u8::try_from(frac.len()).ok()?;
2759 if scale > MAX_DECIMAL_PRECISION {
2760 return None;
2761 }
2762
2763 let digits = format!("{int_part}{frac}");
2764 let normalized = digits.trim_start_matches('0');
2765 let precision_len = normalized.len().max(usize::from(scale)).max(1);
2766 if precision_len > MAX_DECIMAL_PRECISION as usize {
2767 return None;
2768 }
2769 let precision = precision_len as u8;
2770
2771 let magnitude = if normalized.is_empty() {
2772 0
2773 } else {
2774 normalized.parse::<i128>().ok()?
2775 };
2776 Some((
2777 if negative { -magnitude } else { magnitude },
2778 precision,
2779 scale,
2780 ))
2781}
2782
2783pub fn format_decimal_parts(unscaled: i128, scale: u8) -> String {
2784 if scale == 0 {
2785 return unscaled.to_string();
2786 }
2787
2788 let negative = unscaled.is_negative();
2789 let mut digits = unscaled.unsigned_abs().to_string();
2790 let scale_len = scale as usize;
2791 if digits.len() <= scale_len {
2792 let mut padded = String::with_capacity(scale_len + 1);
2793 padded.push_str(&"0".repeat(scale_len + 1 - digits.len()));
2794 padded.push_str(&digits);
2795 digits = padded;
2796 }
2797 let split = digits.len() - scale_len;
2798 let mut out = String::with_capacity(digits.len() + 2);
2799 if negative {
2800 out.push('-');
2801 }
2802 out.push_str(&digits[..split]);
2803 out.push('.');
2804 out.push_str(&digits[split..]);
2805 out
2806}
2807
2808#[doc(hidden)]
2809pub fn compare_decimal_parts(
2810 left_unscaled: i128,
2811 left_scale: u8,
2812 right_unscaled: i128,
2813 right_scale: u8,
2814) -> Ordering {
2815 DecimalIdentity::from_parts(left_unscaled, left_scale)
2816 .cmp_numeric(&DecimalIdentity::from_parts(right_unscaled, right_scale))
2817}
2818
2819pub fn parse_date_days_since_unix_epoch(s: &str) -> Option<i32> {
2820 let date = NaiveDate::parse_from_str(s.trim(), "%Y-%m-%d").ok()?;
2821 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1)?;
2822 i32::try_from(date.signed_duration_since(epoch).num_days()).ok()
2823}
2824
2825pub fn format_date_days_since_unix_epoch(days: i32) -> Option<String> {
2826 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1)?;
2827 epoch
2828 .checked_add_signed(chrono::Duration::days(days as i64))
2829 .map(|date| date.format("%Y-%m-%d").to_string())
2830}
2831
2832pub fn format_bytes_hex(data: &[u8]) -> String {
2833 const HEX: &[u8; 16] = b"0123456789abcdef";
2834 let mut out = String::with_capacity(2 + data.len() * 2);
2835 out.push_str("0x");
2836 for byte in data {
2837 out.push(HEX[(byte >> 4) as usize] as char);
2838 out.push(HEX[(byte & 0x0f) as usize] as char);
2839 }
2840 out
2841}
2842
2843pub fn parse_vector_str(s: &str) -> Option<Vec<f32>> {
2845 let s = s.trim();
2846 let inner = s.strip_prefix('[')?.strip_suffix(']')?;
2847 if inner.trim().is_empty() {
2848 return Some(Vec::new());
2849 }
2850 let mut result = Vec::new();
2851 for part in inner.split(',') {
2852 let val: f32 = part.trim().parse().ok()?;
2853 result.push(val);
2854 }
2855 Some(result)
2856}
2857
2858fn compare_floats(a: f64, b: f64) -> Ordering {
2860 match (a.is_nan(), b.is_nan()) {
2862 (true, true) => Ordering::Equal,
2863 (true, false) => Ordering::Greater,
2864 (false, true) => Ordering::Less,
2865 (false, false) => a.partial_cmp(&b).unwrap_or(Ordering::Equal),
2866 }
2867}
2868
2869#[cfg(test)]
2870mod tests;