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