1use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
6use rust_decimal::Decimal;
7use serde_json::Value as JsonValue;
8use smallvec::SmallVec;
9use std::collections::HashMap;
10use std::hash::{Hash, Hasher};
11use std::sync::Arc;
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub enum JsonPathToken {
16 Key(Arc<str>),
17 Index(usize),
18}
19
20fn resolve_json_at<'a>(mut current: &'a JsonValue, path: &[JsonPathToken]) -> Option<&'a JsonValue> {
21 for token in path {
22 match token {
23 JsonPathToken::Key(key) => {
24 current = current.as_object()?.get(key.as_ref())?;
25 }
26 JsonPathToken::Index(idx) => {
27 current = current.as_array()?.get(*idx)?;
28 }
29 }
30 }
31 Some(current)
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum TimePrecision {
37 Hour, Minute, Second, Millisecond, }
42
43impl TimePrecision {
44 pub fn is_compatible_with(self, other: TimePrecision) -> bool {
46 self == other
47 || matches!(
48 (self, other),
49 (TimePrecision::Second, TimePrecision::Millisecond)
50 | (TimePrecision::Millisecond, TimePrecision::Second)
51 )
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub enum DatePrecision {
58 Year, Month, Day, }
62
63impl DatePrecision {
64 pub fn is_compatible_with(self, other: DatePrecision) -> bool {
65 self == other
66 }
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71pub enum DateTimePrecision {
72 Year, Month, Day, Hour, Minute, Second, Millisecond, }
80
81impl DateTimePrecision {
82 pub fn is_compatible_with(self, other: DateTimePrecision) -> bool {
84 self == other
85 || matches!(
86 (self, other),
87 (DateTimePrecision::Second, DateTimePrecision::Millisecond)
88 | (DateTimePrecision::Millisecond, DateTimePrecision::Second)
89 )
90 }
91}
92
93#[derive(Clone, Debug)]
95pub struct Value(Arc<ValueData>);
96
97impl PartialEq for Value {
98 fn eq(&self, other: &Self) -> bool {
99 if self.ptr_eq(other) {
100 return true;
101 }
102 match (self.data(), other.data()) {
103 (ValueData::Empty, ValueData::Empty) => true,
104 (ValueData::Boolean(l), ValueData::Boolean(r)) => l == r,
105 (ValueData::Integer(l), ValueData::Integer(r)) => l == r,
106 (ValueData::Decimal(l), ValueData::Decimal(r)) => l == r,
107 (ValueData::String(l), ValueData::String(r)) => l == r,
108 (
109 ValueData::Date {
110 value: lv,
111 precision: lp,
112 },
113 ValueData::Date {
114 value: rv,
115 precision: rp,
116 },
117 ) => lv == rv && lp == rp,
118 (
119 ValueData::DateTime {
120 value: lv,
121 precision: lp,
122 timezone_offset: lt,
123 },
124 ValueData::DateTime {
125 value: rv,
126 precision: rp,
127 timezone_offset: rt,
128 },
129 ) => lv == rv && lp == rp && lt == rt,
130 (
131 ValueData::Time {
132 value: lv,
133 precision: lp,
134 },
135 ValueData::Time {
136 value: rv,
137 precision: rp,
138 },
139 ) => lv == rv && lp == rp,
140 (
141 ValueData::Quantity { value: lv, unit: lu },
142 ValueData::Quantity { value: rv, unit: ru },
143 ) => lv == rv && lu == ru,
144 (ValueData::Object(l), ValueData::Object(r)) => Arc::ptr_eq(l, r),
145 (
146 ValueData::LazyJson {
147 root: lr,
148 path: lp,
149 },
150 ValueData::LazyJson {
151 root: rr,
152 path: rp,
153 },
154 ) => Arc::ptr_eq(lr, rr) && lp == rp,
155 _ => false,
156 }
157 }
158}
159
160impl Eq for Value {}
161
162impl Hash for Value {
163 fn hash<H: Hasher>(&self, state: &mut H) {
164 match self.data() {
165 ValueData::Empty => {
166 0u8.hash(state);
167 }
168 ValueData::Boolean(b) => {
169 1u8.hash(state);
170 b.hash(state);
171 }
172 ValueData::Integer(i) => {
173 2u8.hash(state);
174 i.hash(state);
175 }
176 ValueData::Decimal(d) => {
177 3u8.hash(state);
178 d.to_string().hash(state);
180 }
181 ValueData::String(s) => {
182 4u8.hash(state);
183 s.hash(state);
184 }
185 ValueData::Date { value, precision } => {
186 5u8.hash(state);
187 value.hash(state);
188 precision.hash(state);
189 }
190 ValueData::DateTime {
191 value,
192 precision,
193 timezone_offset,
194 } => {
195 6u8.hash(state);
196 value.hash(state);
197 precision.hash(state);
198 timezone_offset.hash(state);
199 }
200 ValueData::Time { value, precision } => {
201 7u8.hash(state);
202 value.hash(state);
203 precision.hash(state);
204 }
205 ValueData::Quantity { value, unit } => {
206 8u8.hash(state);
207 value.to_string().hash(state);
209 unit.hash(state);
210 }
211 ValueData::Object(map) => {
212 9u8.hash(state);
213 Arc::as_ptr(map).hash(state);
215 }
216 ValueData::LazyJson { root, path } => {
217 10u8.hash(state);
218 Arc::as_ptr(root).hash(state);
220 path.hash(state);
221 }
222 }
223 }
224}
225
226impl Value {
227 pub fn data(&self) -> &ValueData {
228 &self.0
229 }
230
231 pub fn ptr_eq(&self, other: &Self) -> bool {
232 Arc::ptr_eq(&self.0, &other.0)
233 }
234
235 pub fn from_json(json: JsonValue) -> Self {
236 Self::from_json_root(Arc::new(json))
237 }
238
239 pub fn from_json_root(root: Arc<JsonValue>) -> Self {
240 Self::from_json_node(root.clone(), SmallVec::new(), root.as_ref())
241 }
242
243 pub fn boolean(b: bool) -> Self {
244 Self(Arc::new(ValueData::Boolean(b)))
245 }
246
247 pub fn integer(i: i64) -> Self {
248 Self(Arc::new(ValueData::Integer(i)))
249 }
250
251 pub fn decimal(d: Decimal) -> Self {
252 Self(Arc::new(ValueData::Decimal(d)))
253 }
254
255 pub fn string(s: impl Into<Arc<str>>) -> Self {
256 Self(Arc::new(ValueData::String(s.into())))
257 }
258
259 pub fn empty() -> Self {
260 Self(Arc::new(ValueData::Empty))
261 }
262
263 pub fn date(d: NaiveDate) -> Self {
264 Self(Arc::new(ValueData::Date {
265 value: d,
266 precision: DatePrecision::Day,
267 }))
268 }
269
270 pub fn date_with_precision(d: NaiveDate, precision: DatePrecision) -> Self {
271 Self(Arc::new(ValueData::Date {
272 value: d,
273 precision,
274 }))
275 }
276
277 pub fn datetime(dt: DateTime<Utc>) -> Self {
278 Self(Arc::new(ValueData::DateTime {
279 value: dt,
280 precision: DateTimePrecision::Second,
281 timezone_offset: Some(0), }))
283 }
284
285 pub fn datetime_with_precision(dt: DateTime<Utc>, precision: DateTimePrecision) -> Self {
286 Self(Arc::new(ValueData::DateTime {
287 value: dt,
288 precision,
289 timezone_offset: Some(0), }))
291 }
292
293 pub fn datetime_with_precision_and_offset(
294 dt: DateTime<Utc>,
295 precision: DateTimePrecision,
296 offset_seconds: Option<i32>,
297 ) -> Self {
298 Self(Arc::new(ValueData::DateTime {
299 value: dt,
300 precision,
301 timezone_offset: offset_seconds,
302 }))
303 }
304
305 pub fn time(t: NaiveTime) -> Self {
306 Self(Arc::new(ValueData::Time {
307 value: t,
308 precision: TimePrecision::Second,
309 }))
310 }
311
312 pub fn time_with_precision(t: NaiveTime, precision: TimePrecision) -> Self {
313 Self(Arc::new(ValueData::Time {
314 value: t,
315 precision,
316 }))
317 }
318
319 pub fn quantity(value: Decimal, unit: Arc<str>) -> Self {
320 Self(Arc::new(ValueData::Quantity { value, unit }))
321 }
322
323 pub fn object(map: HashMap<Arc<str>, Collection>) -> Self {
324 Self(Arc::new(ValueData::Object(Arc::new(map))))
325 }
326
327 fn from_json_eager_value(json: &JsonValue) -> Self {
329 Self(Arc::new(ValueData::from_json_eager(json)))
330 }
331
332 pub(crate) fn from_json_node(
333 root: Arc<JsonValue>,
334 path: SmallVec<[JsonPathToken; 4]>,
335 node: &JsonValue,
336 ) -> Self {
337 match node {
338 JsonValue::Null => Self::empty(),
339 JsonValue::Bool(b) => Self::boolean(*b),
340 JsonValue::Number(n) => {
341 if let Some(i) = n.as_i64() {
342 Self::integer(i)
343 } else if let Some(f) = n.as_f64() {
344 Self::decimal(Decimal::from_f64_retain(f).unwrap_or_default())
345 } else {
346 Self::empty()
347 }
348 }
349 JsonValue::String(s) => Self::string(Arc::from(s.as_str())),
350 JsonValue::Object(_) => Self(Arc::new(ValueData::LazyJson { root, path })),
351 JsonValue::Array(_) => Self::empty(),
352 }
353 }
354
355 pub fn materialize(&self) -> Self {
361 match self.data() {
362 ValueData::LazyJson { .. } => Self(Arc::new(self.0.materialize())),
363 _ => self.clone(),
364 }
365 }
366}
367
368#[derive(Debug, Clone)]
370pub enum ValueData {
371 Boolean(bool),
373 Integer(i64),
374 Decimal(Decimal),
375
376 String(Arc<str>),
378 Date {
379 value: NaiveDate,
380 precision: DatePrecision,
381 },
382 DateTime {
383 value: DateTime<Utc>,
384 precision: DateTimePrecision,
385 timezone_offset: Option<i32>,
390 },
391 Time {
392 value: NaiveTime,
393 precision: TimePrecision,
394 },
395 Quantity {
396 value: Decimal,
397 unit: Arc<str>,
398 },
399
400 Object(Arc<HashMap<Arc<str>, Collection>>),
402
403 LazyJson {
406 root: Arc<JsonValue>,
407 path: SmallVec<[JsonPathToken; 4]>,
408 },
409
410 Empty,
412 }
414
415impl ValueData {
416 pub(crate) fn resolved_json(&self) -> Option<&JsonValue> {
417 match self {
418 ValueData::LazyJson { root, path } => resolve_json_at(root.as_ref(), path.as_slice()),
419 _ => None,
420 }
421 }
422
423 pub fn as_string(&self) -> Option<Arc<str>> {
425 match self {
426 ValueData::String(s) => Some(s.clone()),
427 _ => None,
428 }
429 }
430
431 pub(crate) fn materialize(&self) -> ValueData {
436 match self {
437 ValueData::LazyJson { .. } => self
438 .resolved_json()
439 .map(Self::from_json_eager)
440 .unwrap_or(ValueData::Empty),
441 other => other.clone(),
442 }
443 }
444
445 fn from_json_eager(json: &JsonValue) -> Self {
447 match json {
448 JsonValue::Null => ValueData::Empty,
449 JsonValue::Bool(b) => ValueData::Boolean(*b),
450 JsonValue::Number(n) => {
451 if let Some(i) = n.as_i64() {
452 ValueData::Integer(i)
453 } else if let Some(f) = n.as_f64() {
454 ValueData::Decimal(Decimal::from_f64_retain(f).unwrap_or_default())
455 } else {
456 ValueData::Empty
457 }
458 }
459 JsonValue::String(s) => ValueData::String(Arc::from(s.as_str())),
460 JsonValue::Array(_arr) => {
461 ValueData::Empty
463 }
464 JsonValue::Object(obj) => {
465 let mut map = HashMap::new();
466 for (k, v) in obj {
467 if let JsonValue::Array(arr) = v {
468 let mut coll = Collection::empty();
469 for item in arr {
470 coll.push(Value::from_json_eager_value(item));
471 }
472 map.insert(Arc::from(k.as_str()), coll);
473 } else {
474 let mut coll = Collection::empty();
475 coll.push(Value::from_json_eager_value(v));
476 map.insert(Arc::from(k.as_str()), coll);
477 }
478 }
479 ValueData::Object(Arc::new(map))
480 }
481 }
482 }
483}
484
485const COLLECTION_ARC_THRESHOLD: usize = 4;
488
489#[derive(Clone, Debug)]
494pub struct Collection {
495 inner: CollectionInner,
496}
497
498#[derive(Clone, Debug)]
499enum CollectionInner {
500 Small(SmallVec<[Value; 4]>),
502 Large(Arc<SmallVec<[Value; 4]>>),
505}
506
507impl Collection {
508 pub fn empty() -> Self {
509 Self {
510 inner: CollectionInner::Small(SmallVec::new()),
511 }
512 }
513
514 pub fn singleton(value: Value) -> Self {
515 let mut inner = SmallVec::new();
516 inner.push(value);
517 Self {
518 inner: CollectionInner::Small(inner),
519 }
520 }
521
522 pub fn with_capacity(capacity: usize) -> Self {
523 let inner = SmallVec::with_capacity(capacity);
524 if capacity > COLLECTION_ARC_THRESHOLD {
525 Self {
526 inner: CollectionInner::Large(Arc::new(inner)),
527 }
528 } else {
529 Self {
530 inner: CollectionInner::Small(inner),
531 }
532 }
533 }
534
535 fn get_mut(&mut self) -> &mut SmallVec<[Value; 4]> {
538 if let CollectionInner::Large(arc) = &self.inner {
540 let vec = (**arc).clone();
541 self.inner = CollectionInner::Small(vec);
542 }
543
544 match &mut self.inner {
546 CollectionInner::Small(vec) => vec,
547 CollectionInner::Large(_) => unreachable!(),
548 }
549 }
550
551 fn ensure_representation(&mut self) {
554 let len = self.len();
555 match &self.inner {
556 CollectionInner::Small(vec) if len > COLLECTION_ARC_THRESHOLD => {
557 let vec = vec.clone();
559 self.inner = CollectionInner::Large(Arc::new(vec));
560 }
561 CollectionInner::Large(arc) if len <= COLLECTION_ARC_THRESHOLD => {
562 let vec = (**arc).clone();
564 self.inner = CollectionInner::Small(vec);
565 }
566 _ => {
567 }
569 }
570 }
571
572 pub fn push(&mut self, value: Value) {
573 self.get_mut().push(value);
574 self.ensure_representation();
575 }
576
577 pub fn iter(&self) -> impl Iterator<Item = &Value> {
578 match &self.inner {
580 CollectionInner::Small(vec) => vec.iter(),
581 CollectionInner::Large(arc) => arc.iter(),
582 }
583 }
584
585 pub fn is_empty(&self) -> bool {
586 match &self.inner {
587 CollectionInner::Small(vec) => vec.is_empty(),
588 CollectionInner::Large(arc) => arc.is_empty(),
589 }
590 }
591
592 pub fn len(&self) -> usize {
593 match &self.inner {
594 CollectionInner::Small(vec) => vec.len(),
595 CollectionInner::Large(arc) => arc.len(),
596 }
597 }
598
599 pub fn get(&self, index: usize) -> Option<&Value> {
601 match &self.inner {
602 CollectionInner::Small(vec) => vec.get(index),
603 CollectionInner::Large(arc) => arc.get(index),
604 }
605 }
606
607 pub fn as_boolean(&self) -> Result<bool> {
608 if self.is_empty() {
609 return Ok(false);
610 }
611 if self.len() > 1 {
612 return Err(Error::TypeError("Expected singleton boolean".into()));
613 }
614 match self.get(0).unwrap().data() {
615 ValueData::Boolean(b) => Ok(*b),
616 _ => Err(Error::TypeError("Expected boolean value".into())),
617 }
618 }
619
620 pub fn as_string(&self) -> Result<Arc<str>> {
621 if self.is_empty() {
622 return Err(Error::TypeError("Empty collection".into()));
623 }
624 if self.len() > 1 {
625 return Err(Error::TypeError("Expected singleton string".into()));
626 }
627 match self.get(0).unwrap().data() {
628 ValueData::String(s) => Ok(s.clone()),
629 _ => Err(Error::TypeError("Expected string value".into())),
630 }
631 }
632
633 pub fn as_integer(&self) -> Result<i64> {
634 if self.is_empty() {
635 return Err(Error::TypeError("Empty collection".into()));
636 }
637 if self.len() > 1 {
638 return Err(Error::TypeError("Expected singleton integer".into()));
639 }
640 match self.get(0).unwrap().data() {
641 ValueData::Integer(i) => Ok(*i),
642 _ => Err(Error::TypeError("Expected integer value".into())),
643 }
644 }
645}
646
647use crate::error::{Error, Result};