1use std::cmp::Ordering;
21use std::fmt;
22use std::hash::{Hash, Hasher};
23use std::sync::Arc;
24
25use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, 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;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct ExternalValueRef<'a> {
39 type_ref: ExternalTypeRef,
40 payload: &'a [u8],
41}
42
43impl<'a> ExternalValueRef<'a> {
44 pub const fn type_ref(self) -> ExternalTypeRef {
45 self.type_ref
46 }
47
48 pub const fn payload(self) -> &'a [u8] {
49 self.payload
50 }
51}
52
53const TIMESTAMP_FORMATS: &[&str] = &[
56 "%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-%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", ];
70
71const TIME_FORMATS: &[&str] = &[
72 "%H:%M:%S%.f", "%H:%M:%S", "%H:%M", ];
76
77#[derive(Debug, Clone)]
99pub enum Value {
100 Null(DataType),
102
103 Integer(i64),
105
106 Float(f64),
108
109 Text(SmartString),
111
112 Boolean(bool),
114
115 Timestamp(DateTime<Utc>),
117
118 Extension(CompactArc<[u8]>),
123}
124
125pub const NULL_VALUE: Value = Value::Null(DataType::Null);
127
128impl Value {
129 #[inline]
135 pub fn null(data_type: DataType) -> Self {
136 Value::Null(data_type)
137 }
138
139 #[inline(always)]
141 pub fn null_unknown() -> Self {
142 Value::Null(DataType::Null)
143 }
144
145 pub fn integer(value: i64) -> Self {
147 Value::Integer(value)
148 }
149
150 pub fn float(value: f64) -> Self {
152 Value::Float(value)
153 }
154
155 pub fn text(value: impl Into<String>) -> Self {
161 Value::Text(SmartString::from_string_shared(value.into()))
162 }
163
164 pub fn text_arc(value: Arc<str>) -> Self {
168 Value::Text(SmartString::from(value))
169 }
170
171 pub fn boolean(value: bool) -> Self {
173 Value::Boolean(value)
174 }
175
176 pub fn timestamp(value: DateTime<Utc>) -> Self {
178 Value::Timestamp(value)
179 }
180
181 pub fn try_json(value: impl Into<String>) -> Result<Self> {
183 let value = value.into();
184 serde_json::from_str::<serde_json::Value>(&value)
185 .map_err(|error| Error::invalid_argument(format!("invalid JSON value: {error}")))?;
186 Ok(Self::json_unchecked(value))
187 }
188
189 fn json_unchecked(value: impl Into<String>) -> Self {
191 let s_bytes = value.into().into_bytes();
192 let mut bytes = Vec::with_capacity(1 + s_bytes.len());
193 bytes.push(DataType::Json as u8);
194 bytes.extend_from_slice(&s_bytes);
195 Value::Extension(CompactArc::from(bytes))
196 }
197
198 #[inline]
199 #[doc(hidden)]
200 pub fn json(value: impl Into<String>) -> Self {
201 Self::json_unchecked(value)
202 }
203
204 pub fn vector(data: Vec<f32>) -> Self {
206 let mut bytes = Vec::with_capacity(1 + data.len() * 4);
207 bytes.push(DataType::Vector as u8);
208 for f in &data {
209 bytes.extend_from_slice(&f.to_le_bytes());
210 }
211 Value::Extension(CompactArc::from(bytes))
212 }
213
214 pub fn try_vector_from_bytes(raw_f32_bytes: CompactArc<[u8]>) -> Result<Self> {
216 if !raw_f32_bytes
217 .len()
218 .is_multiple_of(std::mem::size_of::<f32>())
219 {
220 return Err(Error::invalid_argument(format!(
221 "VECTOR payload has {} bytes, expected a multiple of 4",
222 raw_f32_bytes.len()
223 )));
224 }
225 Ok(Self::vector_from_bytes_unchecked(raw_f32_bytes))
226 }
227
228 fn vector_from_bytes_unchecked(raw_f32_bytes: CompactArc<[u8]>) -> Self {
229 let mut bytes = Vec::with_capacity(1 + raw_f32_bytes.len());
230 bytes.push(DataType::Vector as u8);
231 bytes.extend_from_slice(&raw_f32_bytes);
232 Value::Extension(CompactArc::from(bytes))
233 }
234
235 pub fn uuid(bytes: [u8; 16]) -> Self {
237 let mut data = Vec::with_capacity(17);
238 data.push(DataType::Uuid as u8);
239 data.extend_from_slice(&bytes);
240 Value::Extension(CompactArc::from(data))
241 }
242
243 pub fn uuid_v7() -> Self {
248 Value::uuid(*Uuid::now_v7().as_bytes())
249 }
250
251 pub fn try_decimal(unscaled: i128, precision: u8, scale: u8) -> Result<Self> {
259 validate_decimal_shape(unscaled, precision, scale)?;
260 Ok(Self::decimal_unchecked(unscaled, precision, scale))
261 }
262
263 fn decimal_unchecked(unscaled: i128, precision: u8, scale: u8) -> Self {
264 let mut data = Vec::with_capacity(19);
265 data.push(DataType::Decimal as u8);
266 data.extend_from_slice(&unscaled.to_le_bytes());
267 data.push(precision);
268 data.push(scale);
269 Value::Extension(CompactArc::from(data))
270 }
271
272 #[inline]
273 #[doc(hidden)]
274 pub fn decimal(unscaled: i128, precision: u8, scale: u8) -> Self {
275 Self::decimal_unchecked(unscaled, precision, scale)
276 }
277
278 pub fn date(days_since_unix_epoch: i32) -> Self {
280 let mut data = Vec::with_capacity(5);
281 data.push(DataType::Date as u8);
282 data.extend_from_slice(&days_since_unix_epoch.to_le_bytes());
283 Value::Extension(CompactArc::from(data))
284 }
285
286 pub fn bytes(bytes: Vec<u8>) -> Self {
288 let mut data = Vec::with_capacity(1 + bytes.len());
289 data.push(DataType::Bytes as u8);
290 data.extend_from_slice(&bytes);
291 Value::Extension(CompactArc::from(data))
292 }
293
294 pub fn try_external(type_ref: ExternalTypeRef, payload: impl AsRef<[u8]>) -> Result<Self> {
300 let payload = payload.as_ref();
301 if payload.len() > MAX_EXTERNAL_VALUE_BYTES {
302 return Err(Error::invalid_argument(format!(
303 "external value payload has {} bytes, limit is {}",
304 payload.len(),
305 MAX_EXTERNAL_VALUE_BYTES
306 )));
307 }
308 let mut data = Vec::with_capacity(EXTERNAL_VALUE_HEADER_BYTES + payload.len());
309 data.push(EXTERNAL_VALUE_MARKER);
310 data.extend_from_slice(&type_ref.type_object_id());
311 data.extend_from_slice(&type_ref.codec_version().to_le_bytes());
312 data.extend_from_slice(payload);
313 Ok(Value::Extension(CompactArc::from(data)))
314 }
315
316 pub fn data_type(&self) -> DataType {
322 match self {
323 Value::Null(dt) => *dt,
324 Value::Integer(_) => DataType::Integer,
325 Value::Float(_) => DataType::Float,
326 Value::Text(_) => DataType::Text,
327 Value::Boolean(_) => DataType::Boolean,
328 Value::Timestamp(_) => DataType::Timestamp,
329 Value::Extension(data) => data
330 .first()
331 .and_then(|&b| DataType::from_u8(b))
332 .unwrap_or(DataType::Null),
333 }
334 }
335
336 pub fn logical_type(&self) -> LogicalTypeRef {
338 self.as_external()
339 .map(|value| LogicalTypeRef::External(value.type_ref()))
340 .unwrap_or_else(|| LogicalTypeRef::Builtin(self.data_type()))
341 }
342
343 #[inline]
348 pub fn is_external(&self) -> bool {
349 matches!(self, Value::Extension(data) if data.first() == Some(&EXTERNAL_VALUE_MARKER))
350 }
351
352 pub fn as_external(&self) -> Option<ExternalValueRef<'_>> {
354 let Value::Extension(data) = self else {
355 return None;
356 };
357 if data.first() != Some(&EXTERNAL_VALUE_MARKER) || data.len() < EXTERNAL_VALUE_HEADER_BYTES
358 {
359 return None;
360 }
361 let type_object_id = data[1..17].try_into().ok()?;
362 let codec_version = u32::from_le_bytes(data[17..21].try_into().ok()?);
363 let type_ref = ExternalTypeRef::new(type_object_id, codec_version).ok()?;
364 Some(ExternalValueRef {
365 type_ref,
366 payload: &data[EXTERNAL_VALUE_HEADER_BYTES..],
367 })
368 }
369
370 pub fn validate_shape(&self) -> Result<()> {
373 let Value::Extension(data) = self else {
374 return Ok(());
375 };
376 if data.first() == Some(&EXTERNAL_VALUE_MARKER) {
377 let external = self.as_external().ok_or_else(|| {
378 Error::invalid_argument("external value has an invalid typed envelope")
379 })?;
380 if external.payload().len() > MAX_EXTERNAL_VALUE_BYTES {
381 return Err(Error::invalid_argument(
382 "external value payload exceeds 16 MiB",
383 ));
384 }
385 return Ok(());
386 }
387 let Some(tag) = data.first().and_then(|tag| DataType::from_u8(*tag)) else {
388 return Err(Error::invalid_argument(
389 "extension value has an unknown or missing tag",
390 ));
391 };
392 Self::validate_extension_payload(tag, &data[1..])
393 }
394
395 #[doc(hidden)]
397 pub fn validate_extension_payload(tag: DataType, payload: &[u8]) -> Result<()> {
398 match tag {
399 DataType::Json => {
400 let json = std::str::from_utf8(payload).map_err(|error| {
401 Error::invalid_argument(format!("invalid JSON UTF-8: {error}"))
402 })?;
403 serde_json::from_str::<serde_json::Value>(json).map_err(|error| {
404 Error::invalid_argument(format!("invalid JSON document: {error}"))
405 })?;
406 }
407 DataType::Vector => {
408 if !payload.len().is_multiple_of(std::mem::size_of::<f32>()) {
409 return Err(Error::invalid_argument(format!(
410 "VECTOR payload has {} bytes, expected a multiple of 4",
411 payload.len()
412 )));
413 }
414 }
415 DataType::Uuid => {
416 if payload.len() != 16 {
417 return Err(Error::invalid_argument(
418 "UUID payload must contain exactly 16 bytes",
419 ));
420 }
421 }
422 DataType::Decimal => {
423 if payload.len() != 18 {
424 return Err(Error::invalid_argument(
425 "DECIMAL payload must contain exactly 18 bytes",
426 ));
427 }
428 let unscaled = i128::from_le_bytes(
429 payload[..16]
430 .try_into()
431 .map_err(|_| Error::invalid_argument("invalid DECIMAL coefficient"))?,
432 );
433 validate_decimal_shape(unscaled, payload[16], payload[17])?;
434 }
435 DataType::Date => {
436 if payload.len() != 4 {
437 return Err(Error::invalid_argument(
438 "DATE payload must contain exactly 4 bytes",
439 ));
440 }
441 }
442 DataType::Bytes => {}
443 _ => {
444 return Err(Error::invalid_argument(format!(
445 "data type {tag} is not a valid extension payload tag"
446 )));
447 }
448 }
449 Ok(())
450 }
451
452 #[inline(always)]
454 pub fn is_null(&self) -> bool {
455 matches!(self, Value::Null(_))
456 }
457
458 pub fn as_int64(&self) -> Option<i64> {
468 match self {
469 Value::Null(_) => None,
470 Value::Integer(v) => Some(*v),
471 Value::Float(v) => checked_float_to_i64(*v),
472 Value::Text(s) => parse_text_to_i64(s),
473 Value::Boolean(b) => Some(if *b { 1 } else { 0 }),
474 Value::Timestamp(t) => t.timestamp_nanos_opt(),
475 Value::Extension(_) => None,
476 }
477 }
478
479 #[doc(hidden)]
486 pub fn exact_integer_identity(&self) -> Option<i64> {
487 match self {
488 Value::Integer(integer) => Some(*integer),
489 Value::Float(float) if float.is_finite() && float.fract() == 0.0 => {
490 let integer = *float as i64;
491 (Value::Integer(integer) == *self).then_some(integer)
492 }
493 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
494 let (unscaled, _, scale) = self.as_decimal_parts()?;
495 DecimalIdentity::from_parts(unscaled, scale).exact_i64()
496 }
497 _ => None,
498 }
499 }
500
501 pub fn as_float64(&self) -> Option<f64> {
503 match self {
504 Value::Null(_) => None,
505 Value::Integer(v) => Some(*v as f64),
506 Value::Float(v) => Some(*v),
507 Value::Text(s) => s.parse::<f64>().ok(),
508 Value::Boolean(b) => Some(if *b { 1.0 } else { 0.0 }),
509 Value::Timestamp(_) | Value::Extension(_) => None,
510 }
511 }
512
513 pub fn as_boolean(&self) -> Option<bool> {
515 match self {
516 Value::Null(_) => None,
517 Value::Integer(v) => Some(*v != 0),
518 Value::Float(v) => Some(*v != 0.0),
519 Value::Text(s) => {
520 let s_ref: &str = s.as_ref();
522 if s_ref.eq_ignore_ascii_case("true")
523 || s_ref.eq_ignore_ascii_case("t")
524 || s_ref.eq_ignore_ascii_case("yes")
525 || s_ref.eq_ignore_ascii_case("y")
526 || s_ref == "1"
527 {
528 Some(true)
529 } else if s_ref.eq_ignore_ascii_case("false")
530 || s_ref.eq_ignore_ascii_case("f")
531 || s_ref.eq_ignore_ascii_case("no")
532 || s_ref.eq_ignore_ascii_case("n")
533 || s_ref == "0"
534 || s_ref.is_empty()
535 {
536 Some(false)
537 } else {
538 s_ref.parse::<f64>().ok().map(|f| f != 0.0)
539 }
540 }
541 Value::Boolean(b) => Some(*b),
542 Value::Timestamp(_) | Value::Extension(_) => None,
543 }
544 }
545
546 pub fn as_string(&self) -> Option<String> {
548 match self {
549 Value::Null(_) => None,
550 Value::Integer(v) => Some(v.to_string()),
551 Value::Float(v) => Some(format_float(*v)),
552 Value::Text(s) => Some(s.to_string()),
553 Value::Boolean(b) => Some(if *b { "true" } else { "false" }.to_string()),
554 Value::Timestamp(t) => Some(t.to_rfc3339()),
555 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
556 Some(std::str::from_utf8(&data[1..]).unwrap_or("").to_string())
558 }
559 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
560 Some(format_vector_bytes(&data[1..]))
561 }
562 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
563 format_uuid_bytes(&data[1..])
564 }
565 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => self
566 .as_decimal_parts()
567 .map(|(unscaled, _, scale)| format_decimal_parts(unscaled, scale)),
568 Value::Extension(data) if data.first() == Some(&(DataType::Date as u8)) => self
569 .as_date_days()
570 .and_then(format_date_days_since_unix_epoch),
571 Value::Extension(data) if data.first() == Some(&(DataType::Bytes as u8)) => {
572 Some(format_bytes_hex(&data[1..]))
573 }
574 Value::Extension(data) => {
575 if data.len() > 1 {
577 std::str::from_utf8(&data[1..]).ok().map(|s| s.to_string())
578 } else {
579 None
580 }
581 }
582 }
583 }
584
585 pub fn as_str(&self) -> Option<&str> {
587 match self {
588 Value::Text(s) => Some(s.as_str()),
589 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
590 let json = std::str::from_utf8(&data[1..]).ok()?;
591 serde_json::from_str::<serde_json::Value>(json).ok()?;
592 Some(json)
593 }
594 _ => None,
595 }
596 }
597
598 pub fn as_timestamp(&self) -> Option<DateTime<Utc>> {
600 match self {
601 Value::Null(_) => None,
602 Value::Timestamp(t) => Some(*t),
603 Value::Text(s) => parse_timestamp(s).ok(),
604 Value::Integer(nanos) => {
605 datetime_from_epoch_nanos(*nanos)
607 }
608 _ => None,
609 }
610 }
611
612 #[inline]
618 #[doc(hidden)]
619 pub fn artifact_timestamp_nanos(&self) -> Option<i64> {
620 match self {
621 Value::Timestamp(timestamp) => timestamp.timestamp_nanos_opt(),
622 _ => None,
623 }
624 }
625
626 pub fn as_json(&self) -> Option<&str> {
628 match self {
629 Value::Null(_) => None,
630 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
632 let json = std::str::from_utf8(&data[1..]).ok()?;
633 serde_json::from_str::<serde_json::Value>(json).ok()?;
634 Some(json)
635 }
636 _ => None,
637 }
638 }
639
640 pub fn as_vector_f32(&self) -> Option<Vec<f32>> {
642 match self {
643 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
644 let payload = &data[1..];
645 if payload.len() % std::mem::size_of::<f32>() != 0 {
646 return None;
647 }
648 let len = payload.len() / 4;
649 let mut result = Vec::with_capacity(len);
650 for i in 0..len {
651 let bytes = [
652 payload[i * 4],
653 payload[i * 4 + 1],
654 payload[i * 4 + 2],
655 payload[i * 4 + 3],
656 ];
657 result.push(f32::from_le_bytes(bytes));
658 }
659 Some(result)
660 }
661 _ => None,
662 }
663 }
664
665 pub fn as_uuid_bytes(&self) -> Option<[u8; 16]> {
667 match self {
668 Value::Extension(data)
669 if data.first() == Some(&(DataType::Uuid as u8)) && data.len() == 17 =>
670 {
671 data[1..].try_into().ok()
672 }
673 _ => None,
674 }
675 }
676
677 pub fn as_decimal_parts(&self) -> Option<(i128, u8, u8)> {
679 match self {
680 Value::Extension(data)
681 if data.first() == Some(&(DataType::Decimal as u8)) && data.len() == 19 =>
682 {
683 let unscaled = i128::from_le_bytes(data[1..17].try_into().ok()?);
684 validate_decimal_shape(unscaled, data[17], data[18]).ok()?;
685 Some((unscaled, data[17], data[18]))
686 }
687 _ => None,
688 }
689 }
690
691 pub fn as_date_days(&self) -> Option<i32> {
693 match self {
694 Value::Extension(data)
695 if data.first() == Some(&(DataType::Date as u8)) && data.len() == 5 =>
696 {
697 Some(i32::from_le_bytes(data[1..5].try_into().ok()?))
698 }
699 _ => None,
700 }
701 }
702
703 pub fn as_bytes_value(&self) -> Option<&[u8]> {
705 match self {
706 Value::Extension(data) if data.first() == Some(&(DataType::Bytes as u8)) => {
707 Some(&data[1..])
708 }
709 _ => None,
710 }
711 }
712
713 pub fn compare(&self, other: &Value) -> Result<Ordering> {
725 if self.is_null() || other.is_null() {
727 if self.is_null() && other.is_null() {
728 return Ok(Ordering::Equal);
729 }
730 return Err(Error::NullComparison);
731 }
732
733 if let Some(ordering) = compare_canonical_numeric(self, other) {
737 return Ok(ordering);
738 }
739
740 if self.data_type() == other.data_type() {
742 return self.compare_same_type(other);
743 }
744
745 Err(Error::IncomparableTypes)
747 }
748
749 fn compare_same_type(&self, other: &Value) -> Result<Ordering> {
751 match (self, other) {
752 (Value::Integer(a), Value::Integer(b)) => Ok(a.cmp(b)),
753 (Value::Float(a), Value::Float(b)) => Ok(compare_floats(*a, *b)),
754 (Value::Text(a), Value::Text(b)) => Ok(a.cmp(b)),
755 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
756 (Value::Timestamp(a), Value::Timestamp(b)) => Ok(a.cmp(b)),
757 (Value::Extension(a), Value::Extension(b)) => {
758 if a.first() == Some(&EXTERNAL_VALUE_MARKER)
762 || b.first() == Some(&EXTERNAL_VALUE_MARKER)
763 {
764 return Err(Error::IncomparableTypes);
765 }
766 if a.first() != b.first() {
768 return Err(Error::IncomparableTypes);
769 }
770 if a.first() == Some(&(DataType::Uuid as u8)) {
771 return if a.len() == 17 && b.len() == 17 {
772 Ok(a[1..].cmp(&b[1..]))
773 } else {
774 Err(Error::IncomparableTypes)
775 };
776 }
777 if a.first() == Some(&(DataType::Decimal as u8)) {
778 return match (self.as_decimal_parts(), other.as_decimal_parts()) {
779 (
780 Some((left_unscaled, _, left_scale)),
781 Some((right_unscaled, _, right_scale)),
782 ) => Ok(compare_decimal_parts(
783 left_unscaled,
784 left_scale,
785 right_unscaled,
786 right_scale,
787 )),
788 _ => Err(Error::IncomparableTypes),
789 };
790 }
791 if a.first() == Some(&(DataType::Date as u8)) {
792 return match (self.as_date_days(), other.as_date_days()) {
793 (Some(left), Some(right)) => Ok(left.cmp(&right)),
794 _ => Err(Error::IncomparableTypes),
795 };
796 }
797 if a.first() == Some(&(DataType::Bytes as u8)) {
798 return Ok(a[1..].cmp(&b[1..]));
799 }
800 if a == b {
802 Ok(Ordering::Equal)
803 } else {
804 Err(Error::IncomparableTypes)
805 }
806 }
807 _ => Err(Error::IncomparableTypes),
808 }
809 }
810
811 pub fn from_typed(value: Option<&dyn std::any::Any>, data_type: DataType) -> Result<Self> {
817 let has_value = value.is_some();
818 let result = match value {
819 None => Value::Null(data_type),
820 Some(v) => {
821 match data_type {
823 DataType::Integer => {
824 if let Some(&i) = v.downcast_ref::<i64>() {
825 Value::Integer(i)
826 } else if let Some(&i) = v.downcast_ref::<i32>() {
827 Value::Integer(i as i64)
828 } else if let Some(s) = v.downcast_ref::<String>() {
829 s.parse::<i64>()
830 .map(Value::Integer)
831 .unwrap_or(Value::Null(data_type))
832 } else {
833 Value::Null(data_type)
834 }
835 }
836 DataType::Float => {
837 if let Some(&f) = v.downcast_ref::<f64>() {
838 Value::Float(f)
839 } else if let Some(&i) = v.downcast_ref::<i64>() {
840 Value::Float(i as f64)
841 } else if let Some(s) = v.downcast_ref::<String>() {
842 s.parse::<f64>()
843 .map(Value::Float)
844 .unwrap_or(Value::Null(data_type))
845 } else {
846 Value::Null(data_type)
847 }
848 }
849 DataType::Text => {
850 if let Some(s) = v.downcast_ref::<String>() {
851 Value::Text(SmartString::new(s))
852 } else if let Some(&s) = v.downcast_ref::<&str>() {
853 Value::Text(SmartString::from(s))
854 } else {
855 Value::Null(data_type)
856 }
857 }
858 DataType::Boolean => {
859 if let Some(&b) = v.downcast_ref::<bool>() {
860 Value::Boolean(b)
861 } else if let Some(&i) = v.downcast_ref::<i64>() {
862 Value::Boolean(i != 0)
863 } else {
864 Value::Null(data_type)
865 }
866 }
867 DataType::Timestamp => {
868 if let Some(&t) = v.downcast_ref::<DateTime<Utc>>() {
869 Value::Timestamp(t)
870 } else if let Some(s) = v.downcast_ref::<String>() {
871 parse_timestamp(s)
872 .map(Value::Timestamp)
873 .unwrap_or(Value::Null(data_type))
874 } else {
875 Value::Null(data_type)
876 }
877 }
878 DataType::Json => {
879 if let Some(s) = v.downcast_ref::<String>() {
880 if serde_json::from_str::<serde_json::Value>(s).is_ok() {
882 Value::json_unchecked(s)
883 } else {
884 Value::Null(data_type)
885 }
886 } else {
887 Value::Null(data_type)
888 }
889 }
890 DataType::Uuid => {
891 if let Some(&bytes) = v.downcast_ref::<[u8; 16]>() {
892 Value::uuid(bytes)
893 } else if let Some(s) = v.downcast_ref::<String>() {
894 parse_uuid_str(s)
895 .map(Value::uuid)
896 .unwrap_or(Value::Null(data_type))
897 } else if let Some(&s) = v.downcast_ref::<&str>() {
898 parse_uuid_str(s)
899 .map(Value::uuid)
900 .unwrap_or(Value::Null(data_type))
901 } else {
902 Value::Null(data_type)
903 }
904 }
905 DataType::Vector => {
906 if let Some(vec) = v.downcast_ref::<Vec<f32>>() {
907 Value::vector(vec.clone())
908 } else {
909 Value::Null(data_type)
910 }
911 }
912 DataType::Decimal => {
913 if let Some(&(unscaled, precision, scale)) =
914 v.downcast_ref::<(i128, u8, u8)>()
915 {
916 Value::decimal_unchecked(unscaled, precision, scale)
917 } else if let Some(&i) = v.downcast_ref::<i64>() {
918 Value::decimal_unchecked(
919 i as i128,
920 decimal_precision_for_unscaled(i),
921 0,
922 )
923 } else if let Some(s) = v.downcast_ref::<String>() {
924 parse_decimal_str(s)
925 .map(|(unscaled, precision, scale)| {
926 Value::decimal_unchecked(unscaled, precision, scale)
927 })
928 .unwrap_or(Value::Null(data_type))
929 } else if let Some(&s) = v.downcast_ref::<&str>() {
930 parse_decimal_str(s)
931 .map(|(unscaled, precision, scale)| {
932 Value::decimal_unchecked(unscaled, precision, scale)
933 })
934 .unwrap_or(Value::Null(data_type))
935 } else {
936 Value::Null(data_type)
937 }
938 }
939 DataType::Date => {
940 if let Some(&days) = v.downcast_ref::<i32>() {
941 Value::date(days)
942 } else if let Some(s) = v.downcast_ref::<String>() {
943 parse_date_days_since_unix_epoch(s)
944 .map(Value::date)
945 .unwrap_or(Value::Null(data_type))
946 } else if let Some(&s) = v.downcast_ref::<&str>() {
947 parse_date_days_since_unix_epoch(s)
948 .map(Value::date)
949 .unwrap_or(Value::Null(data_type))
950 } else {
951 Value::Null(data_type)
952 }
953 }
954 DataType::Bytes => {
955 if let Some(bytes) = v.downcast_ref::<Vec<u8>>() {
956 Value::bytes(bytes.clone())
957 } else if let Some(s) = v.downcast_ref::<String>() {
958 Value::bytes(s.as_bytes().to_vec())
959 } else if let Some(&s) = v.downcast_ref::<&str>() {
960 Value::bytes(s.as_bytes().to_vec())
961 } else {
962 Value::Null(data_type)
963 }
964 }
965 DataType::Null => Value::Null(DataType::Null),
966 }
967 }
968 };
969 result.validate_shape()?;
970 if has_value && result.is_null() && data_type != DataType::Null {
971 return Err(Error::type_conversion("typed value", data_type.to_string()));
972 }
973 Ok(result)
974 }
975
976 pub fn coerce_to_type(&self, target_type: DataType) -> Value {
992 if self.is_null() {
994 return Value::Null(target_type);
995 }
996
997 if self.validate_shape().is_err() {
998 return Value::Null(target_type);
999 }
1000
1001 if self.data_type() == target_type {
1003 return self.clone();
1004 }
1005
1006 match target_type {
1007 DataType::Integer => {
1008 match self {
1010 Value::Integer(v) => Value::Integer(*v),
1011 Value::Float(v) => checked_float_to_i64(*v)
1012 .map(Value::Integer)
1013 .unwrap_or(Value::Null(target_type)),
1014 Value::Text(s) => parse_text_to_i64(s)
1015 .map(Value::Integer)
1016 .unwrap_or(Value::Null(target_type)),
1017 Value::Boolean(b) => Value::Integer(if *b { 1 } else { 0 }),
1018 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1019 self.as_decimal_parts()
1020 .and_then(|(unscaled, _, scale)| {
1021 decimal_scale_factor(scale)
1022 .and_then(|factor| i64::try_from(unscaled / factor).ok())
1023 })
1024 .map(Value::Integer)
1025 .unwrap_or(Value::Null(target_type))
1026 }
1027 _ => Value::Null(target_type),
1028 }
1029 }
1030 DataType::Float => {
1031 match self {
1033 Value::Float(v) => Value::Float(*v),
1034 Value::Integer(v) => Value::Float(*v as f64),
1035 Value::Text(s) => s
1036 .parse::<f64>()
1037 .map(Value::Float)
1038 .unwrap_or(Value::Null(target_type)),
1039 Value::Boolean(b) => Value::Float(if *b { 1.0 } else { 0.0 }),
1040 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1041 self.as_string()
1042 .and_then(|value| value.parse::<f64>().ok())
1043 .map(Value::Float)
1044 .unwrap_or(Value::Null(target_type))
1045 }
1046 _ => Value::Null(target_type),
1047 }
1048 }
1049 DataType::Text => {
1050 match self {
1052 Value::Text(s) => Value::Text(s.clone()),
1053 Value::Integer(v) => Value::Text(SmartString::from_string(v.to_string())),
1054 Value::Float(v) => Value::Text(SmartString::from_string(format_float(*v))),
1055 Value::Boolean(b) => {
1056 Value::Text(SmartString::new(if *b { "true" } else { "false" }))
1057 }
1058 Value::Timestamp(t) => Value::Text(SmartString::from_string(t.to_rfc3339())),
1059 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
1060 Value::Text(SmartString::new(
1061 std::str::from_utf8(&data[1..]).unwrap_or(""),
1062 ))
1063 }
1064 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
1065 Value::Text(SmartString::from_string(format_vector_bytes(&data[1..])))
1066 }
1067 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1068 format_uuid_bytes(&data[1..])
1069 .map(|s| Value::Text(SmartString::from_string(s)))
1070 .unwrap_or(Value::Null(target_type))
1071 }
1072 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1073 self.as_string()
1074 .map(|value| Value::Text(SmartString::from_string(value)))
1075 .unwrap_or(Value::Null(target_type))
1076 }
1077 Value::Extension(_) => Value::Null(target_type),
1078 Value::Null(_) => Value::Null(target_type),
1079 }
1080 }
1081 DataType::Boolean => {
1082 match self {
1084 Value::Boolean(b) => Value::Boolean(*b),
1085 Value::Integer(v) => Value::Boolean(*v != 0),
1086 Value::Float(v) => Value::Boolean(*v != 0.0),
1087 Value::Text(s) => {
1088 let s_ref: &str = s.as_ref();
1090 if s_ref.eq_ignore_ascii_case("true")
1091 || s_ref.eq_ignore_ascii_case("t")
1092 || s_ref.eq_ignore_ascii_case("yes")
1093 || s_ref.eq_ignore_ascii_case("y")
1094 || s_ref == "1"
1095 {
1096 Value::Boolean(true)
1097 } else if s_ref.eq_ignore_ascii_case("false")
1098 || s_ref.eq_ignore_ascii_case("f")
1099 || s_ref.eq_ignore_ascii_case("no")
1100 || s_ref.eq_ignore_ascii_case("n")
1101 || s_ref == "0"
1102 {
1103 Value::Boolean(false)
1104 } else {
1105 Value::Null(target_type)
1106 }
1107 }
1108 _ => Value::Null(target_type),
1109 }
1110 }
1111 DataType::Timestamp => {
1112 match self {
1114 Value::Timestamp(t) => Value::Timestamp(*t),
1115 Value::Extension(data)
1116 if data.first() == Some(&(DataType::Date as u8)) && data.len() == 5 =>
1117 {
1118 self.as_date_days()
1119 .and_then(|days| {
1120 NaiveDate::from_ymd_opt(1970, 1, 1)?
1121 .checked_add_signed(chrono::Duration::days(i64::from(days)))?
1122 .and_hms_opt(0, 0, 0)
1123 })
1124 .map(|value| {
1125 Value::Timestamp(DateTime::<Utc>::from_naive_utc_and_offset(
1126 value, Utc,
1127 ))
1128 })
1129 .unwrap_or(Value::Null(target_type))
1130 }
1131 Value::Text(s) => parse_timestamp(s)
1132 .map(Value::Timestamp)
1133 .unwrap_or(Value::Null(target_type)),
1134 Value::Integer(nanos) => {
1135 datetime_from_epoch_nanos(*nanos)
1137 .map(Value::Timestamp)
1138 .unwrap_or(Value::Null(target_type))
1139 }
1140 _ => Value::Null(target_type),
1141 }
1142 }
1143 DataType::Json => {
1144 match self {
1146 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
1147 self.clone()
1148 }
1149 Value::Text(s) => {
1150 if serde_json::from_str::<serde_json::Value>(s.as_str()).is_ok() {
1152 Value::json_unchecked(s.as_str())
1153 } else {
1154 Value::Null(target_type)
1155 }
1156 }
1157 Value::Integer(v) => Value::json_unchecked(v.to_string()),
1159 Value::Float(v) if v.is_finite() => Value::json_unchecked(format_float(*v)),
1160 Value::Boolean(b) => Value::json_unchecked(if *b { "true" } else { "false" }),
1161 Value::Timestamp(timestamp) => {
1162 Value::json_unchecked(format!("\"{}\"", timestamp.to_rfc3339()))
1163 }
1164 _ => Value::Null(target_type),
1165 }
1166 }
1167 DataType::Vector => match self {
1168 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
1169 self.clone()
1170 }
1171 Value::Text(s) => {
1172 if let Some(floats) = parse_vector_str(s.as_str()) {
1173 Value::vector(floats)
1174 } else {
1175 Value::Null(target_type)
1176 }
1177 }
1178 _ => Value::Null(target_type),
1179 },
1180 DataType::Uuid => match self {
1181 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1182 if data.len() == 17 {
1183 self.clone()
1184 } else {
1185 Value::Null(target_type)
1186 }
1187 }
1188 Value::Text(s) => parse_uuid_str(s.as_str())
1189 .map(Value::uuid)
1190 .unwrap_or(Value::Null(target_type)),
1191 _ => Value::Null(target_type),
1192 },
1193 DataType::Decimal => match self {
1194 Value::Extension(data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1195 if self.as_decimal_parts().is_some() {
1196 self.clone()
1197 } else {
1198 Value::Null(target_type)
1199 }
1200 }
1201 Value::Integer(value) => {
1202 let digits = decimal_precision_for_unscaled(*value);
1203 Value::decimal_unchecked(*value as i128, digits, 0)
1204 }
1205 Value::Float(value) => parse_decimal_f64(*value)
1206 .map(|(unscaled, precision, scale)| {
1207 Value::decimal_unchecked(unscaled, precision, scale)
1208 })
1209 .unwrap_or(Value::Null(target_type)),
1210 Value::Text(s) => parse_decimal_str(s.as_str())
1211 .map(|(unscaled, precision, scale)| {
1212 Value::decimal_unchecked(unscaled, precision, scale)
1213 })
1214 .unwrap_or(Value::Null(target_type)),
1215 _ => Value::Null(target_type),
1216 },
1217 DataType::Date => match self {
1218 Value::Extension(data) if data.first() == Some(&(DataType::Date as u8)) => {
1219 if data.len() == 5 {
1220 self.clone()
1221 } else {
1222 Value::Null(target_type)
1223 }
1224 }
1225 Value::Text(s) => parse_date_days_since_unix_epoch(s.as_str())
1226 .map(Value::date)
1227 .unwrap_or(Value::Null(target_type)),
1228 Value::Timestamp(timestamp) => {
1229 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1)
1230 .expect("Unix epoch is a valid calendar date");
1231 i32::try_from(
1232 timestamp
1233 .date_naive()
1234 .signed_duration_since(epoch)
1235 .num_days(),
1236 )
1237 .map(Value::date)
1238 .unwrap_or(Value::Null(target_type))
1239 }
1240 _ => Value::Null(target_type),
1241 },
1242 DataType::Bytes => match self {
1243 Value::Extension(data) if data.first() == Some(&(DataType::Bytes as u8)) => {
1244 self.clone()
1245 }
1246 Value::Text(s) => Value::bytes(s.as_bytes().to_vec()),
1247 _ => Value::Null(target_type),
1248 },
1249 DataType::Null => Value::Null(DataType::Null),
1250 }
1251 }
1252
1253 pub fn try_coerce_to_type(&self, target_type: DataType) -> Result<Value> {
1261 self.validate_shape()?;
1262 let coerced = self.coerce_to_type(target_type);
1263 if !self.is_null() && coerced.is_null() && target_type != DataType::Null {
1264 return Err(Error::Type(format!(
1265 "cannot convert value '{}' from {:?} to {:?}",
1266 self,
1267 self.data_type(),
1268 target_type
1269 )));
1270 }
1271 Ok(coerced)
1272 }
1273
1274 #[inline]
1277 pub fn into_coerce_to_type(self, target_type: DataType) -> Value {
1278 if self.is_null() {
1280 return Value::Null(target_type);
1281 }
1282
1283 if self.validate_shape().is_err() {
1284 return Value::Null(target_type);
1285 }
1286
1287 if self.data_type() == target_type {
1289 return self;
1290 }
1291
1292 match target_type {
1293 DataType::Integer => match &self {
1294 Value::Integer(v) => Value::Integer(*v),
1295 Value::Float(v) => checked_float_to_i64(*v)
1296 .map(Value::Integer)
1297 .unwrap_or(Value::Null(target_type)),
1298 Value::Text(s) => parse_text_to_i64(s)
1299 .map(Value::Integer)
1300 .unwrap_or(Value::Null(target_type)),
1301 Value::Boolean(b) => Value::Integer(if *b { 1 } else { 0 }),
1302 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1303 self.as_decimal_parts()
1304 .and_then(|(unscaled, _, scale)| {
1305 decimal_scale_factor(scale)
1306 .and_then(|factor| i64::try_from(unscaled / factor).ok())
1307 })
1308 .map(Value::Integer)
1309 .unwrap_or(Value::Null(target_type))
1310 }
1311 _ => Value::Null(target_type),
1312 },
1313 DataType::Float => match &self {
1314 Value::Float(v) => Value::Float(*v),
1315 Value::Integer(v) => Value::Float(*v as f64),
1316 Value::Text(s) => s
1317 .parse::<f64>()
1318 .map(Value::Float)
1319 .unwrap_or(Value::Null(target_type)),
1320 Value::Boolean(b) => Value::Float(if *b { 1.0 } else { 0.0 }),
1321 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1322 self.as_string()
1323 .and_then(|value| value.parse::<f64>().ok())
1324 .map(Value::Float)
1325 .unwrap_or(Value::Null(target_type))
1326 }
1327 _ => Value::Null(target_type),
1328 },
1329 DataType::Text => match self {
1330 Value::Text(s) => Value::Text(s),
1331 Value::Integer(v) => Value::Text(SmartString::from_string(v.to_string())),
1332 Value::Float(v) => Value::Text(SmartString::from_string(format_float(v))),
1333 Value::Boolean(b) => {
1334 Value::Text(SmartString::new(if b { "true" } else { "false" }))
1335 }
1336 Value::Timestamp(t) => Value::Text(SmartString::from_string(t.to_rfc3339())),
1337 Value::Extension(data) if data.first() == Some(&(DataType::Json as u8)) => {
1338 Value::Text(SmartString::new(
1339 std::str::from_utf8(&data[1..]).unwrap_or(""),
1340 ))
1341 }
1342 Value::Extension(data) if data.first() == Some(&(DataType::Vector as u8)) => {
1343 Value::Text(SmartString::from_string(format_vector_bytes(&data[1..])))
1344 }
1345 Value::Extension(data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1346 format_uuid_bytes(&data[1..])
1347 .map(|s| Value::Text(SmartString::from_string(s)))
1348 .unwrap_or(Value::Null(target_type))
1349 }
1350 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1351 self.as_string()
1352 .map(|value| Value::Text(SmartString::from_string(value)))
1353 .unwrap_or(Value::Null(target_type))
1354 }
1355 Value::Extension(_) | Value::Null(_) => Value::Null(target_type),
1356 },
1357 DataType::Boolean => match &self {
1358 Value::Boolean(b) => Value::Boolean(*b),
1359 Value::Integer(v) => Value::Boolean(*v != 0),
1360 Value::Float(v) => Value::Boolean(*v != 0.0),
1361 Value::Text(s) => {
1362 let s_ref: &str = s.as_ref();
1364 if s_ref.eq_ignore_ascii_case("true")
1365 || s_ref.eq_ignore_ascii_case("t")
1366 || s_ref.eq_ignore_ascii_case("yes")
1367 || s_ref.eq_ignore_ascii_case("y")
1368 || s_ref == "1"
1369 {
1370 Value::Boolean(true)
1371 } else if s_ref.eq_ignore_ascii_case("false")
1372 || s_ref.eq_ignore_ascii_case("f")
1373 || s_ref.eq_ignore_ascii_case("no")
1374 || s_ref.eq_ignore_ascii_case("n")
1375 || s_ref == "0"
1376 {
1377 Value::Boolean(false)
1378 } else {
1379 Value::Null(target_type)
1380 }
1381 }
1382 _ => Value::Null(target_type),
1383 },
1384 DataType::Timestamp => match self {
1385 Value::Timestamp(t) => Value::Timestamp(t),
1386 Value::Text(s) => parse_timestamp(&s)
1387 .map(Value::Timestamp)
1388 .unwrap_or(Value::Null(target_type)),
1389 Value::Integer(nanos) => datetime_from_epoch_nanos(nanos)
1390 .map(Value::Timestamp)
1391 .unwrap_or(Value::Null(target_type)),
1392 _ => Value::Null(target_type),
1393 },
1394 DataType::Json => match self {
1395 Value::Extension(ref data) if data.first() == Some(&(DataType::Json as u8)) => self,
1396 Value::Text(s) => {
1397 if serde_json::from_str::<serde_json::Value>(s.as_str()).is_ok() {
1398 Value::json_unchecked(s.as_str())
1399 } else {
1400 Value::Null(target_type)
1401 }
1402 }
1403 Value::Integer(v) => Value::json_unchecked(v.to_string()),
1404 Value::Float(v) if v.is_finite() => Value::json_unchecked(format_float(v)),
1405 Value::Boolean(b) => Value::json_unchecked(if b { "true" } else { "false" }),
1406 Value::Timestamp(timestamp) => {
1407 Value::json_unchecked(format!("\"{}\"", timestamp.to_rfc3339()))
1408 }
1409 _ => Value::Null(target_type),
1410 },
1411 DataType::Vector => match self {
1412 Value::Extension(ref data) if data.first() == Some(&(DataType::Vector as u8)) => {
1413 self
1414 }
1415 Value::Text(s) => {
1416 if let Some(floats) = parse_vector_str(s.as_str()) {
1417 Value::vector(floats)
1418 } else {
1419 Value::Null(target_type)
1420 }
1421 }
1422 _ => Value::Null(target_type),
1423 },
1424 DataType::Uuid => match self {
1425 Value::Extension(ref data) if data.first() == Some(&(DataType::Uuid as u8)) => {
1426 if data.len() == 17 {
1427 self
1428 } else {
1429 Value::Null(target_type)
1430 }
1431 }
1432 Value::Text(s) => parse_uuid_str(s.as_str())
1433 .map(Value::uuid)
1434 .unwrap_or(Value::Null(target_type)),
1435 _ => Value::Null(target_type),
1436 },
1437 DataType::Decimal => match self {
1438 Value::Extension(ref data) if data.first() == Some(&(DataType::Decimal as u8)) => {
1439 if self.as_decimal_parts().is_some() {
1440 self
1441 } else {
1442 Value::Null(target_type)
1443 }
1444 }
1445 Value::Integer(value) => {
1446 let digits = decimal_precision_for_unscaled(value);
1447 Value::decimal_unchecked(value as i128, digits, 0)
1448 }
1449 Value::Float(value) => parse_decimal_f64(value)
1450 .map(|(unscaled, precision, scale)| {
1451 Value::decimal_unchecked(unscaled, precision, scale)
1452 })
1453 .unwrap_or(Value::Null(target_type)),
1454 Value::Text(s) => parse_decimal_str(s.as_str())
1455 .map(|(unscaled, precision, scale)| {
1456 Value::decimal_unchecked(unscaled, precision, scale)
1457 })
1458 .unwrap_or(Value::Null(target_type)),
1459 _ => Value::Null(target_type),
1460 },
1461 DataType::Date => match self {
1462 Value::Extension(ref data) if data.first() == Some(&(DataType::Date as u8)) => {
1463 if data.len() == 5 {
1464 self
1465 } else {
1466 Value::Null(target_type)
1467 }
1468 }
1469 Value::Text(s) => parse_date_days_since_unix_epoch(s.as_str())
1470 .map(Value::date)
1471 .unwrap_or(Value::Null(target_type)),
1472 _ => Value::Null(target_type),
1473 },
1474 DataType::Bytes => match self {
1475 Value::Extension(ref data) if data.first() == Some(&(DataType::Bytes as u8)) => {
1476 self
1477 }
1478 Value::Text(s) => Value::bytes(s.as_bytes().to_vec()),
1479 _ => Value::Null(target_type),
1480 },
1481 DataType::Null => Value::Null(DataType::Null),
1482 }
1483 }
1484}
1485
1486impl Default for Value {
1491 fn default() -> Self {
1492 Value::Null(DataType::Null)
1493 }
1494}
1495
1496impl fmt::Display for Value {
1497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1498 match self {
1499 Value::Null(_) => write!(f, "NULL"),
1500 Value::Integer(v) => write!(f, "{}", v),
1501 Value::Float(v) => write!(f, "{}", format_float(*v)),
1502 Value::Text(s) => write!(f, "{}", s),
1503 Value::Boolean(b) => write!(f, "{}", if *b { "true" } else { "false" }),
1504 Value::Timestamp(t) => write!(f, "{}", t.to_rfc3339()),
1505 Value::Extension(data) => {
1506 let tag = data.first().copied().unwrap_or(0);
1507 if tag == DataType::Json as u8 {
1508 write!(f, "{}", std::str::from_utf8(&data[1..]).unwrap_or(""))
1509 } else if tag == DataType::Vector as u8 {
1510 write!(f, "{}", format_vector_bytes(&data[1..]))
1511 } else if tag == DataType::Uuid as u8 {
1512 match format_uuid_bytes(&data[1..]) {
1513 Some(uuid) => write!(f, "{}", uuid),
1514 None => write!(f, "<invalid-uuid>"),
1515 }
1516 } else if tag == DataType::Decimal as u8 {
1517 match self.as_decimal_parts() {
1518 Some((unscaled, _, scale)) => {
1519 write!(f, "{}", format_decimal_parts(unscaled, scale))
1520 }
1521 None => write!(f, "<invalid-decimal>"),
1522 }
1523 } else if tag == DataType::Date as u8 {
1524 match self
1525 .as_date_days()
1526 .and_then(format_date_days_since_unix_epoch)
1527 {
1528 Some(date) => write!(f, "{}", date),
1529 None => write!(f, "<invalid-date>"),
1530 }
1531 } else if tag == DataType::Bytes as u8 {
1532 write!(f, "{}", format_bytes_hex(&data[1..]))
1533 } else {
1534 write!(f, "<extension:{}>", tag)
1535 }
1536 }
1537 }
1538 }
1539}
1540
1541impl PartialEq for Value {
1542 #[inline]
1543 fn eq(&self, other: &Self) -> bool {
1544 if let Some(ordering) = compare_canonical_numeric(self, other) {
1545 return ordering == Ordering::Equal;
1546 }
1547
1548 match (self, other) {
1550 (Value::Null(_), Value::Null(_)) => true,
1552 (Value::Null(_), _) | (_, Value::Null(_)) => false,
1554 (Value::Text(a), Value::Text(b)) => a == b,
1555 (Value::Boolean(a), Value::Boolean(b)) => a == b,
1556 (Value::Timestamp(a), Value::Timestamp(b)) => a == b,
1557 (Value::Extension(a), Value::Extension(b)) => a == b,
1558 _ => false,
1559 }
1560 }
1561}
1562
1563impl Eq for Value {}
1564
1565#[inline]
1571fn compare_integer_float(integer: i64, float: f64) -> Ordering {
1572 const I64_EXCLUSIVE_UPPER_F64: f64 = 9_223_372_036_854_775_808.0;
1573 const I64_INCLUSIVE_LOWER_F64: f64 = -9_223_372_036_854_775_808.0;
1574
1575 if float.is_nan() {
1576 return Ordering::Less;
1577 }
1578 if float >= I64_EXCLUSIVE_UPPER_F64 {
1579 return Ordering::Less;
1580 }
1581 if float < I64_INCLUSIVE_LOWER_F64 {
1582 return Ordering::Greater;
1583 }
1584
1585 let truncated = float as i64;
1589 match integer.cmp(&truncated) {
1590 Ordering::Equal => {
1591 let fraction = float.fract();
1592 if fraction == 0.0 {
1593 Ordering::Equal
1594 } else if fraction.is_sign_negative() {
1595 Ordering::Greater
1596 } else {
1597 Ordering::Less
1598 }
1599 }
1600 ordering => ordering,
1601 }
1602}
1603
1604#[inline(always)]
1609fn wymix(a: u64, b: u64) -> u64 {
1610 let r = (a as u128).wrapping_mul(b as u128);
1611 (r as u64) ^ ((r >> 64) as u64)
1612}
1613
1614const WY_P1: u64 = 0xa0761d6478bd642f;
1616const WY_P2: u64 = 0xe7037ed1a0b428db;
1617
1618#[inline(always)]
1619fn integer_hash_word(value: i64) -> u64 {
1620 wymix(1 ^ (value as u64), WY_P1)
1621}
1622
1623#[inline(always)]
1624fn float_hash_word(value: f64) -> u64 {
1625 if value.is_nan() {
1626 return wymix(6 ^ f64::NAN.to_bits(), WY_P1);
1627 }
1628
1629 let integer = value as i64;
1630 if compare_integer_float(integer, value) == Ordering::Equal {
1631 integer_hash_word(integer)
1634 } else {
1635 wymix(6 ^ value.to_bits(), WY_P1)
1636 }
1637}
1638
1639impl Hash for Value {
1640 #[inline(always)]
1641 fn hash<H: Hasher>(&self, state: &mut H) {
1642 match self {
1651 Value::Null(_) => {
1652 state.write_u64(0);
1654 }
1655 Value::Integer(v) => {
1656 state.write_u64(integer_hash_word(*v));
1658 }
1659 Value::Float(v) => {
1660 state.write_u64(float_hash_word(*v));
1661 }
1662 Value::Text(s) => {
1663 let bytes = s.as_bytes();
1665 let len = bytes.len();
1666 let mut h = wymix(2 ^ (len as u64), WY_P1);
1667
1668 let chunks = len / 8;
1670 let ptr = bytes.as_ptr();
1671 for i in 0..chunks {
1672 let chunk = unsafe { (ptr.add(i * 8) as *const u64).read_unaligned() };
1676 h = wymix(h ^ chunk, WY_P2);
1677 }
1678
1679 let tail_start = chunks * 8;
1681 if tail_start < len {
1682 let mut tail = 0u64;
1683 for (j, &b) in bytes[tail_start..].iter().enumerate() {
1684 tail |= (b as u64) << (j * 8);
1685 }
1686 h = wymix(h ^ tail, WY_P1);
1687 }
1688
1689 state.write_u64(h);
1690 }
1691 Value::Boolean(b) => {
1692 state.write_u64(wymix(if *b { 5 } else { 4 }, WY_P1));
1694 }
1695 Value::Timestamp(t) => {
1696 let nanos = t
1699 .timestamp_nanos_opt()
1700 .unwrap_or_else(|| t.timestamp().saturating_mul(1_000_000_000));
1701 state.write_u64(wymix(3 ^ (nanos as u64), WY_P1));
1702 }
1703 Value::Extension(data) => {
1704 if let Some((unscaled, _, scale)) = self.as_decimal_parts() {
1705 state.write_u64(decimal_hash_word(unscaled, scale));
1706 return;
1707 }
1708
1709 let bytes: &[u8] = data;
1712 let len = bytes.len();
1713 let mut h = wymix(10 ^ (len as u64), WY_P1);
1714
1715 let chunks = len / 8;
1716 let ptr = bytes.as_ptr();
1717 for i in 0..chunks {
1718 let chunk = unsafe { (ptr.add(i * 8) as *const u64).read_unaligned() };
1722 h = wymix(h ^ chunk, WY_P2);
1723 }
1724
1725 let tail_start = chunks * 8;
1726 if tail_start < len {
1727 let mut tail = 0u64;
1728 for (j, &b) in bytes[tail_start..].iter().enumerate() {
1729 tail |= (b as u64) << (j * 8);
1730 }
1731 h = wymix(h ^ tail, WY_P1);
1732 }
1733
1734 state.write_u64(h);
1735 }
1736 }
1737 }
1738}
1739
1740#[allow(clippy::non_canonical_partial_ord_impl)]
1744impl PartialOrd for Value {
1745 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1746 self.compare(other).ok()
1750 }
1751}
1752
1753impl Ord for Value {
1769 fn cmp(&self, other: &Self) -> Ordering {
1770 match (self.is_null(), other.is_null()) {
1772 (true, true) => return Ordering::Equal,
1773 (true, false) => return Ordering::Less,
1774 (false, true) => return Ordering::Greater,
1775 (false, false) => {} }
1777
1778 if let Some(ordering) = compare_canonical_numeric(self, other) {
1779 return ordering;
1780 }
1781
1782 fn type_discriminant(v: &Value) -> u8 {
1784 match v {
1785 Value::Null(_) => 0,
1786 Value::Boolean(_) => 1,
1787 Value::Integer(_) | Value::Float(_) => 2,
1789 Value::Extension(_) if v.as_decimal_parts().is_some() => 2,
1790 Value::Text(_) => 3,
1791 Value::Timestamp(_) => 4,
1792 Value::Extension(_) => 5,
1793 }
1794 }
1795
1796 let self_disc = type_discriminant(self);
1797 let other_disc = type_discriminant(other);
1798
1799 if self_disc != other_disc {
1801 return self_disc.cmp(&other_disc);
1802 }
1803
1804 match (self, other) {
1806 (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
1807 (Value::Float(a), Value::Float(b)) => {
1808 match (a.is_nan(), b.is_nan()) {
1810 (true, true) => Ordering::Equal,
1811 (true, false) => Ordering::Greater,
1812 (false, true) => Ordering::Less,
1813 (false, false) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
1814 }
1815 }
1816 (Value::Text(a), Value::Text(b)) => a.cmp(b),
1817 (Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
1818 (Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
1819 (Value::Extension(a), Value::Extension(b)) => a.cmp(b),
1820 _ => Ordering::Equal, }
1822 }
1823}
1824
1825impl From<i64> for Value {
1830 fn from(v: i64) -> Self {
1831 Value::Integer(v)
1832 }
1833}
1834
1835impl From<i32> for Value {
1836 fn from(v: i32) -> Self {
1837 Value::Integer(v as i64)
1838 }
1839}
1840
1841impl From<i16> for Value {
1842 fn from(v: i16) -> Self {
1843 Value::Integer(v as i64)
1844 }
1845}
1846
1847impl From<i8> for Value {
1848 fn from(v: i8) -> Self {
1849 Value::Integer(v as i64)
1850 }
1851}
1852
1853impl From<u32> for Value {
1854 fn from(v: u32) -> Self {
1855 Value::Integer(v as i64)
1856 }
1857}
1858
1859impl From<u16> for Value {
1860 fn from(v: u16) -> Self {
1861 Value::Integer(v as i64)
1862 }
1863}
1864
1865impl From<u8> for Value {
1866 fn from(v: u8) -> Self {
1867 Value::Integer(v as i64)
1868 }
1869}
1870
1871impl From<f64> for Value {
1872 fn from(v: f64) -> Self {
1873 Value::Float(v)
1874 }
1875}
1876
1877impl From<f32> for Value {
1878 fn from(v: f32) -> Self {
1879 Value::Float(v as f64)
1880 }
1881}
1882
1883impl From<String> for Value {
1884 fn from(v: String) -> Self {
1885 Value::Text(SmartString::from_string(v))
1886 }
1887}
1888
1889impl From<&str> for Value {
1890 fn from(v: &str) -> Self {
1891 Value::Text(SmartString::from(v))
1892 }
1893}
1894
1895impl From<Arc<str>> for Value {
1896 fn from(v: Arc<str>) -> Self {
1897 Value::Text(SmartString::from(v.as_ref()))
1898 }
1899}
1900
1901impl From<bool> for Value {
1902 fn from(v: bool) -> Self {
1903 Value::Boolean(v)
1904 }
1905}
1906
1907impl From<DateTime<Utc>> for Value {
1908 fn from(v: DateTime<Utc>) -> Self {
1909 Value::Timestamp(v)
1910 }
1911}
1912
1913impl<T: Into<Value>> From<Option<T>> for Value {
1914 fn from(v: Option<T>) -> Self {
1915 match v {
1916 Some(val) => val.into(),
1917 None => Value::Null(DataType::Null),
1918 }
1919 }
1920}
1921
1922pub fn parse_timestamp(s: &str) -> Result<DateTime<Utc>> {
1928 let s = s.trim();
1929
1930 for format in TIMESTAMP_FORMATS {
1932 if let Ok(dt) = DateTime::parse_from_str(s, format) {
1933 return Ok(dt.with_timezone(&Utc));
1934 }
1935 if let Ok(ndt) = NaiveDateTime::parse_from_str(s, format) {
1937 return Ok(Utc.from_utc_datetime(&ndt));
1938 }
1939 }
1940
1941 if let Ok(date) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
1943 let datetime = date.and_hms_opt(0, 0, 0).unwrap();
1944 return Ok(Utc.from_utc_datetime(&datetime));
1945 }
1946
1947 for format in TIME_FORMATS {
1949 if let Ok(time) = NaiveTime::parse_from_str(s, format) {
1950 let today = Utc::now().date_naive();
1951 let datetime = today.and_time(time);
1952 return Ok(Utc.from_utc_datetime(&datetime));
1953 }
1954 }
1955
1956 Err(Error::parse(format!("invalid timestamp format: {}", s)))
1957}
1958
1959fn format_float(v: f64) -> String {
1961 if v.is_nan() {
1963 return "NaN".to_string();
1964 }
1965 if v.is_infinite() {
1966 return if v.is_sign_positive() {
1967 "Infinity"
1968 } else {
1969 "-Infinity"
1970 }
1971 .to_string();
1972 }
1973
1974 let abs_v = v.abs();
1975
1976 if abs_v != 0.0 && !(1e-4..1e15).contains(&abs_v) {
1978 let s = format!("{:e}", v);
1980 if let Some(e_pos) = s.find('e') {
1982 let (mantissa, exp) = s.split_at(e_pos);
1983 let clean_mantissa = if mantissa.contains('.') {
1984 mantissa
1985 .trim_end_matches('0')
1986 .trim_end_matches('.')
1987 .to_string()
1988 } else {
1989 mantissa.to_string()
1990 };
1991 return format!("{}{}", clean_mantissa, exp);
1992 }
1993 return s;
1994 }
1995
1996 if v.fract() == 0.0 {
1997 format!("{:.0}", v)
1999 } else {
2000 let s = format!("{:?}", v);
2002 if s.contains('.') && !s.contains('e') && !s.contains('E') {
2004 s.trim_end_matches('0').trim_end_matches('.').to_string()
2005 } else {
2006 s
2007 }
2008 }
2009}
2010
2011pub fn format_vector_bytes(data: &[u8]) -> String {
2013 let len = data.len() / 4;
2014 let mut s = String::with_capacity(len * 8 + 2);
2015 s.push('[');
2016 for i in 0..len {
2017 if i > 0 {
2018 s.push_str(", ");
2019 }
2020 let f = f32::from_le_bytes([
2021 data[i * 4],
2022 data[i * 4 + 1],
2023 data[i * 4 + 2],
2024 data[i * 4 + 3],
2025 ]);
2026 use std::fmt::Write;
2027 if f.fract() == 0.0 && f.is_finite() {
2028 let _ = write!(s, "{:.1}", f);
2029 } else {
2030 let _ = write!(s, "{}", f);
2031 }
2032 }
2033 s.push(']');
2034 s
2035}
2036
2037pub fn parse_uuid_str(s: &str) -> Option<[u8; 16]> {
2043 Uuid::parse_str(s.trim()).ok().map(|uuid| *uuid.as_bytes())
2044}
2045
2046pub fn format_uuid_bytes(data: &[u8]) -> Option<String> {
2048 let bytes: [u8; 16] = data.try_into().ok()?;
2049 Some(Uuid::from_bytes(bytes).hyphenated().to_string())
2050}
2051
2052pub const MAX_DECIMAL_PRECISION: u8 = 38;
2053
2054pub fn validate_decimal_shape(unscaled: i128, precision: u8, scale: u8) -> Result<()> {
2056 if !(1..=MAX_DECIMAL_PRECISION).contains(&precision) {
2057 return Err(Error::invalid_argument(format!(
2058 "DECIMAL precision {precision} is outside supported range 1..={MAX_DECIMAL_PRECISION}"
2059 )));
2060 }
2061 if scale > precision {
2062 return Err(Error::invalid_argument(format!(
2063 "DECIMAL scale {scale} exceeds declared precision {precision}"
2064 )));
2065 }
2066 let digits = unscaled.unsigned_abs().to_string().len().max(1);
2067 if digits > usize::from(precision) {
2068 return Err(Error::invalid_argument(format!(
2069 "DECIMAL coefficient has {digits} digits but precision is {precision}"
2070 )));
2071 }
2072 Ok(())
2073}
2074
2075#[inline]
2076fn checked_float_to_i64(value: f64) -> Option<i64> {
2077 const I64_EXCLUSIVE_UPPER_F64: f64 = 9_223_372_036_854_775_808.0;
2078 const I64_INCLUSIVE_LOWER_F64: f64 = -9_223_372_036_854_775_808.0;
2079 (value.is_finite() && (I64_INCLUSIVE_LOWER_F64..I64_EXCLUSIVE_UPPER_F64).contains(&value))
2080 .then_some(value as i64)
2081}
2082
2083#[inline]
2084fn parse_text_to_i64(value: &str) -> Option<i64> {
2085 value
2086 .parse::<i64>()
2087 .ok()
2088 .or_else(|| value.parse::<f64>().ok().and_then(checked_float_to_i64))
2089}
2090
2091#[inline]
2092fn datetime_from_epoch_nanos(nanos: i64) -> Option<DateTime<Utc>> {
2093 DateTime::from_timestamp(
2094 nanos.div_euclid(1_000_000_000),
2095 nanos.rem_euclid(1_000_000_000) as u32,
2096 )
2097}
2098
2099fn decimal_precision_for_unscaled(value: i64) -> u8 {
2101 decimal_precision_for_unscaled_i128(value as i128)
2102}
2103
2104fn decimal_precision_for_unscaled_i128(value: i128) -> u8 {
2105 let digits = value.unsigned_abs().to_string().len().max(1);
2106 digits.min(MAX_DECIMAL_PRECISION as usize) as u8
2107}
2108
2109#[inline]
2110fn decimal_scale_factor(scale: u8) -> Option<i128> {
2111 (scale <= MAX_DECIMAL_PRECISION)
2112 .then(|| 10_i128.checked_pow(scale as u32))
2113 .flatten()
2114}
2115
2116#[derive(Clone, Debug, Eq, PartialEq)]
2122struct DecimalIdentity {
2123 negative: bool,
2124 coefficient: u128,
2125 exponent: i32,
2126}
2127
2128impl DecimalIdentity {
2129 fn new(negative: bool, mut coefficient: u128, mut exponent: i32) -> Self {
2130 if coefficient == 0 {
2131 return Self {
2132 negative: false,
2133 coefficient: 0,
2134 exponent: 0,
2135 };
2136 }
2137
2138 while coefficient.is_multiple_of(10) {
2139 coefficient /= 10;
2140 exponent += 1;
2141 }
2142
2143 Self {
2144 negative,
2145 coefficient,
2146 exponent,
2147 }
2148 }
2149
2150 fn from_parts(unscaled: i128, scale: u8) -> Self {
2151 Self::new(
2152 unscaled.is_negative(),
2153 unscaled.unsigned_abs(),
2154 -i32::from(scale),
2155 )
2156 }
2157
2158 fn from_float(value: f64) -> Option<Self> {
2161 if !value.is_finite() {
2162 return None;
2163 }
2164
2165 let rendered = format!("{value:e}");
2168 let (mantissa, exponent) = rendered.split_once('e')?;
2169 let exponent = exponent.parse::<i32>().ok()?;
2170 let (negative, mantissa) = mantissa
2171 .strip_prefix('-')
2172 .map_or((false, mantissa), |unsigned| (true, unsigned));
2173 let (integer, fraction) = mantissa.split_once('.').unwrap_or((mantissa, ""));
2174 let digits = format!("{integer}{fraction}");
2175 let coefficient = digits.parse::<u128>().ok()?;
2176 let fraction_len = i32::try_from(fraction.len()).ok()?;
2177
2178 Some(Self::new(
2179 negative,
2180 coefficient,
2181 exponent.checked_sub(fraction_len)?,
2182 ))
2183 }
2184
2185 fn exact_i64(&self) -> Option<i64> {
2186 if self.coefficient == 0 {
2187 return Some(0);
2188 }
2189 let exponent = u32::try_from(self.exponent).ok()?;
2190 let magnitude = self
2191 .coefficient
2192 .checked_mul(10_u128.checked_pow(exponent)?)?;
2193 if self.negative {
2194 if magnitude == (i64::MAX as u128) + 1 {
2195 Some(i64::MIN)
2196 } else {
2197 i64::try_from(magnitude).ok().map(|value| -value)
2198 }
2199 } else {
2200 i64::try_from(magnitude).ok()
2201 }
2202 }
2203
2204 fn cmp_magnitude(&self, other: &Self) -> Ordering {
2205 debug_assert!(self.coefficient != 0 && other.coefficient != 0);
2206
2207 let left_digits = self.coefficient.to_string();
2208 let right_digits = other.coefficient.to_string();
2209 let left_order = i32::try_from(left_digits.len())
2210 .unwrap_or(i32::MAX)
2211 .saturating_add(self.exponent);
2212 let right_order = i32::try_from(right_digits.len())
2213 .unwrap_or(i32::MAX)
2214 .saturating_add(other.exponent);
2215 match left_order.cmp(&right_order) {
2216 Ordering::Equal => {}
2217 ordering => return ordering,
2218 }
2219
2220 let width = left_digits.len().max(right_digits.len());
2221 for index in 0..width {
2222 let left = left_digits.as_bytes().get(index).copied().unwrap_or(b'0');
2223 let right = right_digits.as_bytes().get(index).copied().unwrap_or(b'0');
2224 match left.cmp(&right) {
2225 Ordering::Equal => {}
2226 ordering => return ordering,
2227 }
2228 }
2229 Ordering::Equal
2230 }
2231
2232 fn cmp_numeric(&self, other: &Self) -> Ordering {
2233 if self == other {
2234 return Ordering::Equal;
2235 }
2236
2237 match (self.coefficient == 0, other.coefficient == 0) {
2238 (true, true) => return Ordering::Equal,
2239 (true, false) => {
2240 return if other.negative {
2241 Ordering::Greater
2242 } else {
2243 Ordering::Less
2244 };
2245 }
2246 (false, true) => {
2247 return if self.negative {
2248 Ordering::Less
2249 } else {
2250 Ordering::Greater
2251 };
2252 }
2253 (false, false) => {}
2254 }
2255
2256 match self.negative.cmp(&other.negative) {
2257 Ordering::Less => Ordering::Greater,
2258 Ordering::Greater => Ordering::Less,
2259 Ordering::Equal if self.negative => self.cmp_magnitude(other).reverse(),
2260 Ordering::Equal => self.cmp_magnitude(other),
2261 }
2262 }
2263}
2264
2265fn compare_decimal_float(decimal: &DecimalIdentity, float: f64) -> Ordering {
2266 if float.is_nan() || float == f64::INFINITY {
2267 return Ordering::Less;
2268 }
2269 if float == f64::NEG_INFINITY {
2270 return Ordering::Greater;
2271 }
2272
2273 decimal.cmp_numeric(
2274 &DecimalIdentity::from_float(float)
2275 .expect("every finite f64 has a shortest decimal identity"),
2276 )
2277}
2278
2279fn compare_canonical_numeric(left: &Value, right: &Value) -> Option<Ordering> {
2282 match (left, right) {
2283 (Value::Integer(left), Value::Integer(right)) => Some(left.cmp(right)),
2284 (Value::Float(left), Value::Float(right)) => Some(compare_floats(*left, *right)),
2285 (Value::Integer(integer), Value::Float(float)) => {
2286 Some(compare_integer_float(*integer, *float))
2287 }
2288 (Value::Float(float), Value::Integer(integer)) => {
2289 Some(compare_integer_float(*integer, *float).reverse())
2290 }
2291 _ => {
2292 let left_decimal = left
2293 .as_decimal_parts()
2294 .map(|(unscaled, _, scale)| DecimalIdentity::from_parts(unscaled, scale));
2295 let right_decimal = right
2296 .as_decimal_parts()
2297 .map(|(unscaled, _, scale)| DecimalIdentity::from_parts(unscaled, scale));
2298
2299 match (left_decimal, right_decimal, left, right) {
2300 (Some(left), Some(right), _, _) => Some(left.cmp_numeric(&right)),
2301 (Some(left), None, _, Value::Integer(right)) => {
2302 Some(left.cmp_numeric(&DecimalIdentity::from_parts(*right as i128, 0)))
2303 }
2304 (None, Some(right), Value::Integer(left), _) => {
2305 Some(DecimalIdentity::from_parts(*left as i128, 0).cmp_numeric(&right))
2306 }
2307 (Some(left), None, _, Value::Float(right)) => {
2308 Some(compare_decimal_float(&left, *right))
2309 }
2310 (None, Some(right), Value::Float(left), _) => {
2311 Some(compare_decimal_float(&right, *left).reverse())
2312 }
2313 _ => None,
2314 }
2315 }
2316 }
2317}
2318
2319fn decimal_hash_word(unscaled: i128, scale: u8) -> u64 {
2320 let identity = DecimalIdentity::from_parts(unscaled, scale);
2321 if let Some(integer) = identity.exact_i64() {
2322 return integer_hash_word(integer);
2323 }
2324
2325 if let Ok(float) = format_decimal_parts(unscaled, scale).parse::<f64>() {
2330 if float.is_finite() && DecimalIdentity::from_float(float).as_ref() == Some(&identity) {
2331 return float_hash_word(float);
2332 }
2333 }
2334
2335 let low = identity.coefficient as u64;
2336 let high = (identity.coefficient >> 64) as u64;
2337 let sign = u64::from(identity.negative);
2338 let exponent = identity.exponent as i64 as u64;
2339 let mut hash = wymix(7 ^ low, WY_P1);
2340 hash = wymix(hash ^ high, WY_P2);
2341 hash = wymix(hash ^ exponent, WY_P1);
2342 wymix(hash ^ sign, WY_P2)
2343}
2344
2345fn parse_decimal_f64(value: f64) -> Option<(i128, u8, u8)> {
2350 if !value.is_finite() {
2351 return None;
2352 }
2353
2354 let rendered = value.to_string();
2355 let Some(exponent_offset) = rendered.find(['e', 'E']) else {
2356 return parse_decimal_str(&rendered);
2357 };
2358
2359 let (mantissa, exponent_with_marker) = rendered.split_at(exponent_offset);
2360 let exponent = exponent_with_marker[1..].parse::<i32>().ok()?;
2361 let (mut unscaled, _, mantissa_scale) = parse_decimal_str(mantissa)?;
2362 let resulting_scale = i32::from(mantissa_scale).checked_sub(exponent)?;
2363
2364 let scale = if resulting_scale < 0 {
2365 let power = u8::try_from(resulting_scale.checked_neg()?).ok()?;
2366 unscaled = unscaled.checked_mul(decimal_scale_factor(power)?)?;
2367 0
2368 } else {
2369 u8::try_from(resulting_scale).ok()?
2370 };
2371 if scale > MAX_DECIMAL_PRECISION
2372 || unscaled.unsigned_abs().to_string().len() > MAX_DECIMAL_PRECISION as usize
2373 {
2374 return None;
2375 }
2376
2377 Some((
2378 unscaled,
2379 decimal_precision_for_unscaled_i128(unscaled),
2380 scale,
2381 ))
2382}
2383
2384pub fn parse_decimal_str(s: &str) -> Option<(i128, u8, u8)> {
2390 let trimmed = s.trim();
2391 if trimmed.is_empty() {
2392 return None;
2393 }
2394
2395 let (negative, body) = match trimmed.as_bytes()[0] {
2396 b'-' => (true, &trimmed[1..]),
2397 b'+' => (false, &trimmed[1..]),
2398 _ => (false, trimmed),
2399 };
2400 if body.is_empty() {
2401 return None;
2402 }
2403
2404 let mut parts = body.split('.');
2405 let int_part = parts.next().unwrap_or("");
2406 let frac_part = parts.next();
2407 if parts.next().is_some() {
2408 return None;
2409 }
2410
2411 let frac = frac_part.unwrap_or("");
2412 if int_part.is_empty() && frac.is_empty() {
2413 return None;
2414 }
2415 if !int_part.bytes().all(|b| b.is_ascii_digit()) || !frac.bytes().all(|b| b.is_ascii_digit()) {
2416 return None;
2417 }
2418
2419 let scale = u8::try_from(frac.len()).ok()?;
2420 if scale > MAX_DECIMAL_PRECISION {
2421 return None;
2422 }
2423
2424 let digits = format!("{int_part}{frac}");
2425 let normalized = digits.trim_start_matches('0');
2426 let precision_len = normalized.len().max(usize::from(scale)).max(1);
2427 if precision_len > MAX_DECIMAL_PRECISION as usize {
2428 return None;
2429 }
2430 let precision = precision_len as u8;
2431
2432 let magnitude = if normalized.is_empty() {
2433 0
2434 } else {
2435 normalized.parse::<i128>().ok()?
2436 };
2437 Some((
2438 if negative { -magnitude } else { magnitude },
2439 precision,
2440 scale,
2441 ))
2442}
2443
2444pub fn format_decimal_parts(unscaled: i128, scale: u8) -> String {
2445 if scale == 0 {
2446 return unscaled.to_string();
2447 }
2448
2449 let negative = unscaled.is_negative();
2450 let mut digits = unscaled.unsigned_abs().to_string();
2451 let scale_len = scale as usize;
2452 if digits.len() <= scale_len {
2453 let mut padded = String::with_capacity(scale_len + 1);
2454 padded.push_str(&"0".repeat(scale_len + 1 - digits.len()));
2455 padded.push_str(&digits);
2456 digits = padded;
2457 }
2458 let split = digits.len() - scale_len;
2459 let mut out = String::with_capacity(digits.len() + 2);
2460 if negative {
2461 out.push('-');
2462 }
2463 out.push_str(&digits[..split]);
2464 out.push('.');
2465 out.push_str(&digits[split..]);
2466 out
2467}
2468
2469#[doc(hidden)]
2470pub fn compare_decimal_parts(
2471 left_unscaled: i128,
2472 left_scale: u8,
2473 right_unscaled: i128,
2474 right_scale: u8,
2475) -> Ordering {
2476 DecimalIdentity::from_parts(left_unscaled, left_scale)
2477 .cmp_numeric(&DecimalIdentity::from_parts(right_unscaled, right_scale))
2478}
2479
2480pub fn parse_date_days_since_unix_epoch(s: &str) -> Option<i32> {
2481 let date = NaiveDate::parse_from_str(s.trim(), "%Y-%m-%d").ok()?;
2482 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1)?;
2483 i32::try_from(date.signed_duration_since(epoch).num_days()).ok()
2484}
2485
2486pub fn format_date_days_since_unix_epoch(days: i32) -> Option<String> {
2487 let epoch = NaiveDate::from_ymd_opt(1970, 1, 1)?;
2488 epoch
2489 .checked_add_signed(chrono::Duration::days(days as i64))
2490 .map(|date| date.format("%Y-%m-%d").to_string())
2491}
2492
2493pub fn format_bytes_hex(data: &[u8]) -> String {
2494 const HEX: &[u8; 16] = b"0123456789abcdef";
2495 let mut out = String::with_capacity(2 + data.len() * 2);
2496 out.push_str("0x");
2497 for byte in data {
2498 out.push(HEX[(byte >> 4) as usize] as char);
2499 out.push(HEX[(byte & 0x0f) as usize] as char);
2500 }
2501 out
2502}
2503
2504pub fn parse_vector_str(s: &str) -> Option<Vec<f32>> {
2506 let s = s.trim();
2507 let inner = s.strip_prefix('[')?.strip_suffix(']')?;
2508 if inner.trim().is_empty() {
2509 return Some(Vec::new());
2510 }
2511 let mut result = Vec::new();
2512 for part in inner.split(',') {
2513 let val: f32 = part.trim().parse().ok()?;
2514 result.push(val);
2515 }
2516 Some(result)
2517}
2518
2519fn compare_floats(a: f64, b: f64) -> Ordering {
2521 match (a.is_nan(), b.is_nan()) {
2523 (true, true) => Ordering::Equal,
2524 (true, false) => Ordering::Greater,
2525 (false, true) => Ordering::Less,
2526 (false, false) => a.partial_cmp(&b).unwrap_or(Ordering::Equal),
2527 }
2528}
2529
2530#[cfg(test)]
2531mod tests;