1use super::{Entry, EntryPath, Type, TypeUnion, ValueRecord, sparse_record::SparseRecord};
2use std::cmp::Ordering;
3use std::hash::Hash;
4
5#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
35pub enum Value {
36 Bool(bool),
38
39 I8(i8),
41
42 I16(i16),
44
45 I32(i32),
47
48 I64(i64),
50
51 U8(u8),
53
54 U16(u16),
56
57 U32(u32),
59
60 U64(u64),
62
63 SparseRecord(SparseRecord),
65
66 #[default]
68 Null,
69
70 Record(ValueRecord),
72
73 List(Vec<Value>),
75
76 String(String),
78
79 Bytes(Vec<u8>),
81
82 Uuid(uuid::Uuid),
84
85 #[cfg(feature = "rust_decimal")]
88 Decimal(rust_decimal::Decimal),
89
90 #[cfg(feature = "bigdecimal")]
93 BigDecimal(bigdecimal::BigDecimal),
94
95 #[cfg(feature = "jiff")]
98 Timestamp(jiff::Timestamp),
99
100 #[cfg(feature = "jiff")]
103 Zoned(jiff::Zoned),
104
105 #[cfg(feature = "jiff")]
108 Date(jiff::civil::Date),
109
110 #[cfg(feature = "jiff")]
113 Time(jiff::civil::Time),
114
115 #[cfg(feature = "jiff")]
118 DateTime(jiff::civil::DateTime),
119}
120
121impl Value {
122 pub const fn null() -> Self {
132 Self::Null
133 }
134
135 pub const fn is_null(&self) -> bool {
145 matches!(self, Self::Null)
146 }
147
148 pub const fn is_record(&self) -> bool {
150 matches!(self, Self::Record(_))
151 }
152
153 pub fn record_from_vec(fields: Vec<Self>) -> Self {
163 ValueRecord::from_vec(fields).into()
164 }
165
166 pub const fn from_bool(src: bool) -> Self {
176 Self::Bool(src)
177 }
178
179 pub fn as_str(&self) -> Option<&str> {
182 match self {
183 Self::String(v) => Some(&**v),
184 _ => None,
185 }
186 }
187
188 pub fn as_string_unwrap(&self) -> &str {
195 match self {
196 Self::String(v) => v,
197 _ => todo!(),
198 }
199 }
200
201 pub fn as_record(&self) -> Option<&ValueRecord> {
204 match self {
205 Self::Record(record) => Some(record),
206 _ => None,
207 }
208 }
209
210 pub fn as_record_unwrap(&self) -> &ValueRecord {
217 match self {
218 Self::Record(record) => record,
219 _ => panic!("{self:#?}"),
220 }
221 }
222
223 pub fn as_record_mut_unwrap(&mut self) -> &mut ValueRecord {
230 match self {
231 Self::Record(record) => record,
232 _ => panic!(),
233 }
234 }
235
236 pub fn into_record(self) -> ValueRecord {
243 match self {
244 Self::Record(record) => record,
245 _ => panic!(),
246 }
247 }
248
249 pub fn is_a(&self, ty: &Type) -> bool {
254 if let Type::Union(types) = ty {
255 return types.iter().any(|t| self.is_a(t));
256 }
257 match self {
258 Self::Null => true,
259 Self::Bool(_) => ty.is_bool(),
260 Self::I8(_) => ty.is_i8(),
261 Self::I16(_) => ty.is_i16(),
262 Self::I32(_) => ty.is_i32(),
263 Self::I64(_) => ty.is_i64(),
264 Self::U8(_) => ty.is_u8(),
265 Self::U16(_) => ty.is_u16(),
266 Self::U32(_) => ty.is_u32(),
267 Self::U64(_) => ty.is_u64(),
268 Self::List(value) => match ty {
269 Type::List(ty) => {
270 if value.is_empty() {
271 true
272 } else {
273 value[0].is_a(ty)
274 }
275 }
276 _ => false,
277 },
278 Self::Record(value) => match ty {
279 Type::Record(fields) if value.len() == fields.len() => value
280 .fields
281 .iter()
282 .zip(fields.iter())
283 .all(|(value, ty)| value.is_a(ty)),
284 _ => false,
285 },
286 Self::SparseRecord(value) => match ty {
287 Type::SparseRecord(fields) => value.fields == *fields,
288 _ => false,
289 },
290 Self::String(_) => ty.is_string(),
291 Self::Bytes(_) => ty.is_bytes(),
292 Self::Uuid(_) => ty.is_uuid(),
293 #[cfg(feature = "rust_decimal")]
294 Value::Decimal(_) => *ty == Type::Decimal,
295 #[cfg(feature = "bigdecimal")]
296 Value::BigDecimal(_) => *ty == Type::BigDecimal,
297 #[cfg(feature = "jiff")]
298 Value::Timestamp(_) => *ty == Type::Timestamp,
299 #[cfg(feature = "jiff")]
300 Value::Zoned(_) => *ty == Type::Zoned,
301 #[cfg(feature = "jiff")]
302 Value::Date(_) => *ty == Type::Date,
303 #[cfg(feature = "jiff")]
304 Value::Time(_) => *ty == Type::Time,
305 #[cfg(feature = "jiff")]
306 Value::DateTime(_) => *ty == Type::DateTime,
307 }
308 }
309
310 pub fn infer_ty(&self) -> Type {
321 match self {
322 Value::Bool(_) => Type::Bool,
323 Value::I8(_) => Type::I8,
324 Value::I16(_) => Type::I16,
325 Value::I32(_) => Type::I32,
326 Value::I64(_) => Type::I64,
327 Value::SparseRecord(v) => Type::SparseRecord(v.fields.clone()),
328 Value::Null => Type::Null,
329 Value::Record(v) => Type::Record(v.fields.iter().map(Self::infer_ty).collect()),
330 Value::String(_) => Type::String,
331 Value::List(items) if items.is_empty() => Type::list(Type::Null),
332 Value::List(items) => {
333 let mut union = TypeUnion::new();
334 for item in items {
335 union.insert(item.infer_ty());
336 }
337 Type::list(union.simplify())
338 }
339 Value::U8(_) => Type::U8,
340 Value::U16(_) => Type::U16,
341 Value::U32(_) => Type::U32,
342 Value::U64(_) => Type::U64,
343 Value::Bytes(_) => Type::Bytes,
344 Value::Uuid(_) => Type::Uuid,
345 #[cfg(feature = "rust_decimal")]
346 Value::Decimal(_) => Type::Decimal,
347 #[cfg(feature = "bigdecimal")]
348 Value::BigDecimal(_) => Type::BigDecimal,
349 #[cfg(feature = "jiff")]
350 Value::Timestamp(_) => Type::Timestamp,
351 #[cfg(feature = "jiff")]
352 Value::Zoned(_) => Type::Zoned,
353 #[cfg(feature = "jiff")]
354 Value::Date(_) => Type::Date,
355 #[cfg(feature = "jiff")]
356 Value::Time(_) => Type::Time,
357 #[cfg(feature = "jiff")]
358 Value::DateTime(_) => Type::DateTime,
359 }
360 }
361
362 #[track_caller]
372 pub fn entry(&self, path: impl EntryPath) -> Entry<'_> {
373 let mut ret = Entry::Value(self);
374
375 for step in path.step_iter() {
376 ret = match ret {
377 Entry::Value(Self::Record(record)) => Entry::Value(&record[step]),
378 Entry::Value(Self::List(items)) => Entry::Value(&items[step]),
379 _ => todo!("ret={ret:#?}; base={self:#?}; step={step:#?}"),
380 }
381 }
382
383 ret
384 }
385
386 pub fn take(&mut self) -> Self {
398 std::mem::take(self)
399 }
400}
401
402impl AsRef<Self> for Value {
403 fn as_ref(&self) -> &Self {
404 self
405 }
406}
407
408impl PartialOrd for Value {
409 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
417 match (self, other) {
418 (Value::Null, _) | (_, Value::Null) => None,
420
421 (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
423
424 (Value::I8(a), Value::I8(b)) => a.partial_cmp(b),
426 (Value::I16(a), Value::I16(b)) => a.partial_cmp(b),
427 (Value::I32(a), Value::I32(b)) => a.partial_cmp(b),
428 (Value::I64(a), Value::I64(b)) => a.partial_cmp(b),
429
430 (Value::U8(a), Value::U8(b)) => a.partial_cmp(b),
432 (Value::U16(a), Value::U16(b)) => a.partial_cmp(b),
433 (Value::U32(a), Value::U32(b)) => a.partial_cmp(b),
434 (Value::U64(a), Value::U64(b)) => a.partial_cmp(b),
435
436 (Value::String(a), Value::String(b)) => a.partial_cmp(b),
438
439 (Value::Bytes(a), Value::Bytes(b)) => a.partial_cmp(b),
441
442 (Value::Uuid(a), Value::Uuid(b)) => a.partial_cmp(b),
444
445 #[cfg(feature = "rust_decimal")]
447 (Value::Decimal(a), Value::Decimal(b)) => a.partial_cmp(b),
448
449 #[cfg(feature = "bigdecimal")]
451 (Value::BigDecimal(a), Value::BigDecimal(b)) => a.partial_cmp(b),
452
453 #[cfg(feature = "jiff")]
455 (Value::Timestamp(a), Value::Timestamp(b)) => a.partial_cmp(b),
456 #[cfg(feature = "jiff")]
457 (Value::Zoned(a), Value::Zoned(b)) => a.partial_cmp(b),
458 #[cfg(feature = "jiff")]
459 (Value::Date(a), Value::Date(b)) => a.partial_cmp(b),
460 #[cfg(feature = "jiff")]
461 (Value::Time(a), Value::Time(b)) => a.partial_cmp(b),
462 #[cfg(feature = "jiff")]
463 (Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
464
465 _ => None,
467 }
468 }
469}
470
471impl From<bool> for Value {
472 fn from(src: bool) -> Self {
473 Self::Bool(src)
474 }
475}
476
477impl TryFrom<Value> for bool {
478 type Error = crate::Error;
479
480 fn try_from(value: Value) -> Result<Self, Self::Error> {
481 match value {
482 Value::Bool(v) => Ok(v),
483 _ => Err(crate::Error::type_conversion(value, "bool")),
484 }
485 }
486}
487
488impl From<String> for Value {
489 fn from(src: String) -> Self {
490 Self::String(src)
491 }
492}
493
494impl From<&String> for Value {
495 fn from(src: &String) -> Self {
496 Self::String(src.clone())
497 }
498}
499
500impl From<&str> for Value {
501 fn from(src: &str) -> Self {
502 Self::String(src.to_string())
503 }
504}
505
506impl From<ValueRecord> for Value {
507 fn from(value: ValueRecord) -> Self {
508 Self::Record(value)
509 }
510}
511
512impl<T> From<Option<T>> for Value
513where
514 Self: From<T>,
515{
516 fn from(value: Option<T>) -> Self {
517 match value {
518 Some(value) => Self::from(value),
519 None => Self::Null,
520 }
521 }
522}
523
524impl TryFrom<Value> for String {
525 type Error = crate::Error;
526
527 fn try_from(value: Value) -> Result<Self, Self::Error> {
528 match value {
529 Value::String(v) => Ok(v),
530 _ => Err(crate::Error::type_conversion(value, "String")),
531 }
532 }
533}
534
535impl From<Vec<u8>> for Value {
536 fn from(value: Vec<u8>) -> Self {
537 Self::Bytes(value)
538 }
539}
540
541impl TryFrom<Value> for Vec<u8> {
542 type Error = crate::Error;
543
544 fn try_from(value: Value) -> Result<Self, Self::Error> {
545 match value {
546 Value::Bytes(v) => Ok(v),
547 _ => Err(crate::Error::type_conversion(value, "Bytes")),
548 }
549 }
550}
551
552impl From<uuid::Uuid> for Value {
553 fn from(value: uuid::Uuid) -> Self {
554 Self::Uuid(value)
555 }
556}
557
558impl TryFrom<Value> for uuid::Uuid {
559 type Error = crate::Error;
560
561 fn try_from(value: Value) -> Result<Self, Self::Error> {
562 match value {
563 Value::Uuid(v) => Ok(v),
564 _ => Err(crate::Error::type_conversion(value, "uuid::Uuid")),
565 }
566 }
567}
568
569#[cfg(feature = "rust_decimal")]
570impl From<rust_decimal::Decimal> for Value {
571 fn from(value: rust_decimal::Decimal) -> Self {
572 Self::Decimal(value)
573 }
574}
575
576#[cfg(feature = "rust_decimal")]
577impl TryFrom<Value> for rust_decimal::Decimal {
578 type Error = crate::Error;
579
580 fn try_from(value: Value) -> Result<Self, Self::Error> {
581 match value {
582 Value::Decimal(v) => Ok(v),
583 _ => Err(crate::Error::type_conversion(
584 value,
585 "rust_decimal::Decimal",
586 )),
587 }
588 }
589}
590
591#[cfg(feature = "bigdecimal")]
592impl From<bigdecimal::BigDecimal> for Value {
593 fn from(value: bigdecimal::BigDecimal) -> Self {
594 Self::BigDecimal(value)
595 }
596}
597
598#[cfg(feature = "bigdecimal")]
599impl TryFrom<Value> for bigdecimal::BigDecimal {
600 type Error = crate::Error;
601
602 fn try_from(value: Value) -> Result<Self, Self::Error> {
603 match value {
604 Value::BigDecimal(v) => Ok(v),
605 _ => Err(crate::Error::type_conversion(
606 value,
607 "bigdecimal::BigDecimal",
608 )),
609 }
610 }
611}