1use super::{Entry, EntryPath, Type, TypeUnion, ValueRecord, sparse_record::SparseRecord};
2use std::cmp::Ordering;
3
4#[derive(Debug, Default, Clone, PartialEq)]
34pub enum Value {
35 Bool(bool),
37
38 I8(i8),
40
41 I16(i16),
43
44 I32(i32),
46
47 I64(i64),
49
50 U8(u8),
52
53 U16(u16),
55
56 U32(u32),
58
59 U64(u64),
61
62 F32(f32),
64
65 F64(f64),
67
68 SparseRecord(SparseRecord),
70
71 #[default]
73 Null,
74
75 Record(ValueRecord),
77
78 List(Vec<Value>),
80
81 String(String),
83
84 Bytes(Vec<u8>),
86
87 Uuid(uuid::Uuid),
89
90 #[cfg(feature = "rust_decimal")]
93 Decimal(rust_decimal::Decimal),
94
95 #[cfg(feature = "bigdecimal")]
98 BigDecimal(bigdecimal::BigDecimal),
99
100 #[cfg(feature = "jiff")]
103 Timestamp(jiff::Timestamp),
104
105 #[cfg(feature = "jiff")]
108 Zoned(jiff::Zoned),
109
110 #[cfg(feature = "jiff")]
113 Date(jiff::civil::Date),
114
115 #[cfg(feature = "jiff")]
118 Time(jiff::civil::Time),
119
120 #[cfg(feature = "jiff")]
123 DateTime(jiff::civil::DateTime),
124}
125
126impl Value {
127 pub const fn null() -> Self {
137 Self::Null
138 }
139
140 pub const fn is_null(&self) -> bool {
150 matches!(self, Self::Null)
151 }
152
153 pub const fn is_record(&self) -> bool {
155 matches!(self, Self::Record(_))
156 }
157
158 pub fn record_from_vec(fields: Vec<Self>) -> Self {
168 ValueRecord::from_vec(fields).into()
169 }
170
171 pub const fn from_bool(src: bool) -> Self {
181 Self::Bool(src)
182 }
183
184 pub fn as_str(&self) -> Option<&str> {
187 match self {
188 Self::String(v) => Some(&**v),
189 _ => None,
190 }
191 }
192
193 pub fn as_string_unwrap(&self) -> &str {
200 match self {
201 Self::String(v) => v,
202 _ => todo!(),
203 }
204 }
205
206 pub fn as_record(&self) -> Option<&ValueRecord> {
209 match self {
210 Self::Record(record) => Some(record),
211 _ => None,
212 }
213 }
214
215 pub fn as_record_unwrap(&self) -> &ValueRecord {
222 match self {
223 Self::Record(record) => record,
224 _ => panic!("{self:#?}"),
225 }
226 }
227
228 pub fn as_record_mut_unwrap(&mut self) -> &mut ValueRecord {
235 match self {
236 Self::Record(record) => record,
237 _ => panic!(),
238 }
239 }
240
241 pub fn into_record(self) -> ValueRecord {
248 match self {
249 Self::Record(record) => record,
250 _ => panic!(),
251 }
252 }
253
254 pub fn is_a(&self, ty: &Type) -> bool {
259 if let Type::Union(types) = ty {
260 return types.iter().any(|t| self.is_a(t));
261 }
262 match self {
263 Self::Null => true,
264 Self::Bool(_) => ty.is_bool(),
265 Self::I8(_) => ty.is_i8(),
266 Self::I16(_) => ty.is_i16(),
267 Self::I32(_) => ty.is_i32(),
268 Self::I64(_) => ty.is_i64(),
269 Self::U8(_) => ty.is_u8(),
270 Self::U16(_) => ty.is_u16(),
271 Self::U32(_) => ty.is_u32(),
272 Self::U64(_) => ty.is_u64(),
273 Self::F32(_) => ty.is_f32(),
274 Self::F64(_) => ty.is_f64(),
275 Self::List(value) => match ty {
276 Type::List(ty) => {
277 if value.is_empty() {
278 true
279 } else {
280 value[0].is_a(ty)
281 }
282 }
283 _ => false,
284 },
285 Self::Record(value) => match ty {
286 Type::Record(fields) if value.len() == fields.len() => value
287 .fields
288 .iter()
289 .zip(fields.iter())
290 .all(|(value, ty)| value.is_a(ty)),
291 _ => false,
292 },
293 Self::SparseRecord(value) => match ty {
294 Type::SparseRecord(fields) => value.fields == *fields,
295 _ => false,
296 },
297 Self::String(_) => ty.is_string(),
298 Self::Bytes(_) => ty.is_bytes(),
299 Self::Uuid(_) => ty.is_uuid(),
300 #[cfg(feature = "rust_decimal")]
301 Value::Decimal(_) => *ty == Type::Decimal,
302 #[cfg(feature = "bigdecimal")]
303 Value::BigDecimal(_) => *ty == Type::BigDecimal,
304 #[cfg(feature = "jiff")]
305 Value::Timestamp(_) => *ty == Type::Timestamp,
306 #[cfg(feature = "jiff")]
307 Value::Zoned(_) => *ty == Type::Zoned,
308 #[cfg(feature = "jiff")]
309 Value::Date(_) => *ty == Type::Date,
310 #[cfg(feature = "jiff")]
311 Value::Time(_) => *ty == Type::Time,
312 #[cfg(feature = "jiff")]
313 Value::DateTime(_) => *ty == Type::DateTime,
314 }
315 }
316
317 pub fn infer_ty(&self) -> Type {
328 match self {
329 Value::Bool(_) => Type::Bool,
330 Value::I8(_) => Type::I8,
331 Value::I16(_) => Type::I16,
332 Value::I32(_) => Type::I32,
333 Value::I64(_) => Type::I64,
334 Value::SparseRecord(v) => Type::SparseRecord(v.fields.clone()),
335 Value::Null => Type::Null,
336 Value::Record(v) => Type::Record(v.fields.iter().map(Self::infer_ty).collect()),
337 Value::String(_) => Type::String,
338 Value::List(items) if items.is_empty() => Type::list(Type::Null),
339 Value::List(items) => {
340 let mut union = TypeUnion::new();
341 for item in items {
342 union.insert(item.infer_ty());
343 }
344 Type::list(union.simplify())
345 }
346 Value::U8(_) => Type::U8,
347 Value::U16(_) => Type::U16,
348 Value::U32(_) => Type::U32,
349 Value::U64(_) => Type::U64,
350 Value::F32(_) => Type::F32,
351 Value::F64(_) => Type::F64,
352 Value::Bytes(_) => Type::Bytes,
353 Value::Uuid(_) => Type::Uuid,
354 #[cfg(feature = "rust_decimal")]
355 Value::Decimal(_) => Type::Decimal,
356 #[cfg(feature = "bigdecimal")]
357 Value::BigDecimal(_) => Type::BigDecimal,
358 #[cfg(feature = "jiff")]
359 Value::Timestamp(_) => Type::Timestamp,
360 #[cfg(feature = "jiff")]
361 Value::Zoned(_) => Type::Zoned,
362 #[cfg(feature = "jiff")]
363 Value::Date(_) => Type::Date,
364 #[cfg(feature = "jiff")]
365 Value::Time(_) => Type::Time,
366 #[cfg(feature = "jiff")]
367 Value::DateTime(_) => Type::DateTime,
368 }
369 }
370
371 #[track_caller]
381 pub fn entry(&self, path: impl EntryPath) -> Entry<'_> {
382 let mut ret = Entry::Value(self);
383
384 for step in path.step_iter() {
385 ret = match ret {
386 Entry::Value(Self::Record(record)) => Entry::Value(&record[step]),
387 Entry::Value(Self::List(items)) => Entry::Value(&items[step]),
388 _ => todo!("ret={ret:#?}; base={self:#?}; step={step:#?}"),
389 }
390 }
391
392 ret
393 }
394
395 pub fn take(&mut self) -> Self {
407 std::mem::take(self)
408 }
409}
410
411impl AsRef<Self> for Value {
412 fn as_ref(&self) -> &Self {
413 self
414 }
415}
416
417impl PartialOrd for Value {
418 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
426 match (self, other) {
427 (Value::Null, _) | (_, Value::Null) => None,
429
430 (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
432
433 (Value::I8(a), Value::I8(b)) => a.partial_cmp(b),
435 (Value::I16(a), Value::I16(b)) => a.partial_cmp(b),
436 (Value::I32(a), Value::I32(b)) => a.partial_cmp(b),
437 (Value::I64(a), Value::I64(b)) => a.partial_cmp(b),
438
439 (Value::U8(a), Value::U8(b)) => a.partial_cmp(b),
441 (Value::U16(a), Value::U16(b)) => a.partial_cmp(b),
442 (Value::U32(a), Value::U32(b)) => a.partial_cmp(b),
443 (Value::U64(a), Value::U64(b)) => a.partial_cmp(b),
444
445 (Value::F32(a), Value::F32(b)) => a.partial_cmp(b),
447 (Value::F64(a), Value::F64(b)) => a.partial_cmp(b),
448
449 (Value::String(a), Value::String(b)) => a.partial_cmp(b),
451
452 (Value::Bytes(a), Value::Bytes(b)) => a.partial_cmp(b),
454
455 (Value::Uuid(a), Value::Uuid(b)) => a.partial_cmp(b),
457
458 #[cfg(feature = "rust_decimal")]
460 (Value::Decimal(a), Value::Decimal(b)) => a.partial_cmp(b),
461
462 #[cfg(feature = "bigdecimal")]
464 (Value::BigDecimal(a), Value::BigDecimal(b)) => a.partial_cmp(b),
465
466 #[cfg(feature = "jiff")]
468 (Value::Timestamp(a), Value::Timestamp(b)) => a.partial_cmp(b),
469 #[cfg(feature = "jiff")]
470 (Value::Zoned(a), Value::Zoned(b)) => a.partial_cmp(b),
471 #[cfg(feature = "jiff")]
472 (Value::Date(a), Value::Date(b)) => a.partial_cmp(b),
473 #[cfg(feature = "jiff")]
474 (Value::Time(a), Value::Time(b)) => a.partial_cmp(b),
475 #[cfg(feature = "jiff")]
476 (Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
477
478 _ => None,
480 }
481 }
482}
483
484impl From<bool> for Value {
485 fn from(src: bool) -> Self {
486 Self::Bool(src)
487 }
488}
489
490impl TryFrom<Value> for bool {
491 type Error = crate::Error;
492
493 fn try_from(value: Value) -> Result<Self, Self::Error> {
494 match value {
495 Value::Bool(v) => Ok(v),
496 _ => Err(crate::Error::type_conversion(value, "bool")),
497 }
498 }
499}
500
501impl From<String> for Value {
502 fn from(src: String) -> Self {
503 Self::String(src)
504 }
505}
506
507impl From<&String> for Value {
508 fn from(src: &String) -> Self {
509 Self::String(src.clone())
510 }
511}
512
513impl From<&str> for Value {
514 fn from(src: &str) -> Self {
515 Self::String(src.to_string())
516 }
517}
518
519impl From<ValueRecord> for Value {
520 fn from(value: ValueRecord) -> Self {
521 Self::Record(value)
522 }
523}
524
525impl<T> From<Option<T>> for Value
526where
527 Self: From<T>,
528{
529 fn from(value: Option<T>) -> Self {
530 match value {
531 Some(value) => Self::from(value),
532 None => Self::Null,
533 }
534 }
535}
536
537impl TryFrom<Value> for String {
538 type Error = crate::Error;
539
540 fn try_from(value: Value) -> Result<Self, Self::Error> {
541 match value {
542 Value::String(v) => Ok(v),
543 _ => Err(crate::Error::type_conversion(value, "String")),
544 }
545 }
546}
547
548impl From<Vec<u8>> for Value {
549 fn from(value: Vec<u8>) -> Self {
550 Self::Bytes(value)
551 }
552}
553
554impl TryFrom<Value> for Vec<u8> {
555 type Error = crate::Error;
556
557 fn try_from(value: Value) -> Result<Self, Self::Error> {
558 match value {
559 Value::Bytes(v) => Ok(v),
560 _ => Err(crate::Error::type_conversion(value, "Bytes")),
561 }
562 }
563}
564
565impl From<uuid::Uuid> for Value {
566 fn from(value: uuid::Uuid) -> Self {
567 Self::Uuid(value)
568 }
569}
570
571impl TryFrom<Value> for uuid::Uuid {
572 type Error = crate::Error;
573
574 fn try_from(value: Value) -> Result<Self, Self::Error> {
575 match value {
576 Value::Uuid(v) => Ok(v),
577 _ => Err(crate::Error::type_conversion(value, "uuid::Uuid")),
578 }
579 }
580}
581
582#[cfg(feature = "rust_decimal")]
583impl From<rust_decimal::Decimal> for Value {
584 fn from(value: rust_decimal::Decimal) -> Self {
585 Self::Decimal(value)
586 }
587}
588
589#[cfg(feature = "rust_decimal")]
590impl TryFrom<Value> for rust_decimal::Decimal {
591 type Error = crate::Error;
592
593 fn try_from(value: Value) -> Result<Self, Self::Error> {
594 match value {
595 Value::Decimal(v) => Ok(v),
596 _ => Err(crate::Error::type_conversion(
597 value,
598 "rust_decimal::Decimal",
599 )),
600 }
601 }
602}
603
604#[cfg(feature = "bigdecimal")]
605impl From<bigdecimal::BigDecimal> for Value {
606 fn from(value: bigdecimal::BigDecimal) -> Self {
607 Self::BigDecimal(value)
608 }
609}
610
611#[cfg(feature = "bigdecimal")]
612impl TryFrom<Value> for bigdecimal::BigDecimal {
613 type Error = crate::Error;
614
615 fn try_from(value: Value) -> Result<Self, Self::Error> {
616 match value {
617 Value::BigDecimal(v) => Ok(v),
618 _ => Err(crate::Error::type_conversion(
619 value,
620 "bigdecimal::BigDecimal",
621 )),
622 }
623 }
624}