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};
26
27use super::error::{Error, Result};
28use super::types::DataType;
29use crate::common::{CompactArc, SmartString};
30
31const TIMESTAMP_FORMATS: &[&str] = &[
34 "%Y-%m-%dT%H:%M:%S%.f%:z", "%Y-%m-%dT%H:%M:%S%:z", "%Y-%m-%dT%H:%M:%SZ", "%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", ];
46
47const TIME_FORMATS: &[&str] = &[
48 "%H:%M:%S%.f", "%H:%M:%S", "%H:%M", ];
52
53#[derive(Debug, Clone)]
68pub enum Value {
69 Null(DataType),
71
72 Integer(i64),
74
75 Float(f64),
77
78 Text(SmartString),
80
81 Boolean(bool),
83
84 Timestamp(DateTime<Utc>),
86
87 Json(CompactArc<str>),
89}
90
91pub const NULL_VALUE: Value = Value::Null(DataType::Null);
93
94impl Value {
95 #[inline]
101 pub fn null(data_type: DataType) -> Self {
102 Value::Null(data_type)
103 }
104
105 #[inline(always)]
107 pub fn null_unknown() -> Self {
108 Value::Null(DataType::Null)
109 }
110
111 pub fn integer(value: i64) -> Self {
113 Value::Integer(value)
114 }
115
116 pub fn float(value: f64) -> Self {
118 Value::Float(value)
119 }
120
121 pub fn text(value: impl Into<String>) -> Self {
127 Value::Text(SmartString::from_string_shared(value.into()))
128 }
129
130 pub fn text_arc(value: Arc<str>) -> Self {
134 Value::Text(SmartString::from(value))
135 }
136
137 pub fn boolean(value: bool) -> Self {
139 Value::Boolean(value)
140 }
141
142 pub fn timestamp(value: DateTime<Utc>) -> Self {
144 Value::Timestamp(value)
145 }
146
147 pub fn json(value: impl Into<String>) -> Self {
149 Value::Json(CompactArc::from(value.into()))
150 }
151
152 pub fn json_arc(value: CompactArc<str>) -> Self {
154 Value::Json(value)
155 }
156
157 pub fn data_type(&self) -> DataType {
163 match self {
164 Value::Null(dt) => *dt,
165 Value::Integer(_) => DataType::Integer,
166 Value::Float(_) => DataType::Float,
167 Value::Text(_) => DataType::Text,
168 Value::Boolean(_) => DataType::Boolean,
169 Value::Timestamp(_) => DataType::Timestamp,
170 Value::Json(_) => DataType::Json,
171 }
172 }
173
174 #[inline(always)]
176 pub fn is_null(&self) -> bool {
177 matches!(self, Value::Null(_))
178 }
179
180 pub fn as_int64(&self) -> Option<i64> {
190 match self {
191 Value::Null(_) => None,
192 Value::Integer(v) => Some(*v),
193 Value::Float(v) => Some(*v as i64),
194 Value::Text(s) => s
195 .parse::<i64>()
196 .ok()
197 .or_else(|| s.parse::<f64>().ok().map(|f| f as i64)),
198 Value::Boolean(b) => Some(if *b { 1 } else { 0 }),
199 Value::Timestamp(t) => Some(t.timestamp_nanos_opt().unwrap_or(0)),
200 Value::Json(_) => None,
201 }
202 }
203
204 pub fn as_float64(&self) -> Option<f64> {
206 match self {
207 Value::Null(_) => None,
208 Value::Integer(v) => Some(*v as f64),
209 Value::Float(v) => Some(*v),
210 Value::Text(s) => s.parse::<f64>().ok(),
211 Value::Boolean(b) => Some(if *b { 1.0 } else { 0.0 }),
212 Value::Timestamp(_) => None,
213 Value::Json(_) => None,
214 }
215 }
216
217 pub fn as_boolean(&self) -> Option<bool> {
219 match self {
220 Value::Null(_) => None,
221 Value::Integer(v) => Some(*v != 0),
222 Value::Float(v) => Some(*v != 0.0),
223 Value::Text(s) => {
224 let s_ref: &str = s.as_ref();
226 if s_ref.eq_ignore_ascii_case("true")
227 || s_ref.eq_ignore_ascii_case("t")
228 || s_ref.eq_ignore_ascii_case("yes")
229 || s_ref.eq_ignore_ascii_case("y")
230 || s_ref == "1"
231 {
232 Some(true)
233 } else if s_ref.eq_ignore_ascii_case("false")
234 || s_ref.eq_ignore_ascii_case("f")
235 || s_ref.eq_ignore_ascii_case("no")
236 || s_ref.eq_ignore_ascii_case("n")
237 || s_ref == "0"
238 || s_ref.is_empty()
239 {
240 Some(false)
241 } else {
242 s_ref.parse::<f64>().ok().map(|f| f != 0.0)
243 }
244 }
245 Value::Boolean(b) => Some(*b),
246 Value::Timestamp(_) => None,
247 Value::Json(_) => None,
248 }
249 }
250
251 pub fn as_string(&self) -> Option<String> {
253 match self {
254 Value::Null(_) => None,
255 Value::Integer(v) => Some(v.to_string()),
256 Value::Float(v) => Some(format_float(*v)),
257 Value::Text(s) => Some(s.to_string()),
258 Value::Boolean(b) => Some(if *b { "true" } else { "false" }.to_string()),
259 Value::Timestamp(t) => Some(t.to_rfc3339()),
260 Value::Json(s) => Some(s.to_string()),
261 }
262 }
263
264 pub fn as_str(&self) -> Option<&str> {
266 match self {
267 Value::Text(s) => Some(s.as_str()),
268 Value::Json(s) => Some(s.as_ref()),
269 _ => None,
270 }
271 }
272
273 pub fn as_arc_str(&self) -> Option<CompactArc<str>> {
275 match self {
276 Value::Text(s) => Some(CompactArc::from(s.as_str())),
277 Value::Json(s) => Some(s.clone()),
278 _ => None,
279 }
280 }
281
282 pub fn as_timestamp(&self) -> Option<DateTime<Utc>> {
284 match self {
285 Value::Null(_) => None,
286 Value::Timestamp(t) => Some(*t),
287 Value::Text(s) => parse_timestamp(s).ok(),
288 Value::Integer(nanos) => {
289 DateTime::from_timestamp(*nanos / 1_000_000_000, (*nanos % 1_000_000_000) as u32)
291 }
292 _ => None,
293 }
294 }
295
296 pub fn as_json(&self) -> Option<&str> {
298 match self {
299 Value::Null(_) => Some("{}"),
300 Value::Json(s) => Some(s),
301 _ => None,
302 }
303 }
304
305 pub fn compare(&self, other: &Value) -> Result<Ordering> {
317 if self.is_null() || other.is_null() {
319 if self.is_null() && other.is_null() {
320 return Ok(Ordering::Equal);
321 }
322 return Err(Error::NullComparison);
323 }
324
325 if self.data_type() == other.data_type() {
327 return self.compare_same_type(other);
328 }
329
330 if self.data_type().is_numeric() && other.data_type().is_numeric() {
332 let v1 = self.as_float64().unwrap();
333 let v2 = other.as_float64().unwrap();
334 return Ok(compare_floats(v1, v2));
335 }
336
337 let s1 = self.as_string().unwrap_or_default();
339 let s2 = other.as_string().unwrap_or_default();
340 Ok(s1.cmp(&s2))
341 }
342
343 fn compare_same_type(&self, other: &Value) -> Result<Ordering> {
345 match (self, other) {
346 (Value::Integer(a), Value::Integer(b)) => Ok(a.cmp(b)),
347 (Value::Float(a), Value::Float(b)) => Ok(compare_floats(*a, *b)),
348 (Value::Text(a), Value::Text(b)) => Ok(a.cmp(b)),
349 (Value::Boolean(a), Value::Boolean(b)) => Ok(a.cmp(b)),
350 (Value::Timestamp(a), Value::Timestamp(b)) => Ok(a.cmp(b)),
351 (Value::Json(a), Value::Json(b)) => {
352 if a == b {
354 Ok(Ordering::Equal)
355 } else {
356 Err(Error::IncomparableTypes)
357 }
358 }
359 _ => Err(Error::IncomparableTypes),
360 }
361 }
362
363 pub fn from_typed(value: Option<&dyn std::any::Any>, data_type: DataType) -> Self {
369 match value {
370 None => Value::Null(data_type),
371 Some(v) => {
372 match data_type {
374 DataType::Integer => {
375 if let Some(&i) = v.downcast_ref::<i64>() {
376 Value::Integer(i)
377 } else if let Some(&i) = v.downcast_ref::<i32>() {
378 Value::Integer(i as i64)
379 } else if let Some(s) = v.downcast_ref::<String>() {
380 s.parse::<i64>()
381 .map(Value::Integer)
382 .unwrap_or(Value::Null(data_type))
383 } else {
384 Value::Null(data_type)
385 }
386 }
387 DataType::Float => {
388 if let Some(&f) = v.downcast_ref::<f64>() {
389 Value::Float(f)
390 } else if let Some(&i) = v.downcast_ref::<i64>() {
391 Value::Float(i as f64)
392 } else if let Some(s) = v.downcast_ref::<String>() {
393 s.parse::<f64>()
394 .map(Value::Float)
395 .unwrap_or(Value::Null(data_type))
396 } else {
397 Value::Null(data_type)
398 }
399 }
400 DataType::Text => {
401 if let Some(s) = v.downcast_ref::<String>() {
402 Value::Text(SmartString::new(s))
403 } else if let Some(&s) = v.downcast_ref::<&str>() {
404 Value::Text(SmartString::from(s))
405 } else {
406 Value::Null(data_type)
407 }
408 }
409 DataType::Boolean => {
410 if let Some(&b) = v.downcast_ref::<bool>() {
411 Value::Boolean(b)
412 } else if let Some(&i) = v.downcast_ref::<i64>() {
413 Value::Boolean(i != 0)
414 } else {
415 Value::Null(data_type)
416 }
417 }
418 DataType::Timestamp => {
419 if let Some(&t) = v.downcast_ref::<DateTime<Utc>>() {
420 Value::Timestamp(t)
421 } else if let Some(s) = v.downcast_ref::<String>() {
422 parse_timestamp(s)
423 .map(Value::Timestamp)
424 .unwrap_or(Value::Null(data_type))
425 } else {
426 Value::Null(data_type)
427 }
428 }
429 DataType::Json => {
430 if let Some(s) = v.downcast_ref::<String>() {
431 if serde_json::from_str::<serde_json::Value>(s).is_ok() {
433 Value::Json(CompactArc::from(s.as_str()))
434 } else {
435 Value::Null(data_type)
436 }
437 } else {
438 Value::Null(data_type)
439 }
440 }
441 DataType::Null => Value::Null(DataType::Null),
442 }
443 }
444 }
445 }
446
447 pub fn coerce_to_type(&self, target_type: DataType) -> Value {
463 if self.is_null() {
465 return Value::Null(target_type);
466 }
467
468 if self.data_type() == target_type {
470 return self.clone();
471 }
472
473 match target_type {
474 DataType::Integer => {
475 match self {
477 Value::Integer(v) => Value::Integer(*v),
478 Value::Float(v) => Value::Integer(*v as i64),
479 Value::Text(s) => s
480 .parse::<i64>()
481 .map(Value::Integer)
482 .unwrap_or(Value::Null(target_type)),
483 Value::Boolean(b) => Value::Integer(if *b { 1 } else { 0 }),
484 _ => Value::Null(target_type),
485 }
486 }
487 DataType::Float => {
488 match self {
490 Value::Float(v) => Value::Float(*v),
491 Value::Integer(v) => Value::Float(*v as f64),
492 Value::Text(s) => s
493 .parse::<f64>()
494 .map(Value::Float)
495 .unwrap_or(Value::Null(target_type)),
496 Value::Boolean(b) => Value::Float(if *b { 1.0 } else { 0.0 }),
497 _ => Value::Null(target_type),
498 }
499 }
500 DataType::Text => {
501 match self {
503 Value::Text(s) => Value::Text(s.clone()),
504 Value::Integer(v) => Value::Text(SmartString::from_string(v.to_string())),
505 Value::Float(v) => Value::Text(SmartString::from_string(format_float(*v))),
506 Value::Boolean(b) => {
507 Value::Text(SmartString::new(if *b { "true" } else { "false" }))
508 }
509 Value::Timestamp(t) => Value::Text(SmartString::from_string(t.to_rfc3339())),
510 Value::Json(s) => Value::Text(SmartString::new(s.as_ref())),
511 Value::Null(_) => Value::Null(target_type),
512 }
513 }
514 DataType::Boolean => {
515 match self {
517 Value::Boolean(b) => Value::Boolean(*b),
518 Value::Integer(v) => Value::Boolean(*v != 0),
519 Value::Float(v) => Value::Boolean(*v != 0.0),
520 Value::Text(s) => {
521 let s_ref: &str = s.as_ref();
523 if s_ref.eq_ignore_ascii_case("true")
524 || s_ref.eq_ignore_ascii_case("t")
525 || s_ref.eq_ignore_ascii_case("yes")
526 || s_ref.eq_ignore_ascii_case("y")
527 || s_ref == "1"
528 {
529 Value::Boolean(true)
530 } else if s_ref.eq_ignore_ascii_case("false")
531 || s_ref.eq_ignore_ascii_case("f")
532 || s_ref.eq_ignore_ascii_case("no")
533 || s_ref.eq_ignore_ascii_case("n")
534 || s_ref == "0"
535 {
536 Value::Boolean(false)
537 } else {
538 Value::Null(target_type)
539 }
540 }
541 _ => Value::Null(target_type),
542 }
543 }
544 DataType::Timestamp => {
545 match self {
547 Value::Timestamp(t) => Value::Timestamp(*t),
548 Value::Text(s) => parse_timestamp(s)
549 .map(Value::Timestamp)
550 .unwrap_or(Value::Null(target_type)),
551 Value::Integer(nanos) => {
552 DateTime::from_timestamp(
554 *nanos / 1_000_000_000,
555 (*nanos % 1_000_000_000) as u32,
556 )
557 .map(Value::Timestamp)
558 .unwrap_or(Value::Null(target_type))
559 }
560 _ => Value::Null(target_type),
561 }
562 }
563 DataType::Json => {
564 match self {
566 Value::Json(s) => Value::Json(s.clone()),
567 Value::Text(s) => {
568 if serde_json::from_str::<serde_json::Value>(s.as_str()).is_ok() {
570 Value::Json(CompactArc::from(s.as_str()))
571 } else {
572 Value::Null(target_type)
573 }
574 }
575 Value::Integer(v) => Value::Json(CompactArc::from(v.to_string())),
577 Value::Float(v) => Value::Json(CompactArc::from(format_float(*v))),
578 Value::Boolean(b) => {
579 Value::Json(CompactArc::from(if *b { "true" } else { "false" }))
580 }
581 _ => Value::Null(target_type),
582 }
583 }
584 DataType::Null => Value::Null(DataType::Null),
585 }
586 }
587
588 #[inline]
591 pub fn into_coerce_to_type(self, target_type: DataType) -> Value {
592 if self.is_null() {
594 return Value::Null(target_type);
595 }
596
597 if self.data_type() == target_type {
599 return self;
600 }
601
602 match target_type {
603 DataType::Integer => match &self {
604 Value::Integer(v) => Value::Integer(*v),
605 Value::Float(v) => Value::Integer(*v as i64),
606 Value::Text(s) => s
607 .parse::<i64>()
608 .map(Value::Integer)
609 .unwrap_or(Value::Null(target_type)),
610 Value::Boolean(b) => Value::Integer(if *b { 1 } else { 0 }),
611 _ => Value::Null(target_type),
612 },
613 DataType::Float => match &self {
614 Value::Float(v) => Value::Float(*v),
615 Value::Integer(v) => Value::Float(*v as f64),
616 Value::Text(s) => s
617 .parse::<f64>()
618 .map(Value::Float)
619 .unwrap_or(Value::Null(target_type)),
620 Value::Boolean(b) => Value::Float(if *b { 1.0 } else { 0.0 }),
621 _ => Value::Null(target_type),
622 },
623 DataType::Text => match self {
624 Value::Text(s) => Value::Text(s),
625 Value::Integer(v) => Value::Text(SmartString::from_string(v.to_string())),
626 Value::Float(v) => Value::Text(SmartString::from_string(format_float(v))),
627 Value::Boolean(b) => {
628 Value::Text(SmartString::new(if b { "true" } else { "false" }))
629 }
630 Value::Timestamp(t) => Value::Text(SmartString::from_string(t.to_rfc3339())),
631 Value::Json(s) => Value::Text(SmartString::new(s.as_ref())),
632 Value::Null(_) => Value::Null(target_type),
633 },
634 DataType::Boolean => match &self {
635 Value::Boolean(b) => Value::Boolean(*b),
636 Value::Integer(v) => Value::Boolean(*v != 0),
637 Value::Float(v) => Value::Boolean(*v != 0.0),
638 Value::Text(s) => {
639 let s_ref: &str = s.as_ref();
641 if s_ref.eq_ignore_ascii_case("true")
642 || s_ref.eq_ignore_ascii_case("t")
643 || s_ref.eq_ignore_ascii_case("yes")
644 || s_ref.eq_ignore_ascii_case("y")
645 || s_ref == "1"
646 {
647 Value::Boolean(true)
648 } else if s_ref.eq_ignore_ascii_case("false")
649 || s_ref.eq_ignore_ascii_case("f")
650 || s_ref.eq_ignore_ascii_case("no")
651 || s_ref.eq_ignore_ascii_case("n")
652 || s_ref == "0"
653 {
654 Value::Boolean(false)
655 } else {
656 Value::Null(target_type)
657 }
658 }
659 _ => Value::Null(target_type),
660 },
661 DataType::Timestamp => match self {
662 Value::Timestamp(t) => Value::Timestamp(t),
663 Value::Text(s) => parse_timestamp(&s)
664 .map(Value::Timestamp)
665 .unwrap_or(Value::Null(target_type)),
666 Value::Integer(nanos) => {
667 DateTime::from_timestamp(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
668 .map(Value::Timestamp)
669 .unwrap_or(Value::Null(target_type))
670 }
671 _ => Value::Null(target_type),
672 },
673 DataType::Json => match self {
674 Value::Json(s) => Value::Json(s),
675 Value::Text(s) => {
676 if serde_json::from_str::<serde_json::Value>(s.as_str()).is_ok() {
677 Value::Json(CompactArc::from(s.as_str()))
678 } else {
679 Value::Null(target_type)
680 }
681 }
682 Value::Integer(v) => Value::Json(CompactArc::from(v.to_string())),
683 Value::Float(v) => Value::Json(CompactArc::from(format_float(v))),
684 Value::Boolean(b) => {
685 Value::Json(CompactArc::from(if b { "true" } else { "false" }))
686 }
687 _ => Value::Null(target_type),
688 },
689 DataType::Null => Value::Null(DataType::Null),
690 }
691 }
692}
693
694impl Default for Value {
699 fn default() -> Self {
700 Value::Null(DataType::Null)
701 }
702}
703
704impl fmt::Display for Value {
705 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706 match self {
707 Value::Null(_) => write!(f, "NULL"),
708 Value::Integer(v) => write!(f, "{}", v),
709 Value::Float(v) => write!(f, "{}", format_float(*v)),
710 Value::Text(s) => write!(f, "{}", s),
711 Value::Boolean(b) => write!(f, "{}", if *b { "true" } else { "false" }),
712 Value::Timestamp(t) => write!(f, "{}", t.to_rfc3339()),
713 Value::Json(s) => write!(f, "{}", s),
714 }
715 }
716}
717
718impl PartialEq for Value {
719 #[inline]
720 fn eq(&self, other: &Self) -> bool {
721 match (self, other) {
723 (Value::Null(_), Value::Null(_)) => true,
725 (Value::Null(_), _) | (_, Value::Null(_)) => false,
727 (Value::Integer(a), Value::Integer(b)) => a == b,
729 (Value::Float(a), Value::Float(b)) => {
730 if a.is_nan() && b.is_nan() {
732 true
733 } else {
734 a == b
735 }
736 }
737 (Value::Integer(i), Value::Float(f)) | (Value::Float(f), Value::Integer(i)) => {
740 *f == (*i as f64)
741 }
742 (Value::Text(a), Value::Text(b)) => a == b,
743 (Value::Boolean(a), Value::Boolean(b)) => a == b,
744 (Value::Timestamp(a), Value::Timestamp(b)) => a == b,
745 (Value::Json(a), Value::Json(b)) => a == b,
746 _ => false,
747 }
748 }
749}
750
751impl Eq for Value {}
752
753const I64_SAFE_MAX: i64 = (1_i64 << 53) - 1;
758const I64_SAFE_MIN: i64 = -I64_SAFE_MAX;
759
760#[inline(always)]
765fn wymix(a: u64, b: u64) -> u64 {
766 let r = (a as u128).wrapping_mul(b as u128);
767 (r as u64) ^ ((r >> 64) as u64)
768}
769
770const WY_P1: u64 = 0xa0761d6478bd642f;
772const WY_P2: u64 = 0xe7037ed1a0b428db;
773
774impl Hash for Value {
775 #[inline(always)]
776 fn hash<H: Hasher>(&self, state: &mut H) {
777 match self {
785 Value::Null(_) => {
786 state.write_u64(0);
788 }
789 Value::Integer(v) => {
790 match *v {
792 I64_SAFE_MIN..=I64_SAFE_MAX => {
793 state.write_u64(wymix(1 ^ (*v as u64), WY_P1));
794 }
795 _ => {
796 state.write_u64(wymix(1 ^ (*v as f64).to_bits(), WY_P1));
798 }
799 }
800 }
801 Value::Float(v) => {
802 if v.is_nan() {
803 state.write_u64(wymix(6 ^ f64::NAN.to_bits(), WY_P1));
805 } else if v.fract() == 0.0 {
806 match *v as i64 {
808 i @ I64_SAFE_MIN..=I64_SAFE_MAX => {
809 state.write_u64(wymix(1 ^ (i as u64), WY_P1));
810 }
811 _ => {
812 state.write_u64(wymix(1 ^ v.to_bits(), WY_P1));
813 }
814 }
815 } else {
816 state.write_u64(wymix(6 ^ v.to_bits(), WY_P1));
818 }
819 }
820 Value::Text(s) => {
821 let bytes = s.as_bytes();
823 let len = bytes.len();
824 let mut h = wymix(2 ^ (len as u64), WY_P1);
825
826 let chunks = len / 8;
828 let ptr = bytes.as_ptr();
829 for i in 0..chunks {
830 let chunk = unsafe { (ptr.add(i * 8) as *const u64).read_unaligned() };
834 h = wymix(h ^ chunk, WY_P2);
835 }
836
837 let tail_start = chunks * 8;
839 if tail_start < len {
840 let mut tail = 0u64;
841 for (j, &b) in bytes[tail_start..].iter().enumerate() {
842 tail |= (b as u64) << (j * 8);
843 }
844 h = wymix(h ^ tail, WY_P1);
845 }
846
847 state.write_u64(h);
848 }
849 Value::Boolean(b) => {
850 state.write_u64(wymix(if *b { 5 } else { 4 }, WY_P1));
852 }
853 Value::Timestamp(t) => {
854 let nanos = t.timestamp_nanos_opt().unwrap_or(i64::MAX);
856 state.write_u64(wymix(3 ^ (nanos as u64), WY_P1));
857 }
858 Value::Json(s) => {
859 let bytes = s.as_bytes();
861 let len = bytes.len();
862 let mut h = wymix(7 ^ (len as u64), WY_P1);
863
864 let chunks = len / 8;
865 let ptr = bytes.as_ptr();
866 for i in 0..chunks {
867 let chunk = unsafe { (ptr.add(i * 8) as *const u64).read_unaligned() };
871 h = wymix(h ^ chunk, WY_P2);
872 }
873
874 let tail_start = chunks * 8;
875 if tail_start < len {
876 let mut tail = 0u64;
877 for (j, &b) in bytes[tail_start..].iter().enumerate() {
878 tail |= (b as u64) << (j * 8);
879 }
880 h = wymix(h ^ tail, WY_P1);
881 }
882
883 state.write_u64(h);
884 }
885 }
886 }
887}
888
889#[allow(clippy::non_canonical_partial_ord_impl)]
893impl PartialOrd for Value {
894 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
895 self.compare(other).ok()
899 }
900}
901
902impl Ord for Value {
918 fn cmp(&self, other: &Self) -> Ordering {
919 match (self.is_null(), other.is_null()) {
921 (true, true) => return Ordering::Equal,
922 (true, false) => return Ordering::Less,
923 (false, true) => return Ordering::Greater,
924 (false, false) => {} }
926
927 match (self, other) {
930 (Value::Integer(i), Value::Float(f)) => {
931 let i_as_f64 = *i as f64;
932 if f.is_nan() {
934 return Ordering::Less; }
936 return i_as_f64.partial_cmp(f).unwrap_or(Ordering::Equal);
937 }
938 (Value::Float(f), Value::Integer(i)) => {
939 let i_as_f64 = *i as f64;
940 if f.is_nan() {
942 return Ordering::Greater; }
944 return f.partial_cmp(&i_as_f64).unwrap_or(Ordering::Equal);
945 }
946 _ => {} }
948
949 fn type_discriminant(v: &Value) -> u8 {
951 match v {
952 Value::Null(_) => 0,
953 Value::Boolean(_) => 1,
954 Value::Integer(_) | Value::Float(_) => 2,
957 Value::Text(_) => 3,
958 Value::Timestamp(_) => 4,
959 Value::Json(_) => 5,
960 }
961 }
962
963 let self_disc = type_discriminant(self);
964 let other_disc = type_discriminant(other);
965
966 if self_disc != other_disc {
968 return self_disc.cmp(&other_disc);
969 }
970
971 match (self, other) {
973 (Value::Integer(a), Value::Integer(b)) => a.cmp(b),
974 (Value::Float(a), Value::Float(b)) => {
975 match (a.is_nan(), b.is_nan()) {
977 (true, true) => Ordering::Equal,
978 (true, false) => Ordering::Greater,
979 (false, true) => Ordering::Less,
980 (false, false) => a.partial_cmp(b).unwrap_or(Ordering::Equal),
981 }
982 }
983 (Value::Text(a), Value::Text(b)) => a.cmp(b),
984 (Value::Boolean(a), Value::Boolean(b)) => a.cmp(b),
985 (Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
986 (Value::Json(a), Value::Json(b)) => a.cmp(b), _ => Ordering::Equal, }
989 }
990}
991
992impl From<i64> for Value {
997 fn from(v: i64) -> Self {
998 Value::Integer(v)
999 }
1000}
1001
1002impl From<i32> for Value {
1003 fn from(v: i32) -> Self {
1004 Value::Integer(v as i64)
1005 }
1006}
1007
1008impl From<i16> for Value {
1009 fn from(v: i16) -> Self {
1010 Value::Integer(v as i64)
1011 }
1012}
1013
1014impl From<i8> for Value {
1015 fn from(v: i8) -> Self {
1016 Value::Integer(v as i64)
1017 }
1018}
1019
1020impl From<u32> for Value {
1021 fn from(v: u32) -> Self {
1022 Value::Integer(v as i64)
1023 }
1024}
1025
1026impl From<u16> for Value {
1027 fn from(v: u16) -> Self {
1028 Value::Integer(v as i64)
1029 }
1030}
1031
1032impl From<u8> for Value {
1033 fn from(v: u8) -> Self {
1034 Value::Integer(v as i64)
1035 }
1036}
1037
1038impl From<f64> for Value {
1039 fn from(v: f64) -> Self {
1040 Value::Float(v)
1041 }
1042}
1043
1044impl From<f32> for Value {
1045 fn from(v: f32) -> Self {
1046 Value::Float(v as f64)
1047 }
1048}
1049
1050impl From<String> for Value {
1051 fn from(v: String) -> Self {
1052 Value::Text(SmartString::from_string(v))
1053 }
1054}
1055
1056impl From<&str> for Value {
1057 fn from(v: &str) -> Self {
1058 Value::Text(SmartString::from(v))
1059 }
1060}
1061
1062impl From<Arc<str>> for Value {
1063 fn from(v: Arc<str>) -> Self {
1064 Value::Text(SmartString::from(v.as_ref()))
1065 }
1066}
1067
1068impl From<bool> for Value {
1069 fn from(v: bool) -> Self {
1070 Value::Boolean(v)
1071 }
1072}
1073
1074impl From<DateTime<Utc>> for Value {
1075 fn from(v: DateTime<Utc>) -> Self {
1076 Value::Timestamp(v)
1077 }
1078}
1079
1080impl<T: Into<Value>> From<Option<T>> for Value {
1081 fn from(v: Option<T>) -> Self {
1082 match v {
1083 Some(val) => val.into(),
1084 None => Value::Null(DataType::Null),
1085 }
1086 }
1087}
1088
1089pub fn parse_timestamp(s: &str) -> Result<DateTime<Utc>> {
1095 let s = s.trim();
1096
1097 for format in TIMESTAMP_FORMATS {
1099 if let Ok(dt) = DateTime::parse_from_str(s, format) {
1100 return Ok(dt.with_timezone(&Utc));
1101 }
1102 if let Ok(ndt) = NaiveDateTime::parse_from_str(s, format) {
1104 return Ok(Utc.from_utc_datetime(&ndt));
1105 }
1106 }
1107
1108 if let Ok(date) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
1110 let datetime = date.and_hms_opt(0, 0, 0).unwrap();
1111 return Ok(Utc.from_utc_datetime(&datetime));
1112 }
1113
1114 for format in TIME_FORMATS {
1116 if let Ok(time) = NaiveTime::parse_from_str(s, format) {
1117 let today = Utc::now().date_naive();
1118 let datetime = today.and_time(time);
1119 return Ok(Utc.from_utc_datetime(&datetime));
1120 }
1121 }
1122
1123 Err(Error::parse(format!("invalid timestamp format: {}", s)))
1124}
1125
1126fn format_float(v: f64) -> String {
1128 if v.is_nan() {
1130 return "NaN".to_string();
1131 }
1132 if v.is_infinite() {
1133 return if v.is_sign_positive() {
1134 "Infinity"
1135 } else {
1136 "-Infinity"
1137 }
1138 .to_string();
1139 }
1140
1141 let abs_v = v.abs();
1142
1143 if abs_v != 0.0 && !(1e-4..1e15).contains(&abs_v) {
1145 let s = format!("{:e}", v);
1147 if let Some(e_pos) = s.find('e') {
1149 let (mantissa, exp) = s.split_at(e_pos);
1150 let clean_mantissa = if mantissa.contains('.') {
1151 mantissa
1152 .trim_end_matches('0')
1153 .trim_end_matches('.')
1154 .to_string()
1155 } else {
1156 mantissa.to_string()
1157 };
1158 return format!("{}{}", clean_mantissa, exp);
1159 }
1160 return s;
1161 }
1162
1163 if v.fract() == 0.0 {
1164 format!("{:.0}", v)
1166 } else {
1167 let s = format!("{:?}", v);
1169 if s.contains('.') && !s.contains('e') && !s.contains('E') {
1171 s.trim_end_matches('0').trim_end_matches('.').to_string()
1172 } else {
1173 s
1174 }
1175 }
1176}
1177
1178fn compare_floats(a: f64, b: f64) -> Ordering {
1180 match (a.is_nan(), b.is_nan()) {
1182 (true, true) => Ordering::Equal,
1183 (true, false) => Ordering::Greater,
1184 (false, true) => Ordering::Less,
1185 (false, false) => a.partial_cmp(&b).unwrap_or(Ordering::Equal),
1186 }
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191 use super::*;
1192 use chrono::{Datelike, Timelike};
1193
1194 #[test]
1199 fn test_value_size() {
1200 use std::mem::size_of;
1201
1202 assert_eq!(
1204 size_of::<Value>(),
1205 16,
1206 "Value should be 16 bytes, got {}",
1207 size_of::<Value>()
1208 );
1209
1210 assert_eq!(
1212 size_of::<Option<Value>>(),
1213 16,
1214 "Option<Value> should be 16 bytes (niche optimization), got {}",
1215 size_of::<Option<Value>>()
1216 );
1217 }
1218
1219 #[test]
1224 fn test_constructors() {
1225 assert!(Value::null(DataType::Integer).is_null());
1226 assert_eq!(Value::integer(42).as_int64(), Some(42));
1227 assert_eq!(Value::float(3.5).as_float64(), Some(3.5));
1228 assert_eq!(Value::text("hello").as_str(), Some("hello"));
1229 assert_eq!(Value::boolean(true).as_boolean(), Some(true));
1230 assert!(Value::json(r#"{"key": "value"}"#).as_json().is_some());
1231 }
1232
1233 #[test]
1234 fn test_from_implementations() {
1235 let v: Value = 42i64.into();
1236 assert_eq!(v.as_int64(), Some(42));
1237
1238 let v: Value = 3.5f64.into();
1239 assert_eq!(v.as_float64(), Some(3.5));
1240
1241 let v: Value = "hello".into();
1242 assert_eq!(v.as_str(), Some("hello"));
1243
1244 let v: Value = true.into();
1245 assert_eq!(v.as_boolean(), Some(true));
1246
1247 let v: Value = Option::<i64>::None.into();
1248 assert!(v.is_null());
1249
1250 let v: Value = Some(42i64).into();
1251 assert_eq!(v.as_int64(), Some(42));
1252 }
1253
1254 #[test]
1259 fn test_data_type() {
1260 assert_eq!(
1261 Value::null(DataType::Integer).data_type(),
1262 DataType::Integer
1263 );
1264 assert_eq!(Value::integer(42).data_type(), DataType::Integer);
1265 assert_eq!(Value::float(3.5).data_type(), DataType::Float);
1266 assert_eq!(Value::text("hello").data_type(), DataType::Text);
1267 assert_eq!(Value::boolean(true).data_type(), DataType::Boolean);
1268 assert_eq!(
1269 Value::Timestamp(Utc::now()).data_type(),
1270 DataType::Timestamp
1271 );
1272 assert_eq!(Value::json("{}").data_type(), DataType::Json);
1273 }
1274
1275 #[test]
1280 fn test_as_int64() {
1281 assert_eq!(Value::integer(42).as_int64(), Some(42));
1283
1284 assert_eq!(Value::float(3.7).as_int64(), Some(3));
1286 assert_eq!(Value::float(-3.7).as_int64(), Some(-3));
1287
1288 assert_eq!(Value::text("42").as_int64(), Some(42));
1290 assert_eq!(Value::text("-42").as_int64(), Some(-42));
1291 assert_eq!(Value::text("3.7").as_int64(), Some(3)); assert_eq!(Value::boolean(true).as_int64(), Some(1));
1295 assert_eq!(Value::boolean(false).as_int64(), Some(0));
1296
1297 assert_eq!(Value::null(DataType::Integer).as_int64(), None);
1299
1300 assert_eq!(Value::text("not a number").as_int64(), None);
1302 }
1303
1304 #[test]
1305 fn test_as_float64() {
1306 assert_eq!(Value::float(3.5).as_float64(), Some(3.5));
1308
1309 assert_eq!(Value::integer(42).as_float64(), Some(42.0));
1311
1312 assert_eq!(Value::text("3.5").as_float64(), Some(3.5));
1314
1315 assert_eq!(Value::boolean(true).as_float64(), Some(1.0));
1317 assert_eq!(Value::boolean(false).as_float64(), Some(0.0));
1318
1319 assert_eq!(Value::null(DataType::Float).as_float64(), None);
1321 }
1322
1323 #[test]
1324 fn test_as_boolean() {
1325 assert_eq!(Value::boolean(true).as_boolean(), Some(true));
1327 assert_eq!(Value::boolean(false).as_boolean(), Some(false));
1328
1329 assert_eq!(Value::integer(1).as_boolean(), Some(true));
1331 assert_eq!(Value::integer(0).as_boolean(), Some(false));
1332 assert_eq!(Value::integer(-1).as_boolean(), Some(true));
1333
1334 assert_eq!(Value::float(1.0).as_boolean(), Some(true));
1336 assert_eq!(Value::float(0.0).as_boolean(), Some(false));
1337
1338 assert_eq!(Value::text("true").as_boolean(), Some(true));
1340 assert_eq!(Value::text("TRUE").as_boolean(), Some(true));
1341 assert_eq!(Value::text("t").as_boolean(), Some(true));
1342 assert_eq!(Value::text("yes").as_boolean(), Some(true));
1343 assert_eq!(Value::text("y").as_boolean(), Some(true));
1344 assert_eq!(Value::text("1").as_boolean(), Some(true));
1345 assert_eq!(Value::text("false").as_boolean(), Some(false));
1346 assert_eq!(Value::text("FALSE").as_boolean(), Some(false));
1347 assert_eq!(Value::text("f").as_boolean(), Some(false));
1348 assert_eq!(Value::text("no").as_boolean(), Some(false));
1349 assert_eq!(Value::text("n").as_boolean(), Some(false));
1350 assert_eq!(Value::text("0").as_boolean(), Some(false));
1351 assert_eq!(Value::text("").as_boolean(), Some(false));
1352
1353 assert_eq!(Value::text("42").as_boolean(), Some(true));
1355 assert_eq!(Value::text("0.0").as_boolean(), Some(false));
1356 }
1357
1358 #[test]
1359 fn test_as_string() {
1360 assert_eq!(Value::text("hello").as_string(), Some("hello".to_string()));
1362
1363 assert_eq!(Value::integer(42).as_string(), Some("42".to_string()));
1365
1366 assert_eq!(Value::float(3.5).as_string(), Some("3.5".to_string()));
1368
1369 assert_eq!(Value::boolean(true).as_string(), Some("true".to_string()));
1371 assert_eq!(Value::boolean(false).as_string(), Some("false".to_string()));
1372
1373 assert_eq!(Value::null(DataType::Text).as_string(), None);
1375 }
1376
1377 #[test]
1382 fn test_equality() {
1383 assert_eq!(Value::integer(42), Value::integer(42));
1385 assert_ne!(Value::integer(42), Value::integer(43));
1386
1387 assert_eq!(Value::float(3.5), Value::float(3.5));
1388 assert_ne!(Value::float(3.5), Value::float(3.15));
1389
1390 assert_eq!(Value::text("hello"), Value::text("hello"));
1391 assert_ne!(Value::text("hello"), Value::text("world"));
1392
1393 assert_eq!(Value::boolean(true), Value::boolean(true));
1394 assert_ne!(Value::boolean(true), Value::boolean(false));
1395
1396 assert_eq!(Value::null(DataType::Integer), Value::null(DataType::Float));
1398 assert_ne!(Value::null(DataType::Integer), Value::integer(0));
1399
1400 assert_eq!(Value::integer(1), Value::float(1.0));
1403 assert_eq!(Value::integer(5), Value::float(5.0));
1404 assert_ne!(Value::integer(1), Value::float(1.5)); assert_ne!(Value::text("1"), Value::integer(1));
1408 }
1409
1410 #[test]
1411 fn test_float_nan_equality() {
1412 let nan = Value::float(f64::NAN);
1414 assert_eq!(nan, nan.clone());
1415 }
1416
1417 #[test]
1422 fn test_compare_integers() {
1423 assert_eq!(
1424 Value::integer(1).compare(&Value::integer(2)).unwrap(),
1425 Ordering::Less
1426 );
1427 assert_eq!(
1428 Value::integer(2).compare(&Value::integer(2)).unwrap(),
1429 Ordering::Equal
1430 );
1431 assert_eq!(
1432 Value::integer(3).compare(&Value::integer(2)).unwrap(),
1433 Ordering::Greater
1434 );
1435 }
1436
1437 #[test]
1438 fn test_compare_floats() {
1439 assert_eq!(
1440 Value::float(1.0).compare(&Value::float(2.0)).unwrap(),
1441 Ordering::Less
1442 );
1443 assert_eq!(
1444 Value::float(2.0).compare(&Value::float(2.0)).unwrap(),
1445 Ordering::Equal
1446 );
1447 assert_eq!(
1448 Value::float(3.0).compare(&Value::float(2.0)).unwrap(),
1449 Ordering::Greater
1450 );
1451 }
1452
1453 #[test]
1454 fn test_compare_cross_type_numeric() {
1455 assert_eq!(
1457 Value::integer(1).compare(&Value::float(2.0)).unwrap(),
1458 Ordering::Less
1459 );
1460 assert_eq!(
1461 Value::integer(2).compare(&Value::float(2.0)).unwrap(),
1462 Ordering::Equal
1463 );
1464 assert_eq!(
1465 Value::float(3.0).compare(&Value::integer(2)).unwrap(),
1466 Ordering::Greater
1467 );
1468 }
1469
1470 #[test]
1471 fn test_compare_strings() {
1472 assert_eq!(
1473 Value::text("a").compare(&Value::text("b")).unwrap(),
1474 Ordering::Less
1475 );
1476 assert_eq!(
1477 Value::text("b").compare(&Value::text("b")).unwrap(),
1478 Ordering::Equal
1479 );
1480 assert_eq!(
1481 Value::text("c").compare(&Value::text("b")).unwrap(),
1482 Ordering::Greater
1483 );
1484 }
1485
1486 #[test]
1487 fn test_compare_null() {
1488 assert_eq!(
1490 Value::null(DataType::Integer)
1491 .compare(&Value::null(DataType::Float))
1492 .unwrap(),
1493 Ordering::Equal
1494 );
1495
1496 assert!(Value::null(DataType::Integer)
1498 .compare(&Value::integer(0))
1499 .is_err());
1500 assert!(Value::integer(0)
1501 .compare(&Value::null(DataType::Integer))
1502 .is_err());
1503 }
1504
1505 #[test]
1506 fn test_compare_json_error() {
1507 let j1 = Value::json(r#"{"a": 1}"#);
1509 let j2 = Value::json(r#"{"b": 2}"#);
1510 assert!(j1.compare(&j2).is_err());
1511
1512 let j3 = Value::json(r#"{"a": 1}"#);
1514 assert_eq!(j1.compare(&j3).unwrap(), Ordering::Equal);
1515 }
1516
1517 #[test]
1522 fn test_parse_timestamp() {
1523 let ts = parse_timestamp("2024-01-15T10:30:00Z").unwrap();
1525 assert_eq!(ts.year(), 2024);
1526 assert_eq!(ts.month(), 1);
1527 assert_eq!(ts.day(), 15);
1528 assert_eq!(ts.hour(), 10);
1529 assert_eq!(ts.minute(), 30);
1530
1531 let ts = parse_timestamp("2024-01-15 10:30:00").unwrap();
1533 assert_eq!(ts.year(), 2024);
1534
1535 let ts = parse_timestamp("2024-01-15").unwrap();
1537 assert_eq!(ts.year(), 2024);
1538 assert_eq!(ts.hour(), 0);
1539
1540 assert!(parse_timestamp("not a date").is_err());
1542 }
1543
1544 #[test]
1549 fn test_display() {
1550 assert_eq!(Value::null(DataType::Integer).to_string(), "NULL");
1551 assert_eq!(Value::integer(42).to_string(), "42");
1552 assert_eq!(Value::float(3.5).to_string(), "3.5");
1553 assert_eq!(Value::text("hello").to_string(), "hello");
1554 assert_eq!(Value::boolean(true).to_string(), "true");
1555 assert_eq!(Value::boolean(false).to_string(), "false");
1556 }
1557
1558 #[test]
1563 fn test_hash() {
1564 use rustc_hash::FxHashSet;
1565
1566 let mut set = FxHashSet::default();
1567 set.insert(Value::integer(42));
1568 set.insert(Value::integer(42)); set.insert(Value::integer(43));
1570
1571 assert_eq!(set.len(), 2);
1572 assert!(set.contains(&Value::integer(42)));
1573 assert!(set.contains(&Value::integer(43)));
1574 }
1575
1576 #[test]
1577 fn test_hash_integer_float_consistency() {
1578 use std::hash::{DefaultHasher, Hash, Hasher};
1579
1580 fn hash_value(v: &Value) -> u64 {
1581 let mut hasher = DefaultHasher::new();
1582 v.hash(&mut hasher);
1583 hasher.finish()
1584 }
1585
1586 assert_eq!(
1588 hash_value(&Value::integer(5)),
1589 hash_value(&Value::float(5.0))
1590 );
1591 assert_eq!(
1592 hash_value(&Value::integer(-100)),
1593 hash_value(&Value::float(-100.0))
1594 );
1595 assert_eq!(
1596 hash_value(&Value::integer(0)),
1597 hash_value(&Value::float(0.0))
1598 );
1599
1600 assert_ne!(
1602 hash_value(&Value::float(5.5)),
1603 hash_value(&Value::integer(5))
1604 );
1605 assert_ne!(
1606 hash_value(&Value::float(5.5)),
1607 hash_value(&Value::integer(6))
1608 );
1609
1610 let safe_max = (1_i64 << 53) - 1; assert_eq!(
1613 hash_value(&Value::integer(safe_max)),
1614 hash_value(&Value::float(safe_max as f64))
1615 );
1616 assert_eq!(
1617 hash_value(&Value::integer(-safe_max)),
1618 hash_value(&Value::float(-safe_max as f64))
1619 );
1620
1621 let boundary = 1_i64 << 53; assert_eq!(
1624 hash_value(&Value::integer(boundary)),
1625 hash_value(&Value::float(boundary as f64))
1626 );
1627
1628 let large = boundary + 1; let large_as_f64 = large as f64; assert_eq!(
1633 hash_value(&Value::integer(large)),
1634 hash_value(&Value::float(large_as_f64))
1635 );
1636 }
1637
1638 #[test]
1639 fn test_hash_in_hashmap() {
1640 use rustc_hash::FxHashMap;
1641
1642 let mut map = FxHashMap::default();
1644 map.insert(Value::integer(42), "int");
1645
1646 assert_eq!(map.get(&Value::float(42.0)), Some(&"int"));
1648
1649 map.insert(Value::float(42.0), "float");
1651 assert_eq!(map.len(), 1);
1652 assert_eq!(map.get(&Value::integer(42)), Some(&"float"));
1653 }
1654
1655 #[test]
1656 fn test_hash_nan_consistency() {
1657 use std::hash::{DefaultHasher, Hash, Hasher};
1658
1659 fn hash_value(v: &Value) -> u64 {
1660 let mut hasher = DefaultHasher::new();
1661 v.hash(&mut hasher);
1662 hasher.finish()
1663 }
1664
1665 let nan1 = Value::float(f64::NAN);
1667 let nan2 = Value::float(f64::from_bits(0x7ff8000000000001)); let nan3 = Value::float(f64::INFINITY - f64::INFINITY);
1670
1671 assert_eq!(hash_value(&nan1), hash_value(&nan2));
1672 assert_eq!(hash_value(&nan2), hash_value(&nan3));
1673
1674 assert_eq!(nan1, nan2);
1676 assert_eq!(nan2, nan3);
1677 }
1678}