1use super::{sparse_record::SparseRecord, Entry, EntryPath, Type, TypeUnion, ValueRecord};
2use std::cmp::Ordering;
3use std::hash::Hash;
4
5#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
6pub enum Value {
7 Bool(bool),
9
10 I8(i8),
12
13 I16(i16),
15
16 I32(i32),
18
19 I64(i64),
21
22 U8(u8),
24
25 U16(u16),
27
28 U32(u32),
30
31 U64(u64),
33
34 SparseRecord(SparseRecord),
36
37 #[default]
39 Null,
40
41 Record(ValueRecord),
43
44 List(Vec<Value>),
46
47 String(String),
49
50 Bytes(Vec<u8>),
52
53 Uuid(uuid::Uuid),
55
56 #[cfg(feature = "rust_decimal")]
59 Decimal(rust_decimal::Decimal),
60
61 #[cfg(feature = "bigdecimal")]
64 BigDecimal(bigdecimal::BigDecimal),
65
66 #[cfg(feature = "jiff")]
69 Timestamp(jiff::Timestamp),
70
71 #[cfg(feature = "jiff")]
74 Zoned(jiff::Zoned),
75
76 #[cfg(feature = "jiff")]
79 Date(jiff::civil::Date),
80
81 #[cfg(feature = "jiff")]
84 Time(jiff::civil::Time),
85
86 #[cfg(feature = "jiff")]
89 DateTime(jiff::civil::DateTime),
90}
91
92impl Value {
93 pub const fn null() -> Self {
95 Self::Null
96 }
97
98 pub const fn is_null(&self) -> bool {
99 matches!(self, Self::Null)
100 }
101
102 pub const fn is_record(&self) -> bool {
103 matches!(self, Self::Record(_))
104 }
105
106 pub fn record_from_vec(fields: Vec<Self>) -> Self {
107 ValueRecord::from_vec(fields).into()
108 }
109
110 pub const fn from_bool(src: bool) -> Self {
112 Self::Bool(src)
113 }
114
115 pub fn as_str(&self) -> Option<&str> {
116 match self {
117 Self::String(v) => Some(&**v),
118 _ => None,
119 }
120 }
121
122 pub fn expect_string(&self) -> &str {
123 match self {
124 Self::String(v) => v,
125 _ => todo!(),
126 }
127 }
128
129 pub fn as_record(&self) -> Option<&ValueRecord> {
130 match self {
131 Self::Record(record) => Some(record),
132 _ => None,
133 }
134 }
135
136 pub fn expect_record(&self) -> &ValueRecord {
137 match self {
138 Self::Record(record) => record,
139 _ => panic!("{self:#?}"),
140 }
141 }
142
143 pub fn expect_record_mut(&mut self) -> &mut ValueRecord {
144 match self {
145 Self::Record(record) => record,
146 _ => panic!(),
147 }
148 }
149
150 pub fn into_record(self) -> ValueRecord {
151 match self {
152 Self::Record(record) => record,
153 _ => panic!(),
154 }
155 }
156
157 pub fn is_a(&self, ty: &Type) -> bool {
158 if let Type::Union(types) = ty {
159 return types.iter().any(|t| self.is_a(t));
160 }
161 match self {
162 Self::Null => true,
163 Self::Bool(_) => ty.is_bool(),
164 Self::I8(_) => ty.is_i8(),
165 Self::I16(_) => ty.is_i16(),
166 Self::I32(_) => ty.is_i32(),
167 Self::I64(_) => ty.is_i64(),
168 Self::U8(_) => ty.is_u8(),
169 Self::U16(_) => ty.is_u16(),
170 Self::U32(_) => ty.is_u32(),
171 Self::U64(_) => ty.is_u64(),
172 Self::List(value) => match ty {
173 Type::List(ty) => {
174 if value.is_empty() {
175 true
176 } else {
177 value[0].is_a(ty)
178 }
179 }
180 _ => false,
181 },
182 Self::Record(value) => match ty {
183 Type::Record(fields) if value.len() == fields.len() => value
184 .fields
185 .iter()
186 .zip(fields.iter())
187 .all(|(value, ty)| value.is_a(ty)),
188 _ => false,
189 },
190 Self::SparseRecord(value) => match ty {
191 Type::SparseRecord(fields) => value.fields == *fields,
192 _ => false,
193 },
194 Self::String(_) => ty.is_string(),
195 Self::Bytes(_) => ty.is_bytes(),
196 Self::Uuid(_) => ty.is_uuid(),
197 #[cfg(feature = "rust_decimal")]
198 Value::Decimal(_) => *ty == Type::Decimal,
199 #[cfg(feature = "bigdecimal")]
200 Value::BigDecimal(_) => *ty == Type::BigDecimal,
201 #[cfg(feature = "jiff")]
202 Value::Timestamp(_) => *ty == Type::Timestamp,
203 #[cfg(feature = "jiff")]
204 Value::Zoned(_) => *ty == Type::Zoned,
205 #[cfg(feature = "jiff")]
206 Value::Date(_) => *ty == Type::Date,
207 #[cfg(feature = "jiff")]
208 Value::Time(_) => *ty == Type::Time,
209 #[cfg(feature = "jiff")]
210 Value::DateTime(_) => *ty == Type::DateTime,
211 }
212 }
213
214 pub fn infer_ty(&self) -> Type {
216 match self {
217 Value::Bool(_) => Type::Bool,
218 Value::I8(_) => Type::I8,
219 Value::I16(_) => Type::I16,
220 Value::I32(_) => Type::I32,
221 Value::I64(_) => Type::I64,
222 Value::SparseRecord(v) => Type::SparseRecord(v.fields.clone()),
223 Value::Null => Type::Null,
224 Value::Record(v) => Type::Record(v.fields.iter().map(Self::infer_ty).collect()),
225 Value::String(_) => Type::String,
226 Value::List(items) if items.is_empty() => Type::list(Type::Null),
227 Value::List(items) => {
228 let mut union = TypeUnion::new();
229 for item in items {
230 union.insert(item.infer_ty());
231 }
232 Type::list(union.simplify())
233 }
234 Value::U8(_) => Type::U8,
235 Value::U16(_) => Type::U16,
236 Value::U32(_) => Type::U32,
237 Value::U64(_) => Type::U64,
238 Value::Bytes(_) => Type::Bytes,
239 Value::Uuid(_) => Type::Uuid,
240 #[cfg(feature = "rust_decimal")]
241 Value::Decimal(_) => Type::Decimal,
242 #[cfg(feature = "bigdecimal")]
243 Value::BigDecimal(_) => Type::BigDecimal,
244 #[cfg(feature = "jiff")]
245 Value::Timestamp(_) => Type::Timestamp,
246 #[cfg(feature = "jiff")]
247 Value::Zoned(_) => Type::Zoned,
248 #[cfg(feature = "jiff")]
249 Value::Date(_) => Type::Date,
250 #[cfg(feature = "jiff")]
251 Value::Time(_) => Type::Time,
252 #[cfg(feature = "jiff")]
253 Value::DateTime(_) => Type::DateTime,
254 }
255 }
256
257 #[track_caller]
258 pub fn entry(&self, path: impl EntryPath) -> Entry<'_> {
259 let mut ret = Entry::Value(self);
260
261 for step in path.step_iter() {
262 ret = match ret {
263 Entry::Value(Self::Record(record)) => Entry::Value(&record[step]),
264 Entry::Value(Self::List(items)) => Entry::Value(&items[step]),
265 _ => todo!("ret={ret:#?}; base={self:#?}; step={step:#?}"),
266 }
267 }
268
269 ret
270 }
271
272 pub fn take(&mut self) -> Self {
273 std::mem::take(self)
274 }
275}
276
277impl AsRef<Self> for Value {
278 fn as_ref(&self) -> &Self {
279 self
280 }
281}
282
283impl PartialOrd for Value {
284 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
292 match (self, other) {
293 (Value::Null, _) | (_, Value::Null) => None,
295
296 (Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
298
299 (Value::I8(a), Value::I8(b)) => a.partial_cmp(b),
301 (Value::I16(a), Value::I16(b)) => a.partial_cmp(b),
302 (Value::I32(a), Value::I32(b)) => a.partial_cmp(b),
303 (Value::I64(a), Value::I64(b)) => a.partial_cmp(b),
304
305 (Value::U8(a), Value::U8(b)) => a.partial_cmp(b),
307 (Value::U16(a), Value::U16(b)) => a.partial_cmp(b),
308 (Value::U32(a), Value::U32(b)) => a.partial_cmp(b),
309 (Value::U64(a), Value::U64(b)) => a.partial_cmp(b),
310
311 (Value::String(a), Value::String(b)) => a.partial_cmp(b),
313
314 (Value::Bytes(a), Value::Bytes(b)) => a.partial_cmp(b),
316
317 (Value::Uuid(a), Value::Uuid(b)) => a.partial_cmp(b),
319
320 #[cfg(feature = "rust_decimal")]
322 (Value::Decimal(a), Value::Decimal(b)) => a.partial_cmp(b),
323
324 #[cfg(feature = "bigdecimal")]
326 (Value::BigDecimal(a), Value::BigDecimal(b)) => a.partial_cmp(b),
327
328 #[cfg(feature = "jiff")]
330 (Value::Timestamp(a), Value::Timestamp(b)) => a.partial_cmp(b),
331 #[cfg(feature = "jiff")]
332 (Value::Zoned(a), Value::Zoned(b)) => a.partial_cmp(b),
333 #[cfg(feature = "jiff")]
334 (Value::Date(a), Value::Date(b)) => a.partial_cmp(b),
335 #[cfg(feature = "jiff")]
336 (Value::Time(a), Value::Time(b)) => a.partial_cmp(b),
337 #[cfg(feature = "jiff")]
338 (Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
339
340 _ => None,
342 }
343 }
344}
345
346impl From<bool> for Value {
347 fn from(src: bool) -> Self {
348 Self::Bool(src)
349 }
350}
351
352impl TryFrom<Value> for bool {
353 type Error = crate::Error;
354
355 fn try_from(value: Value) -> Result<Self, Self::Error> {
356 match value {
357 Value::Bool(v) => Ok(v),
358 _ => Err(crate::Error::type_conversion(value, "bool")),
359 }
360 }
361}
362
363impl From<String> for Value {
364 fn from(src: String) -> Self {
365 Self::String(src)
366 }
367}
368
369impl From<&String> for Value {
370 fn from(src: &String) -> Self {
371 Self::String(src.clone())
372 }
373}
374
375impl From<&str> for Value {
376 fn from(src: &str) -> Self {
377 Self::String(src.to_string())
378 }
379}
380
381impl From<ValueRecord> for Value {
382 fn from(value: ValueRecord) -> Self {
383 Self::Record(value)
384 }
385}
386
387impl<T> From<Option<T>> for Value
388where
389 Self: From<T>,
390{
391 fn from(value: Option<T>) -> Self {
392 match value {
393 Some(value) => Self::from(value),
394 None => Self::Null,
395 }
396 }
397}
398
399impl TryFrom<Value> for String {
400 type Error = crate::Error;
401
402 fn try_from(value: Value) -> Result<Self, Self::Error> {
403 match value {
404 Value::String(v) => Ok(v),
405 _ => Err(crate::Error::type_conversion(value, "String")),
406 }
407 }
408}
409
410impl From<Vec<u8>> for Value {
411 fn from(value: Vec<u8>) -> Self {
412 Self::Bytes(value)
413 }
414}
415
416impl TryFrom<Value> for Vec<u8> {
417 type Error = crate::Error;
418
419 fn try_from(value: Value) -> Result<Self, Self::Error> {
420 match value {
421 Value::Bytes(v) => Ok(v),
422 _ => Err(crate::Error::type_conversion(value, "Bytes")),
423 }
424 }
425}
426
427impl From<uuid::Uuid> for Value {
428 fn from(value: uuid::Uuid) -> Self {
429 Self::Uuid(value)
430 }
431}
432
433impl TryFrom<Value> for uuid::Uuid {
434 type Error = crate::Error;
435
436 fn try_from(value: Value) -> Result<Self, Self::Error> {
437 match value {
438 Value::Uuid(v) => Ok(v),
439 _ => Err(crate::Error::type_conversion(value, "uuid::Uuid")),
440 }
441 }
442}
443
444#[cfg(feature = "rust_decimal")]
445impl From<rust_decimal::Decimal> for Value {
446 fn from(value: rust_decimal::Decimal) -> Self {
447 Self::Decimal(value)
448 }
449}
450
451#[cfg(feature = "rust_decimal")]
452impl TryFrom<Value> for rust_decimal::Decimal {
453 type Error = crate::Error;
454
455 fn try_from(value: Value) -> Result<Self, Self::Error> {
456 match value {
457 Value::Decimal(v) => Ok(v),
458 _ => Err(crate::Error::type_conversion(
459 value,
460 "rust_decimal::Decimal",
461 )),
462 }
463 }
464}
465
466#[cfg(feature = "bigdecimal")]
467impl From<bigdecimal::BigDecimal> for Value {
468 fn from(value: bigdecimal::BigDecimal) -> Self {
469 Self::BigDecimal(value)
470 }
471}
472
473#[cfg(feature = "bigdecimal")]
474impl TryFrom<Value> for bigdecimal::BigDecimal {
475 type Error = crate::Error;
476
477 fn try_from(value: Value) -> Result<Self, Self::Error> {
478 match value {
479 Value::BigDecimal(v) => Ok(v),
480 _ => Err(crate::Error::type_conversion(
481 value,
482 "bigdecimal::BigDecimal",
483 )),
484 }
485 }
486}