1use std::{
9 cmp::Ordering,
10 fmt::{Display, Formatter},
11};
12
13use num_traits::ToPrimitive;
14use serde::{Deserialize, Serialize};
15pub mod as_string;
16pub mod blob;
17pub mod boolean;
18pub mod constraint;
19pub mod container;
20pub mod date;
21pub mod datetime;
22pub mod decimal;
23pub mod dictionary;
24pub mod duration;
25pub mod frame;
26pub mod identity;
27pub mod int;
28pub mod into;
29pub mod is;
30pub mod iso;
31pub mod json;
32pub mod number;
33pub mod ordered_f32;
34pub mod ordered_f64;
35pub mod partition;
36pub mod percentile;
37pub mod row_number;
38pub mod sumtype;
39pub mod system_columns;
40pub mod temporal;
41pub mod time;
42pub mod to_value;
43pub mod try_from;
44pub mod uint;
45pub mod uuid;
46pub mod value_type;
47
48use std::{fmt, hash, mem};
49
50use blob::Blob;
51use date::Date;
52use datetime::DateTime;
53use decimal::Decimal;
54use dictionary::DictionaryEntryId;
55use duration::Duration;
56use identity::IdentityId;
57use int::Int;
58use ordered_f32::OrderedF32;
59use ordered_f64::OrderedF64;
60use time::Time;
61use uint::Uint;
62use uuid::{Uuid4, Uuid7};
63use value_type::ValueType;
64
65#[derive(Clone, Debug, Serialize, Deserialize)]
66pub enum Value {
67 None {
68 inner: ValueType,
69 },
70
71 Boolean(bool),
72
73 Float4(OrderedF32),
74
75 Float8(OrderedF64),
76
77 Int1(i8),
78
79 Int2(i16),
80
81 Int4(i32),
82
83 Int8(i64),
84
85 Int16(i128),
86
87 Utf8(String),
88
89 Uint1(u8),
90
91 Uint2(u16),
92
93 Uint4(u32),
94
95 Uint8(u64),
96
97 Uint16(u128),
98
99 Date(Date),
100
101 DateTime(DateTime),
102
103 Time(Time),
104
105 Duration(Duration),
106
107 IdentityId(IdentityId),
108
109 Uuid4(Uuid4),
110
111 Uuid7(Uuid7),
112
113 Blob(Blob),
114
115 Int(Int),
116
117 Uint(Uint),
118
119 Decimal(Decimal),
120
121 Any(Box<Value>),
122
123 DictionaryId(DictionaryEntryId),
124
125 Type(ValueType),
126
127 List(Vec<Value>),
128
129 Record(Vec<(String, Value)>),
130
131 Tuple(Vec<Value>),
132}
133
134impl Value {
135 pub fn none() -> Self {
136 Value::None {
137 inner: ValueType::Any,
138 }
139 }
140
141 pub fn none_of(ty: ValueType) -> Self {
142 Value::None {
143 inner: ty,
144 }
145 }
146
147 pub fn bool(v: impl Into<bool>) -> Self {
148 Value::Boolean(v.into())
149 }
150
151 pub fn float4(v: impl Into<f32>) -> Self {
152 OrderedF32::try_from(v.into()).map(Value::Float4).unwrap_or(Value::None {
153 inner: ValueType::Float4,
154 })
155 }
156
157 pub fn float8(v: impl Into<f64>) -> Self {
158 OrderedF64::try_from(v.into()).map(Value::Float8).unwrap_or(Value::None {
159 inner: ValueType::Float8,
160 })
161 }
162
163 pub fn int1(v: impl Into<i8>) -> Self {
164 Value::Int1(v.into())
165 }
166
167 pub fn int2(v: impl Into<i16>) -> Self {
168 Value::Int2(v.into())
169 }
170
171 pub fn int4(v: impl Into<i32>) -> Self {
172 Value::Int4(v.into())
173 }
174
175 pub fn int8(v: impl Into<i64>) -> Self {
176 Value::Int8(v.into())
177 }
178
179 pub fn int16(v: impl Into<i128>) -> Self {
180 Value::Int16(v.into())
181 }
182
183 pub fn utf8(v: impl Into<String>) -> Self {
184 Value::Utf8(v.into())
185 }
186
187 pub fn uint1(v: impl Into<u8>) -> Self {
188 Value::Uint1(v.into())
189 }
190
191 pub fn uint2(v: impl Into<u16>) -> Self {
192 Value::Uint2(v.into())
193 }
194
195 pub fn uint4(v: impl Into<u32>) -> Self {
196 Value::Uint4(v.into())
197 }
198
199 pub fn uint8(v: impl Into<u64>) -> Self {
200 Value::Uint8(v.into())
201 }
202
203 pub fn uint16(v: impl Into<u128>) -> Self {
204 Value::Uint16(v.into())
205 }
206
207 pub fn date(v: impl Into<Date>) -> Self {
208 Value::Date(v.into())
209 }
210
211 pub fn datetime(v: impl Into<DateTime>) -> Self {
212 Value::DateTime(v.into())
213 }
214
215 pub fn time(v: impl Into<Time>) -> Self {
216 Value::Time(v.into())
217 }
218
219 pub fn duration(v: impl Into<Duration>) -> Self {
220 Value::Duration(v.into())
221 }
222
223 pub fn duration_nanoseconds(nanoseconds: i64) -> Self {
224 Value::Duration(Duration::from_nanoseconds_const(nanoseconds))
225 }
226
227 pub fn duration_microseconds(microseconds: i64) -> Self {
228 Value::Duration(Duration::from_microseconds_const(microseconds))
229 }
230
231 pub fn duration_milliseconds(milliseconds: i64) -> Self {
232 Value::Duration(Duration::from_milliseconds_const(milliseconds))
233 }
234
235 pub fn duration_seconds(seconds: i64) -> Self {
236 Value::Duration(Duration::from_seconds_const(seconds))
237 }
238
239 pub fn duration_minutes(minutes: i64) -> Self {
240 Value::Duration(Duration::from_minutes_const(minutes))
241 }
242
243 pub fn duration_hours(hours: i64) -> Self {
244 Value::Duration(Duration::from_hours_const(hours))
245 }
246
247 pub fn identity_id(v: impl Into<IdentityId>) -> Self {
248 Value::IdentityId(v.into())
249 }
250
251 pub fn uuid4(v: impl Into<Uuid4>) -> Self {
252 Value::Uuid4(v.into())
253 }
254
255 pub fn uuid7(v: impl Into<Uuid7>) -> Self {
256 Value::Uuid7(v.into())
257 }
258
259 pub fn blob(v: impl Into<Blob>) -> Self {
260 Value::Blob(v.into())
261 }
262
263 pub fn any(v: impl Into<Value>) -> Self {
264 Value::Any(Box::new(v.into()))
265 }
266
267 pub fn list(items: Vec<Value>) -> Self {
268 Value::List(items)
269 }
270
271 pub fn record(fields: Vec<(String, Value)>) -> Self {
272 Value::Record(fields)
273 }
274
275 pub fn to_usize(&self) -> Option<usize> {
276 match self {
277 Value::Uint1(v) => Some(*v as usize),
278 Value::Uint2(v) => Some(*v as usize),
279 Value::Uint4(v) => Some(*v as usize),
280 Value::Uint8(v) => usize::try_from(*v).ok(),
281 Value::Uint16(v) => usize::try_from(*v).ok(),
282 Value::Int1(v) => usize::try_from(*v).ok(),
283 Value::Int2(v) => usize::try_from(*v).ok(),
284 Value::Int4(v) => usize::try_from(*v).ok(),
285 Value::Int8(v) => usize::try_from(*v).ok(),
286 Value::Int16(v) => usize::try_from(*v).ok(),
287 Value::Float4(v) => {
288 let f = v.value();
289 if f >= 0.0 {
290 Some(f as usize)
291 } else {
292 None
293 }
294 }
295 Value::Float8(v) => {
296 let f = v.value();
297 if f >= 0.0 {
298 Some(f as usize)
299 } else {
300 None
301 }
302 }
303 Value::Int(v) => v.0.to_u64().and_then(|n| usize::try_from(n).ok()),
304 Value::Uint(v) => v.0.to_u64().and_then(|n| usize::try_from(n).ok()),
305 Value::Decimal(v) => v.0.to_u64().and_then(|n| usize::try_from(n).ok()),
306 Value::Utf8(s) => {
307 let s = s.trim();
308 if let Ok(n) = s.parse::<u64>() {
309 usize::try_from(n).ok()
310 } else if let Ok(f) = s.parse::<f64>() {
311 if f >= 0.0 {
312 Some(f as usize)
313 } else {
314 None
315 }
316 } else {
317 None
318 }
319 }
320 _ => None,
321 }
322 }
323}
324
325impl PartialEq for Value {
326 fn eq(&self, other: &Self) -> bool {
327 match (self, other) {
328 (
329 Value::None {
330 inner: l,
331 },
332 Value::None {
333 inner: r,
334 },
335 ) => l == r,
336 (Value::Boolean(l), Value::Boolean(r)) => l == r,
337 (Value::Float4(l), Value::Float4(r)) => l == r,
338 (Value::Float8(l), Value::Float8(r)) => l == r,
339 (Value::Int1(l), Value::Int1(r)) => l == r,
340 (Value::Int2(l), Value::Int2(r)) => l == r,
341 (Value::Int4(l), Value::Int4(r)) => l == r,
342 (Value::Int8(l), Value::Int8(r)) => l == r,
343 (Value::Int16(l), Value::Int16(r)) => l == r,
344 (Value::Utf8(l), Value::Utf8(r)) => l == r,
345 (Value::Uint1(l), Value::Uint1(r)) => l == r,
346 (Value::Uint2(l), Value::Uint2(r)) => l == r,
347 (Value::Uint4(l), Value::Uint4(r)) => l == r,
348 (Value::Uint8(l), Value::Uint8(r)) => l == r,
349 (Value::Uint16(l), Value::Uint16(r)) => l == r,
350 (Value::Date(l), Value::Date(r)) => l == r,
351 (Value::DateTime(l), Value::DateTime(r)) => l == r,
352 (Value::Time(l), Value::Time(r)) => l == r,
353 (Value::Duration(l), Value::Duration(r)) => l == r,
354 (Value::IdentityId(l), Value::IdentityId(r)) => l == r,
355 (Value::Uuid4(l), Value::Uuid4(r)) => l == r,
356 (Value::Uuid7(l), Value::Uuid7(r)) => l == r,
357 (Value::Blob(l), Value::Blob(r)) => l == r,
358 (Value::Int(l), Value::Int(r)) => l == r,
359 (Value::Uint(l), Value::Uint(r)) => l == r,
360 (Value::Decimal(l), Value::Decimal(r)) => l == r,
361 (Value::Any(l), Value::Any(r)) => l == r,
362 (Value::DictionaryId(l), Value::DictionaryId(r)) => l == r,
363 (Value::Type(l), Value::Type(r)) => l == r,
364 (Value::List(l), Value::List(r)) => l == r,
365 (Value::Record(l), Value::Record(r)) => l == r,
366 (Value::Tuple(l), Value::Tuple(r)) => l == r,
367 _ => false,
368 }
369 }
370}
371
372impl Eq for Value {}
373
374#[cfg(reifydb_assertions)]
375pub fn assert_equal_with_tolerance(left: &[Value], right: &[Value]) {
376 const REL_EPS: f64 = 1e-9;
377 const ABS_EPS: f64 = 1e-6;
378 fn close(x: f64, y: f64) -> bool {
379 if x.is_nan() && y.is_nan() {
380 return true;
381 }
382 (x - y).abs() <= ABS_EPS.max(REL_EPS * x.abs().max(y.abs()))
383 }
384 fn matches(a: &Value, b: &Value) -> bool {
385 match (a, b) {
386 (Value::Float8(x), Value::Float8(y)) => close(x.value(), y.value()),
387 (Value::Float4(x), Value::Float4(y)) => close(x.value() as f64, y.value() as f64),
388 _ => a == b,
389 }
390 }
391 assert_eq!(left.len(), right.len(), "value count diverges beyond tolerance: {} vs {}", left.len(), right.len());
392 for (i, (l, r)) in left.iter().zip(right).enumerate() {
393 assert!(matches(l, r), "value {i} diverges beyond tolerance: {l:?} vs {r:?}");
394 }
395}
396
397impl hash::Hash for Value {
398 fn hash<H: hash::Hasher>(&self, state: &mut H) {
399 mem::discriminant(self).hash(state);
400 match self {
401 Value::None {
402 ..
403 } => {}
404 Value::Boolean(v) => v.hash(state),
405 Value::Float4(v) => v.hash(state),
406 Value::Float8(v) => v.hash(state),
407 Value::Int1(v) => v.hash(state),
408 Value::Int2(v) => v.hash(state),
409 Value::Int4(v) => v.hash(state),
410 Value::Int8(v) => v.hash(state),
411 Value::Int16(v) => v.hash(state),
412 Value::Utf8(v) => v.hash(state),
413 Value::Uint1(v) => v.hash(state),
414 Value::Uint2(v) => v.hash(state),
415 Value::Uint4(v) => v.hash(state),
416 Value::Uint8(v) => v.hash(state),
417 Value::Uint16(v) => v.hash(state),
418 Value::Date(v) => v.hash(state),
419 Value::DateTime(v) => v.hash(state),
420 Value::Time(v) => v.hash(state),
421 Value::Duration(v) => v.hash(state),
422 Value::IdentityId(v) => v.hash(state),
423 Value::Uuid4(v) => v.hash(state),
424 Value::Uuid7(v) => v.hash(state),
425 Value::Blob(v) => v.hash(state),
426 Value::Int(v) => v.hash(state),
427 Value::Uint(v) => v.hash(state),
428 Value::Decimal(v) => v.hash(state),
429 Value::Any(v) => v.hash(state),
430 Value::DictionaryId(v) => v.hash(state),
431 Value::Type(v) => v.hash(state),
432 Value::List(v) => v.hash(state),
433 Value::Record(fields) => {
434 for (k, v) in fields {
435 k.hash(state);
436 v.hash(state);
437 }
438 }
439 Value::Tuple(v) => v.hash(state),
440 }
441 }
442}
443
444impl PartialOrd for Value {
445 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
446 Some(self.cmp(other))
447 }
448}
449
450impl Ord for Value {
451 fn cmp(&self, other: &Self) -> Ordering {
452 match (self, other) {
453 (
454 Value::None {
455 ..
456 },
457 Value::None {
458 ..
459 },
460 ) => Ordering::Equal,
461 (
462 Value::None {
463 ..
464 },
465 _,
466 ) => Ordering::Greater,
467 (
468 _,
469 Value::None {
470 ..
471 },
472 ) => Ordering::Less,
473 (Value::Boolean(l), Value::Boolean(r)) => l.cmp(r),
474 (Value::Float4(l), Value::Float4(r)) => l.cmp(r),
475 (Value::Float8(l), Value::Float8(r)) => l.cmp(r),
476 (Value::Int1(l), Value::Int1(r)) => l.cmp(r),
477 (Value::Int2(l), Value::Int2(r)) => l.cmp(r),
478 (Value::Int4(l), Value::Int4(r)) => l.cmp(r),
479 (Value::Int8(l), Value::Int8(r)) => l.cmp(r),
480 (Value::Int16(l), Value::Int16(r)) => l.cmp(r),
481 (Value::Utf8(l), Value::Utf8(r)) => l.cmp(r),
482 (Value::Uint1(l), Value::Uint1(r)) => l.cmp(r),
483 (Value::Uint2(l), Value::Uint2(r)) => l.cmp(r),
484 (Value::Uint4(l), Value::Uint4(r)) => l.cmp(r),
485 (Value::Uint8(l), Value::Uint8(r)) => l.cmp(r),
486 (Value::Uint16(l), Value::Uint16(r)) => l.cmp(r),
487 (Value::Date(l), Value::Date(r)) => l.cmp(r),
488 (Value::DateTime(l), Value::DateTime(r)) => l.cmp(r),
489 (Value::Time(l), Value::Time(r)) => l.cmp(r),
490 (Value::Duration(l), Value::Duration(r)) => l.cmp(r),
491 (Value::IdentityId(l), Value::IdentityId(r)) => l.cmp(r),
492 (Value::Uuid4(l), Value::Uuid4(r)) => l.cmp(r),
493 (Value::Uuid7(l), Value::Uuid7(r)) => l.cmp(r),
494 (Value::Blob(l), Value::Blob(r)) => l.cmp(r),
495 (Value::Int(l), Value::Int(r)) => l.cmp(r),
496 (Value::Uint(l), Value::Uint(r)) => l.cmp(r),
497 (Value::Decimal(l), Value::Decimal(r)) => l.cmp(r),
498 (Value::DictionaryId(l), Value::DictionaryId(r)) => l.to_u128().cmp(&r.to_u128()),
499 (Value::Type(l), Value::Type(r)) => l.cmp(r),
500 (Value::List(_), Value::List(_)) => unreachable!("List values are not orderable"),
501 (Value::Record(_), Value::Record(_)) => unreachable!("Record values are not orderable"),
502 (Value::Tuple(_), Value::Tuple(_)) => unreachable!("Tuple values are not orderable"),
503 (Value::Any(_), Value::Any(_)) => unreachable!("Any values are not orderable"),
504 _ => unimplemented!(),
505 }
506 }
507}
508
509impl Display for Value {
510 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
511 match self {
512 Value::Boolean(true) => f.write_str("true"),
513 Value::Boolean(false) => f.write_str("false"),
514 Value::Float4(value) => Display::fmt(value, f),
515 Value::Float8(value) => Display::fmt(value, f),
516 Value::Int1(value) => Display::fmt(value, f),
517 Value::Int2(value) => Display::fmt(value, f),
518 Value::Int4(value) => Display::fmt(value, f),
519 Value::Int8(value) => Display::fmt(value, f),
520 Value::Int16(value) => Display::fmt(value, f),
521 Value::Utf8(value) => Display::fmt(value, f),
522 Value::Uint1(value) => Display::fmt(value, f),
523 Value::Uint2(value) => Display::fmt(value, f),
524 Value::Uint4(value) => Display::fmt(value, f),
525 Value::Uint8(value) => Display::fmt(value, f),
526 Value::Uint16(value) => Display::fmt(value, f),
527 Value::Date(value) => Display::fmt(value, f),
528 Value::DateTime(value) => Display::fmt(value, f),
529 Value::Time(value) => Display::fmt(value, f),
530 Value::Duration(value) => Display::fmt(value, f),
531 Value::IdentityId(value) => Display::fmt(value, f),
532 Value::Uuid4(value) => Display::fmt(value, f),
533 Value::Uuid7(value) => Display::fmt(value, f),
534 Value::Blob(value) => Display::fmt(value, f),
535 Value::Int(value) => Display::fmt(value, f),
536 Value::Uint(value) => Display::fmt(value, f),
537 Value::Decimal(value) => Display::fmt(value, f),
538 Value::Any(value) => Display::fmt(value, f),
539 Value::DictionaryId(value) => Display::fmt(value, f),
540 Value::Type(value) => Display::fmt(value, f),
541 Value::List(items) => {
542 f.write_str("[")?;
543 for (i, item) in items.iter().enumerate() {
544 if i > 0 {
545 f.write_str(", ")?;
546 }
547 Display::fmt(item, f)?;
548 }
549 f.write_str("]")
550 }
551 Value::Record(fields) => {
552 f.write_str("{")?;
553 for (i, (key, value)) in fields.iter().enumerate() {
554 if i > 0 {
555 f.write_str(", ")?;
556 }
557 write!(f, "{}: {}", key, value)?;
558 }
559 f.write_str("}")
560 }
561 Value::Tuple(items) => {
562 f.write_str("(")?;
563 for (i, item) in items.iter().enumerate() {
564 if i > 0 {
565 f.write_str(", ")?;
566 }
567 Display::fmt(item, f)?;
568 }
569 f.write_str(")")
570 }
571 Value::None {
572 ..
573 } => f.write_str("none"),
574 }
575 }
576}
577
578impl Value {
579 pub fn get_type(&self) -> ValueType {
580 match self {
581 Value::None {
582 inner,
583 } => ValueType::Option(Box::new(inner.clone())),
584 Value::Boolean(_) => ValueType::Boolean,
585 Value::Float4(_) => ValueType::Float4,
586 Value::Float8(_) => ValueType::Float8,
587 Value::Int1(_) => ValueType::Int1,
588 Value::Int2(_) => ValueType::Int2,
589 Value::Int4(_) => ValueType::Int4,
590 Value::Int8(_) => ValueType::Int8,
591 Value::Int16(_) => ValueType::Int16,
592 Value::Utf8(_) => ValueType::Utf8,
593 Value::Uint1(_) => ValueType::Uint1,
594 Value::Uint2(_) => ValueType::Uint2,
595 Value::Uint4(_) => ValueType::Uint4,
596 Value::Uint8(_) => ValueType::Uint8,
597 Value::Uint16(_) => ValueType::Uint16,
598 Value::Date(_) => ValueType::Date,
599 Value::DateTime(_) => ValueType::DateTime,
600 Value::Time(_) => ValueType::Time,
601 Value::Duration(_) => ValueType::Duration,
602 Value::IdentityId(_) => ValueType::IdentityId,
603 Value::Uuid4(_) => ValueType::Uuid4,
604 Value::Uuid7(_) => ValueType::Uuid7,
605 Value::Blob(_) => ValueType::Blob,
606 Value::Int(_) => ValueType::Int,
607 Value::Uint(_) => ValueType::Uint,
608 Value::Decimal(_) => ValueType::Decimal,
609 Value::Any(_) => ValueType::Any,
610 Value::DictionaryId(_) => ValueType::DictionaryId,
611 Value::Type(t) => t.clone(),
612 Value::List(items) => {
613 let element_type = items.first().map(|v| v.get_type()).unwrap_or(ValueType::Any);
614 ValueType::list_of(element_type)
615 }
616 Value::Record(fields) => {
617 ValueType::Record(fields.iter().map(|(k, v)| (k.clone(), v.get_type())).collect())
618 }
619 Value::Tuple(items) => ValueType::Tuple(items.iter().map(|v| v.get_type()).collect()),
620 }
621 }
622
623 pub fn unwrap_any(&self) -> &Value {
624 match self {
625 Value::Any(inner) => inner.unwrap_any(),
626 other => other,
627 }
628 }
629}
630
631#[cfg(test)]
632mod tests {
633 use std::str::FromStr;
634
635 use ::uuid::Uuid as StdUuid;
636 use bigdecimal::BigDecimal;
637 use num_bigint::BigInt;
638 use postcard::{from_bytes, to_allocvec};
639
640 use super::*;
641 use crate::value::{
642 blob::Blob,
643 date::Date,
644 datetime::DateTime,
645 decimal::Decimal,
646 dictionary::DictionaryEntryId,
647 duration::Duration,
648 identity::IdentityId,
649 int::Int,
650 ordered_f32::OrderedF32,
651 ordered_f64::OrderedF64,
652 time::Time,
653 uint::Uint,
654 uuid::{Uuid4, Uuid7},
655 };
656
657 #[test]
658 fn to_usize_uint1() {
659 assert_eq!(Value::uint1(42u8).to_usize(), Some(42));
660 }
661
662 #[test]
663 fn to_usize_uint2() {
664 assert_eq!(Value::uint2(1000u16).to_usize(), Some(1000));
665 }
666
667 #[test]
668 fn to_usize_uint4() {
669 assert_eq!(Value::uint4(100_000u32).to_usize(), Some(100_000));
670 }
671
672 #[test]
673 fn to_usize_uint8() {
674 assert_eq!(Value::uint8(1_000_000u64).to_usize(), Some(1_000_000));
675 }
676
677 #[test]
678 fn to_usize_uint16() {
679 assert_eq!(Value::Uint16(500u128).to_usize(), Some(500));
680 }
681
682 #[test]
683 fn to_usize_int1() {
684 assert_eq!(Value::int1(100i8).to_usize(), Some(100));
685 }
686
687 #[test]
688 fn to_usize_int2() {
689 assert_eq!(Value::int2(5000i16).to_usize(), Some(5000));
690 }
691
692 #[test]
693 fn to_usize_int4() {
694 assert_eq!(Value::int4(50_000i32).to_usize(), Some(50_000));
695 }
696
697 #[test]
698 fn to_usize_int8() {
699 assert_eq!(Value::int8(1_000_000i64).to_usize(), Some(1_000_000));
700 }
701
702 #[test]
703 fn to_usize_int16() {
704 assert_eq!(Value::Int16(999i128).to_usize(), Some(999));
705 }
706
707 #[test]
708 fn to_usize_float4() {
709 assert_eq!(Value::float4(42.0f32).to_usize(), Some(42));
710 }
711
712 #[test]
713 fn to_usize_float8() {
714 assert_eq!(Value::float8(42.0f64).to_usize(), Some(42));
715 }
716
717 #[test]
718 fn to_usize_int_bigint() {
719 assert_eq!(Value::Int(Int::from_i64(42)).to_usize(), Some(42));
720 }
721
722 #[test]
723 fn to_usize_uint_bigint() {
724 assert_eq!(Value::Uint(Uint::from_u64(42)).to_usize(), Some(42));
725 }
726
727 #[test]
728 fn to_usize_decimal() {
729 assert_eq!(Value::Decimal(Decimal::from_i64(42)).to_usize(), Some(42));
730 }
731
732 #[test]
733 fn to_usize_int1_negative() {
734 assert_eq!(Value::int1(-1i8).to_usize(), None);
735 }
736
737 #[test]
738 fn to_usize_int2_negative() {
739 assert_eq!(Value::int2(-100i16).to_usize(), None);
740 }
741
742 #[test]
743 fn to_usize_int4_negative() {
744 assert_eq!(Value::int4(-1i32).to_usize(), None);
745 }
746
747 #[test]
748 fn to_usize_int8_negative() {
749 assert_eq!(Value::int8(-1i64).to_usize(), None);
750 }
751
752 #[test]
753 fn to_usize_int16_negative() {
754 assert_eq!(Value::Int16(-1i128).to_usize(), None);
755 }
756
757 #[test]
758 fn to_usize_float4_negative() {
759 assert_eq!(Value::float4(-1.0f32).to_usize(), None);
760 }
761
762 #[test]
763 fn to_usize_float8_negative() {
764 assert_eq!(Value::float8(-1.0f64).to_usize(), None);
765 }
766
767 #[test]
768 fn to_usize_int_bigint_negative() {
769 assert_eq!(Value::Int(Int::from_i64(-5)).to_usize(), None);
770 }
771
772 #[test]
773 fn to_usize_zero() {
774 assert_eq!(Value::uint1(0u8).to_usize(), Some(0));
775 }
776
777 #[test]
778 fn to_usize_int1_zero() {
779 assert_eq!(Value::int1(0i8).to_usize(), Some(0));
780 }
781
782 #[test]
783 fn to_usize_float4_zero() {
784 assert_eq!(Value::float4(0.0f32).to_usize(), Some(0));
785 }
786
787 #[test]
788 fn to_usize_boolean_none() {
789 assert_eq!(Value::bool(true).to_usize(), None);
790 }
791
792 #[test]
793 fn to_usize_utf8_integer() {
794 assert_eq!(Value::utf8("42").to_usize(), Some(42));
795 }
796
797 #[test]
798 fn to_usize_utf8_float() {
799 assert_eq!(Value::utf8("3.7").to_usize(), Some(3));
800 }
801
802 #[test]
803 fn to_usize_utf8_negative() {
804 assert_eq!(Value::utf8("-5").to_usize(), None);
805 }
806
807 #[test]
808 fn to_usize_utf8_negative_float() {
809 assert_eq!(Value::utf8("-1.5").to_usize(), None);
810 }
811
812 #[test]
813 fn to_usize_utf8_whitespace() {
814 assert_eq!(Value::utf8(" 42 ").to_usize(), Some(42));
815 }
816
817 #[test]
818 fn to_usize_utf8_zero() {
819 assert_eq!(Value::utf8("0").to_usize(), Some(0));
820 }
821
822 #[test]
823 fn to_usize_utf8_non_numeric() {
824 assert_eq!(Value::utf8("hello").to_usize(), None);
825 }
826
827 #[test]
828 fn to_usize_utf8_empty() {
829 assert_eq!(Value::utf8("").to_usize(), None);
830 }
831
832 #[test]
833 fn to_usize_none_none() {
834 assert_eq!(Value::none().to_usize(), None);
835 }
836
837 #[test]
838 fn to_usize_float8_fractional() {
839 assert_eq!(Value::float8(3.7f64).to_usize(), Some(3));
840 }
841
842 #[test]
843 fn to_usize_decimal_fractional() {
844 assert_eq!(Value::Decimal(Decimal::from_str("3.7").unwrap()).to_usize(), Some(3));
845 }
846
847 #[test]
848 fn test_none_with_same_inner_type_are_equal() {
849 assert_eq!(Value::none_of(ValueType::Duration), Value::none_of(ValueType::Duration));
852 }
853
854 #[test]
855 fn test_none_with_different_inner_type_are_not_equal() {
856 assert_ne!(Value::none_of(ValueType::Duration), Value::none_of(ValueType::Boolean));
857 }
858
859 #[test]
860 fn test_none_with_different_nesting_depth_are_not_equal() {
861 let option_duration = Value::none_of(ValueType::Option(Box::new(ValueType::Duration)));
862 let duration = Value::none_of(ValueType::Duration);
863 assert_ne!(option_duration, duration);
864 }
865
866 #[test]
867 fn test_none_any_is_not_equal_to_none_of_concrete_type() {
868 assert_ne!(Value::none(), Value::none_of(ValueType::Duration));
869 }
870
871 #[test]
872 fn test_value_every_arm_round_trips() {
873 let values = vec![
875 Value::None {
876 inner: ValueType::Utf8,
877 },
878 Value::Boolean(true),
879 Value::Float4(OrderedF32::try_from(1.5f32).unwrap()),
880 Value::Float8(OrderedF64::try_from(-2.25f64).unwrap()),
881 Value::Int1(-8),
882 Value::Int2(-1_600),
883 Value::Int4(-320_000),
884 Value::Int8(-64_000_000_000),
885 Value::Int16(i128::MIN),
886 Value::Utf8("state".to_string()),
887 Value::Uint1(8),
888 Value::Uint2(1_600),
889 Value::Uint4(320_000),
890 Value::Uint8(64_000_000_000),
891 Value::Uint16(u128::MAX),
892 Value::Date(Date::new(2026, 7, 20).unwrap()),
893 Value::DateTime(DateTime::new(2026, 7, 20, 12, 34, 56, 789).unwrap()),
894 Value::Time(Time::new(23, 59, 59, 1).unwrap()),
895 Value::Duration(Duration::new(1, 2, 3).unwrap()),
896 Value::IdentityId(IdentityId(Uuid7(StdUuid::from_bytes([
897 0x01, 0x8F, 0x2A, 0x3B, 0x4C, 0x5D, 0x70, 0x07, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00,
898 0x00, 0x07,
899 ])))),
900 Value::Uuid4(Uuid4(StdUuid::from_u128(4))),
901 Value::Uuid7(Uuid7(StdUuid::from_u128(77))),
902 Value::Blob(Blob::new(vec![1, 2, 3])),
903 Value::Int(Int::from_i128(i128::MIN)),
904 Value::Uint(Uint::from_u128(u128::MAX)),
905 Value::Decimal(Decimal(BigDecimal::new(BigInt::from(-12345), 3))),
906 Value::Any(Box::new(Value::Boolean(false))),
907 Value::DictionaryId(DictionaryEntryId::U16(u128::MAX)),
908 Value::Type(ValueType::Record(vec![("k".to_string(), ValueType::Int4)])),
909 Value::List(vec![Value::Int4(1), Value::Utf8("x".to_string())]),
910 Value::Record(vec![("k".to_string(), Value::Int8(9))]),
911 Value::Tuple(vec![
912 Value::Boolean(true),
913 Value::None {
914 inner: ValueType::Any,
915 },
916 ]),
917 ];
918
919 let bytes = to_allocvec(&values).unwrap();
920 let restored: Vec<Value> = from_bytes(&bytes).unwrap();
921 assert_eq!(restored, values);
922 }
923}