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