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