1use bigdecimal::BigDecimal;
2use num_bigint::BigUint;
3use serde::de::{Error, MapAccess, SeqAccess, Visitor};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Number;
6use std::collections::hash_map::Entry;
7use std::collections::{BTreeMap, HashMap};
8use std::fmt::{self, Display, Formatter};
9use std::str::FromStr;
10use std::time::Duration;
11
12use crate::{join, join_format};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum Value {
16 Object(HashMap<String, Value>),
17 Array(Vec<Value>),
18 Boolean(bool),
19 Null,
20 String(String),
21 Number(Number),
22}
23
24impl Value {
25 pub fn object(obj: HashMap<String, Value>) -> Value {
26 Value::Object(obj)
27 }
28
29 pub fn object_from_iter<I>(iter: I) -> Value
30 where
31 I: IntoIterator<Item = (String, Value)>,
32 {
33 Value::Object(HashMap::from_iter(iter))
34 }
35
36 pub fn array(values: Vec<Value>) -> Value {
37 Value::Array(values)
38 }
39
40 pub fn array_from_iter<I>(iter: I) -> Value
41 where
42 I: IntoIterator<Item = Value>,
43 {
44 Value::Array(iter.into_iter().collect())
45 }
46
47 pub fn boolean(boolean: bool) -> Value {
48 Value::Boolean(boolean)
49 }
50
51 pub fn null() -> Value {
52 Value::Null
53 }
54
55 pub fn new_string(string: impl Into<String>) -> Value {
56 Value::String(string.into())
57 }
58}
59
60impl Value {
61 pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
62 match self {
63 Value::Object(object) => Some(object),
64 _ => None,
65 }
66 }
67
68 pub fn as_object_mut(&mut self) -> Option<&mut HashMap<String, Value>> {
69 match self {
70 Value::Object(object) => Some(object),
71 _ => None,
72 }
73 }
74
75 pub fn as_array(&self) -> Option<&Vec<Value>> {
76 match self {
77 Value::Array(array) => Some(array),
78 _ => None,
79 }
80 }
81
82 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
83 match self {
84 Value::Array(array) => Some(array),
85 _ => None,
86 }
87 }
88
89 pub fn as_array_numerically(&self) -> Option<Vec<&Value>> {
122 match self {
123 Value::Array(array) => Some(array.iter().collect()),
125
126 Value::Object(object) => {
128 let mut object_array = object
130 .iter()
131 .filter(|(key, _)| key.parse::<usize>().is_ok())
132 .collect::<Vec<_>>();
133
134 object_array.sort_by(|a, b| a.0.cmp(b.0));
136
137 let array = object_array
139 .into_iter()
140 .map(|(_, value)| value)
141 .collect::<Vec<_>>();
142
143 Some(array)
144 }
145
146 _ => None,
148 }
149 }
150
151 pub fn as_boolean(&self) -> Option<bool> {
171 match self {
172 Value::Boolean(boolean) => Some(*boolean),
174
175 Value::String(boolean) if boolean == "true" || boolean == "on" || boolean == "yes" => {
177 Some(true)
178 }
179
180 Value::String(boolean) if boolean == "false" || boolean == "off" || boolean == "no" => {
182 Some(false)
183 }
184
185 _ => None,
187 }
188 }
189
190 pub fn as_str(&self) -> Option<&str> {
191 match self {
192 Value::String(string) => Some(string),
193 _ => None,
194 }
195 }
196
197 pub fn as_f64(&self) -> Option<f64> {
198 match self {
199 Value::Number(number) => number.as_f64(),
200 Value::String(number) => number.parse().ok(),
201 _ => None,
202 }
203 }
204
205 pub fn as_i64(&self) -> Option<i64> {
206 match self {
207 Value::Number(number) => number.as_i64(),
208 Value::String(number) => number.parse().ok(),
209 _ => None,
210 }
211 }
212
213 pub fn as_i128(&self) -> Option<i128> {
214 match self {
215 Value::Number(number) => number.as_i128(),
216 Value::String(number) => number.parse().ok(),
217 _ => None,
218 }
219 }
220
221 pub fn as_u128(&self) -> Option<u128> {
222 match self {
223 Value::Number(number) => number.as_u128(),
224 Value::String(number) => number.parse().ok(),
225 _ => None,
226 }
227 }
228
229 pub fn as_u64(&self) -> Option<u64> {
230 match self {
231 Value::Number(number) => number.as_u64(),
232 Value::String(number) => number.parse().ok(),
233 _ => None,
234 }
235 }
236
237 pub fn is_null(&self) -> bool {
251 match self {
252 Value::Null => true,
253 Value::String(s) if s == "null" => true,
254 _ => false,
255 }
256 }
257
258 pub fn ty(&self) -> &'static str {
259 match self {
260 Value::Object(_) => "Object",
261 Value::Array(_) => "Array",
262 Value::Boolean(_) => "Boolean",
263 Value::Null => "Null",
264 Value::String(_) => "String",
265 Value::Number(_) => "Number",
266 }
267 }
268
269 pub fn into_object(self) -> Option<HashMap<String, Value>> {
270 match self {
271 Value::Object(object) => Some(object),
272 _ => None,
273 }
274 }
275
276 pub fn into_array(self) -> Option<Vec<Value>> {
277 match self {
278 Value::Array(array) => Some(array),
279 _ => None,
280 }
281 }
282
283 pub fn into_boolean(self) -> Option<bool> {
284 match self {
285 Value::Boolean(boolean) => Some(boolean),
286 _ => None,
287 }
288 }
289
290 pub fn into_string(self) -> Option<String> {
291 match self {
292 Value::String(string) => Some(string),
293 _ => None,
294 }
295 }
296
297 pub fn into_number(self) -> Option<Number> {
298 match self {
299 Value::Number(number) => Some(number),
300 _ => None,
301 }
302 }
303
304 pub fn get_by_path<'a>(&self, paths: impl AsRef<[&'a str]>) -> Option<&Value> {
333 let paths = paths.as_ref();
334
335 if paths.is_empty() {
337 return None;
338 }
339
340 let mut current = self;
342
343 for &path in paths {
345 current = match current {
346 Value::Object(obj) => obj.get(path)?,
347 _ => return None,
349 };
350 }
351
352 Some(current)
353 }
354
355 pub fn get_by_path_mut<'a>(&mut self, paths: impl AsRef<[&'a str]>) -> Option<&mut Value> {
356 let paths = paths.as_ref();
357 if paths.is_empty() {
358 return None;
359 }
360 let mut current = self;
361 for &path in paths {
362 current = match current {
363 Value::Object(obj) => obj.get_mut(path)?,
364 _ => return None,
365 };
366 }
367 Some(current)
368 }
369
370 pub fn with_fallback(self, fallback: Value) -> Value {
380 match (self, fallback) {
381 (Value::Object(mut obj), Value::Object(fb_obj)) => {
383 for (k, fb_val) in fb_obj {
384 match obj.entry(k) {
385 Entry::Occupied(mut occupied_entry) => {
387 let existing_val = occupied_entry.get_mut();
388
389 if let (Value::Object(_), Value::Object(_)) = (&existing_val, &fb_val) {
391 let mut temp = Value::Null;
393 std::mem::swap(&mut temp, existing_val);
394
395 *existing_val = temp.with_fallback(fb_val);
397 }
398 }
400
401 Entry::Vacant(vacant_entry) => {
403 vacant_entry.insert(fb_val);
404 }
405 }
406 }
407 Value::Object(obj)
408 }
409
410 (other, _) => other,
412 }
413 }
414}
415
416impl Value {
417 pub fn as_bytes(&self) -> Option<BigUint> {
418 fn str_to_bytes(s: &str) -> Option<BigUint> {
419 let idx = s
420 .find(|c: char| !(c.is_ascii_digit() || c == '.'))
421 .unwrap_or(s.len());
422 let (num, unit) = s.split_at(idx);
423 let bytes = match unit.trim() {
424 "" | "B" | "b" | "byte" | "bytes" => Some(BigUint::from(1u32)),
425 "kB" | "kilobyte" | "kilobytes" => Some(BigUint::from(10u32).pow(3u32)),
426 "MB" | "megabyte" | "megabytes" => Some(BigUint::from(10u32).pow(6u32)),
427 "GB" | "gigabyte" | "gigabytes" => Some(BigUint::from(10u32).pow(9u32)),
428 "TB" | "terabyte" | "terabytes" => Some(BigUint::from(10u32).pow(12u32)),
429 "PB" | "petabyte" | "petabytes" => Some(BigUint::from(10u32).pow(15u32)),
430 "EB" | "exabyte" | "exabytes" => Some(BigUint::from(10u32).pow(18u32)),
431 "ZB" | "zettabyte" | "zettabytes" => Some(BigUint::from(10u32).pow(21u32)),
432 "YB" | "yottabyte" | "yottabytes" => Some(BigUint::from(10u32).pow(24u32)),
433
434 "K" | "k" | "Ki" | "KiB" | "kibibyte" | "kibibytes" => {
435 Some(BigUint::from(2u32).pow(10u32))
436 }
437 "M" | "m" | "Mi" | "MiB" | "mebibyte" | "mebibytes" => {
438 Some(BigUint::from(2u32).pow(20u32))
439 }
440 "G" | "g" | "Gi" | "GiB" | "gibibyte" | "gibibytes" => {
441 Some(BigUint::from(2u32).pow(30u32))
442 }
443 "T" | "t" | "Ti" | "TiB" | "tebibyte" | "tebibytes" => {
444 Some(BigUint::from(2u32).pow(40u32))
445 }
446 "P" | "p" | "Pi" | "PiB" | "pebibyte" | "pebibytes" => {
447 Some(BigUint::from(2u32).pow(50u32))
448 }
449 "E" | "e" | "Ei" | "EiB" | "exbibyte" | "exbibytes" => {
450 Some(BigUint::from(2u32).pow(60u32))
451 }
452 "Z" | "z" | "Zi" | "ZiB" | "zebibyte" | "zebibytes" => {
453 Some(BigUint::from(2u32).pow(70u32))
454 }
455 "Y" | "y" | "Yi" | "YiB" | "yobibyte" | "yobibytes" => {
456 Some(BigUint::from(2u32).pow(80u32))
457 }
458
459 _ => None,
460 }?;
461 match BigUint::from_str(num) {
462 Ok(num) => Some(&num * &bytes),
463 Err(_) => match BigDecimal::from_str(num) {
464 Ok(num) => {
465 let bytes = BigDecimal::from_str(&bytes.to_string()).ok()?;
466 let num = &num * &bytes;
467 let (num, _) = num.with_scale(0).into_bigint_and_exponent();
468 BigUint::from_str(&num.to_string()).ok()
469 }
470 Err(_) => None,
471 },
472 }
473 }
474 match self {
475 #[cfg(not(feature = "json_arbitrary_precision"))]
476 Value::Number(num) => match num.as_u64().map(BigUint::from) {
477 None => {
478 use bigdecimal::FromPrimitive;
479 let (num, _) = num
480 .as_f64()
481 .and_then(BigDecimal::from_f64)?
482 .with_scale(0)
483 .into_bigint_and_exponent();
484 BigUint::from_str(&num.to_string()).ok()
485 }
486 Some(i) => Some(i),
487 },
488 #[cfg(feature = "json_arbitrary_precision")]
489 Value::Number(i) => str_to_bytes(i.as_str()),
490 Value::String(s) => str_to_bytes(s.as_str().trim()),
491 _ => None,
492 }
493 }
494
495 pub fn as_duration(&self) -> Option<Duration> {
496 fn duration_from_minutes(min: f64) -> Duration {
497 let secs = min * 60.0;
498 let whole = secs.trunc() as u64;
499 let nanos = (secs.fract() * 1_000_000_000.0).round() as u32;
500 Duration::new(whole, nanos)
501 }
502
503 fn duration_from_millis_f64(ms: f64) -> Duration {
504 let secs = (ms / 1000.0) as u64;
505 let nanos = ((ms % 1000.0) * 1_000_000.0) as u32;
506 Duration::new(secs, nanos)
507 }
508
509 fn str_to_duration(s: &str) -> Option<Duration> {
510 let idx = s
511 .find(|c: char| !(c.is_ascii_digit() || c == '.'))
512 .unwrap_or(s.len());
513 let (num, unit) = s.split_at(idx);
514 match unit {
515 "ns" | "nano" | "nanos" | "nanosecond" | "nanoseconds" => {
516 Some(Duration::from_nanos(num.parse().ok()?))
517 }
518 "us" | "micro" | "micros" | "microsecond" | "microseconds" => {
519 Some(Duration::from_micros(num.parse().ok()?))
520 }
521 "" | "ms" | "milli" | "millis" | "millisecond" | "milliseconds" => {
522 Some(duration_from_millis_f64(num.parse().ok()?))
523 }
524 "s" | "second" | "seconds" => {
525 let s: f64 = num.parse().ok()?;
526 Some(duration_from_millis_f64(s * 1000.0))
527 }
528 "m" | "minute" | "minutes" => Some(duration_from_minutes(num.parse().ok()?)),
529 "h" | "hour" | "hours" => {
530 let h: f64 = num.parse().ok()?;
531 Some(duration_from_minutes(h * 60.0))
532 }
533 "d" | "day" | "days" => {
534 let d: f64 = num.parse().ok()?;
535 Some(duration_from_minutes(d * 60.0 * 24.0))
536 }
537 _ => None,
538 }
539 }
540
541 match self {
542 #[cfg(not(feature = "json_arbitrary_precision"))]
543 Value::Number(millis) => match millis.as_u64() {
544 Some(millis) => {
545 let duration = Duration::from_millis(millis);
546 Some(duration)
547 }
548 None => millis.as_f64().map(duration_from_millis_f64),
549 },
550 #[cfg(feature = "json_arbitrary_precision")]
551 Value::Number(i) => str_to_duration(i.as_str()),
552 Value::String(s) => str_to_duration(s.as_str().trim()),
553 _ => None,
554 }
555 }
556
557 pub fn as_nanos(&self) -> Option<u128> {
558 self.as_duration().map(|d| d.as_nanos())
559 }
560
561 pub fn as_millis(&self) -> Option<u128> {
562 self.as_duration().map(|d| d.as_millis())
563 }
564
565 pub fn as_secs(&self) -> Option<u64> {
566 self.as_duration().map(|d| d.as_secs())
567 }
568
569 pub fn as_secs_f32(&self) -> Option<f32> {
570 self.as_duration().map(|d| d.as_secs_f32())
571 }
572
573 pub fn as_secs_f64(&self) -> Option<f64> {
574 self.as_duration().map(|d| d.as_secs_f64())
575 }
576}
577
578impl Display for Value {
579 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
580 match self {
581 Value::Object(object) => {
582 write!(f, "{{")?;
583 join_format(
584 object.iter(),
585 f,
586 |f| write!(f, ", "),
587 |f, (k, v)| write!(f, "{k}: {v}"),
588 )?;
589 write!(f, "}}")?;
590 Ok(())
591 }
592 Value::Array(array) => {
593 write!(f, "[")?;
594 join(array.iter(), ", ", f)?;
595 write!(f, "]")?;
596 Ok(())
597 }
598 Value::Boolean(boolean) => {
599 write!(f, "{}", boolean)
600 }
601 Value::Null => {
602 write!(f, "null")
603 }
604 Value::String(string) => {
605 write!(f, "{}", string)
606 }
607 Value::Number(number) => {
608 write!(f, "{}", number)
609 }
610 }
611 }
612}
613
614impl TryFrom<crate::merge::value::Value> for Value {
615 type Error = crate::error::Error;
616
617 fn try_from(value: crate::merge::value::Value) -> Result<Self, Self::Error> {
618 fn from_object(object: crate::merge::object::Object) -> crate::Result<Value> {
619 let inner: BTreeMap<_, _> = object.into();
620 let mut object = HashMap::with_capacity(inner.len());
621 for (k, v) in inner.into_iter() {
622 let v = v.into_inner();
623 if !matches!(v, crate::merge::value::Value::None) {
624 let v: Value = v.try_into()?;
625 object.insert(k, v);
626 }
627 }
628 Ok(Value::Object(object))
629 }
630
631 fn from_array(array: crate::merge::array::Array) -> crate::Result<Value> {
632 let mut result = Vec::with_capacity(array.len());
633 for ele in array.into_inner().into_iter() {
634 let v = ele.into_inner();
635 let v: Value = v.try_into()?;
636 result.push(v);
637 }
638 Ok(Value::Array(result))
639 }
640 let value = match value {
641 crate::merge::value::Value::Object(object) => {
642 if object.is_unmerged() {
643 return Err(crate::error::Error::ResolveIncomplete);
644 }
645 from_object(object)?
646 }
647 crate::merge::value::Value::Array(array) => from_array(array)?,
648 crate::merge::value::Value::Boolean(boolean) => Value::Boolean(boolean),
649 crate::merge::value::Value::Null | crate::merge::value::Value::None => Value::Null,
650 crate::merge::value::Value::String(string) => Value::String(string),
651 crate::merge::value::Value::Number(number) => Value::Number(number),
652 crate::merge::value::Value::Substitution(_)
653 | crate::merge::value::Value::Concat(_)
654 | crate::merge::value::Value::AddAssign(_)
655 | crate::merge::value::Value::DelayReplacement(_) => {
656 return Err(crate::error::Error::ResolveIncomplete);
657 }
658 };
659 Ok(value)
660 }
661}
662
663impl Serialize for Value {
664 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
665 where
666 S: Serializer,
667 {
668 match self {
669 Value::Object(map) => map.serialize(serializer),
670 Value::Array(arr) => arr.serialize(serializer),
671 Value::Boolean(b) => b.serialize(serializer),
672 Value::Null => serializer.serialize_none(),
673 Value::String(s) => s.serialize(serializer),
674 Value::Number(num) => num.serialize(serializer),
675 }
676 }
677}
678
679impl<'de> Deserialize<'de> for Value {
680 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
681 where
682 D: Deserializer<'de>,
683 {
684 struct ValueVisitor;
685
686 impl<'de> Visitor<'de> for ValueVisitor {
687 type Value = Value;
688
689 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
690 formatter.write_str("any valid HOCON value")
691 }
692
693 fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
694 Ok(Value::Boolean(v))
695 }
696
697 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> {
698 Ok(Value::Number(Number::from(v)))
699 }
700
701 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
702 Ok(Value::Number(Number::from(v)))
703 }
704
705 fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
706 where
707 E: Error,
708 {
709 Ok(Number::from_f64(v)
710 .map(Value::Number)
711 .unwrap_or(Value::Null))
712 }
713
714 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
715 Ok(Value::String(v.to_owned()))
716 }
717
718 fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
719 Ok(Value::String(v))
720 }
721
722 fn visit_none<E>(self) -> Result<Self::Value, E> {
723 Ok(Value::Null)
724 }
725
726 fn visit_unit<E>(self) -> Result<Self::Value, E> {
727 Ok(Value::Null)
728 }
729
730 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
731 where
732 A: SeqAccess<'de>,
733 {
734 let mut vec = Vec::new();
735 while let Some(elem) = seq.next_element()? {
736 vec.push(elem);
737 }
738 Ok(Value::Array(vec))
739 }
740
741 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
742 where
743 M: MapAccess<'de>,
744 {
745 match map.next_key::<String>()? {
746 None => Ok(Value::Object(HashMap::new())),
747 Some(first_key) => match first_key.as_str() {
748 #[cfg(feature = "json_arbitrary_precision")]
749 "$serde_json::private::Number" => {
750 let v: String = map.next_value()?;
751 let n = serde_json::Number::from_str(&v).map_err(Error::custom)?;
752 Ok(Value::Number(n))
753 }
754 _ => {
755 let mut values = HashMap::new();
756 let value = map.next_value()?;
757 values.insert(first_key, value);
758 while let Some((k, v)) = map.next_entry()? {
759 values.insert(k, v);
760 }
761 Ok(Value::Object(values))
762 }
763 },
764 }
765 }
766 }
767
768 deserializer.deserialize_any(ValueVisitor)
769 }
770}
771
772#[cfg(test)]
773mod tests {
774
775 use super::*;
776 use num_bigint::BigUint;
777 use rstest::rstest;
778
779 #[rstest]
780 #[case(Value::Number(0.into()), Some(BigUint::from(0u32)))]
781 #[case(Value::Number(42.into()), Some(BigUint::from(42u32)))]
782 #[case(Value::String("123".into()), Some(BigUint::from(123u32)))]
783 #[case(Value::String("123B".into()), Some(BigUint::from(123u32)))]
784 #[case(Value::String("10bytes".into()), Some(BigUint::from(10u32)))]
785 #[case(Value::String("1kB".into()), Some(BigUint::from(1000u32)))]
786 #[case(Value::String("2MB".into()), Some(BigUint::from(2_000_000u32)))]
787 #[case(Value::String("3GB".into()), Some(BigUint::from(3_000_000_000u64)))]
788 #[case(Value::String("4TB".into()), Some(BigUint::from(4_000_000_000_000u64)))]
789 #[case(Value::String("5PB".into()), Some(BigUint::from(5_000_000_000_000_000u64)))]
790 #[case(Value::String("6EB".into()), Some(BigUint::from(6u128 * 10u128.pow(18))))]
791 #[case(Value::String("7ZB".into()), Some(BigUint::from(7u128 * 10u128.pow(21))))]
792 #[case(Value::String("8YB".into()), Some(BigUint::from(8u128 * 10u128.pow(24))))]
793 #[case(Value::String("1KiB".into()), Some(BigUint::from(1024u32)))]
794 #[case(Value::String("2MiB".into()), Some(BigUint::from(2u64 * 1024 * 1024)))]
795 #[case(Value::String("3GiB".into()), Some(BigUint::from(3u64 * 1024 * 1024 * 1024)))]
796 #[case(Value::String("4TiB".into()), Some(BigUint::from(4u128 * (1u128 << 40))))]
797 #[case(Value::String("5PiB".into()), Some(BigUint::from(5u128 * (1u128 << 50))))]
798 #[case(Value::String("6EiB".into()), Some(BigUint::from(6u128 * (1u128 << 60))))]
799 #[case(Value::String("7ZiB".into()), Some(BigUint::from(7u128 * (1u128 << 70))))]
800 #[case(Value::String("8YiB".into()), Some(BigUint::from(8u128 * (1u128 << 80))))]
801 #[case(Value::String("1.5kB".into()), Some(BigUint::from(1500u32)))] #[case(Value::String("0.5MiB".into()), Some(BigUint::from(512u32 * 1024)))] #[case(Value::String("999999999YB".into()), Some(BigUint::from(999_999_999u128) * BigUint::from(10u128).pow(24)
804 ))] #[case(Value::String("999999999YiB".into()), Some(BigUint::from(999_999_999u128) * (BigUint::from(2u32).pow(80))
806 ))] #[case(Value::String("not_a_number".into()), None)]
808 #[case(Value::String("123unknown".into()), None)]
809 fn test_as_bytes(#[case] input: Value, #[case] expected: Option<BigUint>) {
810 assert_eq!(input.as_bytes(), expected);
811 }
812
813 fn si_factor(exp: u32) -> BigUint {
814 BigUint::from(10u32).pow(exp)
815 }
816
817 fn bin_factor(exp: u32) -> BigUint {
818 BigUint::from(2u32).pow(exp)
819 }
820
821 #[rstest]
822 #[case("B", BigUint::from(1u32))]
823 #[case("b", BigUint::from(1u32))]
824 #[case("byte", BigUint::from(1u32))]
825 #[case("bytes", BigUint::from(1u32))]
826 #[case("kB", si_factor(3))]
827 #[case("kilobyte", si_factor(3))]
828 #[case("kilobytes", si_factor(3))]
829 #[case("MB", si_factor(6))]
830 #[case("megabyte", si_factor(6))]
831 #[case("megabytes", si_factor(6))]
832 #[case("GB", si_factor(9))]
833 #[case("gigabyte", si_factor(9))]
834 #[case("gigabytes", si_factor(9))]
835 #[case("TB", si_factor(12))]
836 #[case("terabyte", si_factor(12))]
837 #[case("terabytes", si_factor(12))]
838 #[case("PB", si_factor(15))]
839 #[case("petabyte", si_factor(15))]
840 #[case("petabytes", si_factor(15))]
841 #[case("EB", si_factor(18))]
842 #[case("exabyte", si_factor(18))]
843 #[case("exabytes", si_factor(18))]
844 #[case("ZB", si_factor(21))]
845 #[case("zettabyte", si_factor(21))]
846 #[case("zettabytes", si_factor(21))]
847 #[case("YB", si_factor(24))]
848 #[case("yottabyte", si_factor(24))]
849 #[case("yottabytes", si_factor(24))]
850 #[case("K", bin_factor(10))]
851 #[case("k", bin_factor(10))]
852 #[case("Ki", bin_factor(10))]
853 #[case("KiB", bin_factor(10))]
854 #[case("kibibyte", bin_factor(10))]
855 #[case("kibibytes", bin_factor(10))]
856 #[case("M", bin_factor(20))]
857 #[case("m", bin_factor(20))]
858 #[case("Mi", bin_factor(20))]
859 #[case("MiB", bin_factor(20))]
860 #[case("mebibyte", bin_factor(20))]
861 #[case("mebibytes", bin_factor(20))]
862 #[case("G", bin_factor(30))]
863 #[case("g", bin_factor(30))]
864 #[case("Gi", bin_factor(30))]
865 #[case("GiB", bin_factor(30))]
866 #[case("gibibyte", bin_factor(30))]
867 #[case("gibibytes", bin_factor(30))]
868 #[case("T", bin_factor(40))]
869 #[case("t", bin_factor(40))]
870 #[case("Ti", bin_factor(40))]
871 #[case("TiB", bin_factor(40))]
872 #[case("tebibyte", bin_factor(40))]
873 #[case("tebibytes", bin_factor(40))]
874 #[case("P", bin_factor(50))]
875 #[case("p", bin_factor(50))]
876 #[case("Pi", bin_factor(50))]
877 #[case("PiB", bin_factor(50))]
878 #[case("pebibyte", bin_factor(50))]
879 #[case("pebibytes", bin_factor(50))]
880 #[case("E", bin_factor(60))]
881 #[case("e", bin_factor(60))]
882 #[case("Ei", bin_factor(60))]
883 #[case("EiB", bin_factor(60))]
884 #[case("exbibyte", bin_factor(60))]
885 #[case("exbibytes", bin_factor(60))]
886 #[case("Z", bin_factor(70))]
887 #[case("z", bin_factor(70))]
888 #[case("Zi", bin_factor(70))]
889 #[case("ZiB", bin_factor(70))]
890 #[case("zebibyte", bin_factor(70))]
891 #[case("zebibytes", bin_factor(70))]
892 #[case("Y", bin_factor(80))]
893 #[case("y", bin_factor(80))]
894 #[case("Yi", bin_factor(80))]
895 #[case("YiB", bin_factor(80))]
896 #[case("yobibyte", bin_factor(80))]
897 #[case("yobibytes", bin_factor(80))]
898 fn test_as_bytes_all_units(#[case] unit: &str, #[case] factor: BigUint) {
899 let input = Value::String(format!("1{}", unit));
900 assert_eq!(input.as_bytes(), Some(factor));
901 }
902
903 #[rstest]
904 #[case(Value::String("123 B".into()), Some(BigUint::from(123u32)))]
905 #[case(Value::String("1 kB".into()), Some(BigUint::from(1000u32)))]
906 #[case(Value::String("2 MB".into()), Some(BigUint::from(2_000_000u32)))]
907 #[case(Value::String("1.5 kB".into()), Some(BigUint::from(1500u32)))]
908 #[case(Value::String("0.5 MiB".into()), Some(BigUint::from(512u32 * 1024)))]
909 fn test_as_bytes_with_space(#[case] input: Value, #[case] expected: Option<BigUint>) {
910 assert_eq!(input.as_bytes(), expected);
911 }
912
913 #[rstest]
914 #[case(Number::from(-1), None)]
915 #[case(Number::from(0), Some(BigUint::from(0u32)))]
916 #[case(Number::from(42), Some(BigUint::from(42u32)))]
917 #[case(Number::from(u64::MAX), Some(BigUint::from(u64::MAX)))]
918 #[case(Number::from_f64(1.1).unwrap(), Some(BigUint::from(1u32)))]
919 #[case(Number::from_f64(1.9).unwrap(), Some(BigUint::from(1u32)))]
920 fn test_as_bytes_number(#[case] num: Number, #[case] expected: Option<BigUint>) {
921 let input = Value::Number(num);
922 assert_eq!(input.as_bytes(), expected);
923 }
924
925 #[cfg(feature = "json_arbitrary_precision")]
926 #[rstest]
927 #[case("184467440737095516160000")]
928 fn test_as_bytes_arbitrary_precision(#[case] big_num_str: &str) {
929 let num: Number = serde_json::from_str(big_num_str).unwrap();
930
931 let input = Value::Number(num);
932 let expected = BigUint::parse_bytes(big_num_str.as_bytes(), 10);
933 assert_eq!(input.as_bytes(), expected);
934 }
935
936 #[rstest]
937 #[case(Value::String("123ms".into()), Some(123))]
938 #[case(Value::String("1.5s".into()), Some(1500))]
939 #[case(Value::String("1".into()), Some(1))]
940 #[case(Value::String("2m".into()), Some(120_000))]
941 #[case(Value::String("1.2h".into()), Some(4_320_000))]
942 #[case(Value::String("1d".into()), Some(86_400_000))]
943 #[case(Value::Number(Number::from_f64(2500.0).unwrap()), Some(2500))] #[case(Value::String("999us".into()), Some(0))] #[case(Value::Null, None)]
946 fn test_as_millis(#[case] v: Value, #[case] expected: Option<u128>) {
947 assert_eq!(v.as_millis(), expected);
948 }
949
950 #[rstest]
951 #[case(Value::String("2s".into()), Some(2))]
952 #[case(Value::String("1.5m".into()), Some(90))]
953 #[case(Value::String("0.5h".into()), Some(1800))]
954 #[case(Value::String("0.1d".into()), Some(8640))]
955 fn test_as_secs(#[case] v: Value, #[case] expected: Option<u64>) {
956 assert_eq!(v.as_secs(), expected);
957 }
958
959 #[rstest]
960 #[case(Value::String("1ns".into()), Some(1))]
961 #[case(Value::String("1us".into()), Some(1000))]
962 #[case(Value::String("1ms".into()), Some(1_000_000))]
963 #[case(Value::String("1s".into()), Some(1_000_000_000))]
964 #[case(Value::String("1m".into()), Some(60_000_000_000))]
965 fn test_as_nanos(#[case] v: Value, #[case] expected: Option<u128>) {
966 assert_eq!(v.as_nanos(), expected);
967 }
968
969 #[rstest]
970 #[case(Value::String("2s".into()), Some(2.0))]
971 #[case(Value::String("1.5s".into()), Some(1.5))]
972 #[case(Value::String("1.2m".into()), Some(72.0))]
973 fn test_as_secs_f32(#[case] v: Value, #[case] expected: Option<f32>) {
974 assert!((v.as_secs_f32().unwrap() - expected.unwrap()).abs() < f32::EPSILON);
975 }
976
977 #[rstest]
978 #[case(Value::String("2s".into()), Some(2.0))]
979 #[case(Value::String("1.5s".into()), Some(1.5))]
980 #[case(Value::String("1.2m".into()), Some(72.0))]
981 fn test_as_secs_f64(#[case] v: Value, #[case] expected: Option<f64>) {
982 assert!((v.as_secs_f64().unwrap() - expected.unwrap()).abs() < f64::EPSILON);
983 }
984
985 #[cfg(feature = "json_arbitrary_precision")]
986 #[rstest]
987 #[case("12300", Some(12300))]
988 #[case("1.2", Some(1))]
989 fn test_as_millis_arbitrary_precision(#[case] duration: &str, #[case] expected: Option<u128>) {
990 let num: Number = serde_json::from_str(duration).unwrap();
991
992 let input = Value::Number(num);
993 assert_eq!(input.as_millis(), expected);
994 }
995
996 fn obj(entries: Vec<(&str, Value)>) -> Value {
997 let mut map = HashMap::new();
998 for (k, v) in entries {
999 map.insert(k.to_string(), v);
1000 }
1001 Value::Object(map)
1002 }
1003
1004 #[rstest]
1005 #[case(Value::Array(vec![Value::String("a".into()), Value::String("b".into())]),
1006 Some(vec![Value::String("a".into()), Value::String("b".into())]))]
1007 #[case(obj(vec![("0", Value::String("x".into())),
1008 ("1", Value::String("y".into()))]),
1009 Some(vec![Value::String("x".into()), Value::String("y".into())]))]
1010 #[case(obj(vec![("0", Value::String("first".into())),
1011 ("2", Value::String("third".into())),
1012 ("1", Value::String("second".into()))]),
1013 Some(vec![Value::String("first".into()),
1014 Value::String("second".into()),
1015 Value::String("third".into())]))]
1016 #[case(obj(vec![("0", Value::String("ok".into())),
1017 ("foo", Value::String("ignored".into()))]),
1018 Some(vec![Value::String("ok".into())]))]
1019 #[case(Value::String("not an array or object".into()), None)]
1020 fn test_as_array_numerically(#[case] input: Value, #[case] expected: Option<Vec<Value>>) {
1021 let expected = expected.as_ref().map(|v| v.iter().collect::<Vec<_>>());
1022 let result = input.as_array_numerically();
1023 assert_eq!(result, expected);
1024 }
1025
1026 #[rstest]
1027 #[case(Value::Boolean(true), Some(true))]
1028 #[case(Value::Boolean(false), Some(false))]
1029 #[case(Value::String("true".into()), Some(true))]
1030 #[case(Value::String("on".into()), Some(true))]
1031 #[case(Value::String("yes".into()), Some(true))]
1032 #[case(Value::String("false".into()), Some(false))]
1033 #[case(Value::String("off".into()), Some(false))]
1034 #[case(Value::String("no".into()), Some(false))]
1035 #[case(Value::String("True".into()), None)] #[case(Value::String("1".into()), None)] #[case(Value::String("maybe".into()), None)] #[case(Value::Array(vec![]), None)] fn test_as_boolean(#[case] input: Value, #[case] expected: Option<bool>) {
1040 assert_eq!(input.as_boolean(), expected);
1041 }
1042
1043 #[rstest]
1044 #[case(Value::Null, true)]
1045 #[case(Value::String("null".into()), true)]
1046 #[case(Value::String("Null".into()), false)] #[case(Value::String("NULL".into()), false)]
1048 #[case(Value::Boolean(false), false)]
1049 #[case(Value::Array(vec![]), false)]
1050 #[case(Value::Object(Default::default()), false)]
1051 fn test_is_null(#[case] input: Value, #[case] expected: bool) {
1052 assert_eq!(input.is_null(), expected);
1053 }
1054
1055 #[rstest]
1056 #[case(
1058 obj(vec![("a", Value::String("keep".into()))]),
1059 obj(vec![("b", Value::String("fallback".into()))]),
1060 obj(vec![
1061 ("a", Value::String("keep".into())),
1062 ("b", Value::String("fallback".into()))
1063 ])
1064 )]
1065 #[case(
1067 obj(vec![("a", Value::String("self".into()))]),
1068 obj(vec![("a", Value::String("fallback".into()))]),
1069 obj(vec![("a", Value::String("self".into()))])
1070 )]
1071 #[case(
1073 obj(vec![("nested", obj(vec![("x", Value::String("1".into()))]))]),
1074 obj(vec![("nested", obj(vec![("y", Value::String("2".into()))]))]),
1075 obj(vec![("nested", obj(vec![
1076 ("x", Value::String("1".into())),
1077 ("y", Value::String("2".into()))
1078 ]))])
1079 )]
1080 #[case(Value::String("self".into()), obj(vec![("a", Value::String("fb".into()))]), Value::String("self".into()))]
1082 #[case(obj(vec![]), obj(vec![("z", Value::String("fb".into()))]), obj(vec![("z", Value::String("fb".into()))]))]
1084 #[case(
1086 obj(vec![("level1", obj(vec![
1087 ("level2", obj(vec![
1088 ("key1", Value::String("self".into()))
1089 ]))
1090 ]))]),
1091 obj(vec![("level1", obj(vec![
1092 ("level2", obj(vec![
1093 ("key2", Value::String("fallback".into()))
1094 ]))
1095 ]))]),
1096 obj(vec![("level1", obj(vec![
1097 ("level2", obj(vec![
1098 ("key1", Value::String("self".into())),
1099 ("key2", Value::String("fallback".into()))
1100 ]))
1101 ]))])
1102 )]
1103 #[case(
1105 obj(vec![("conflict", Value::String("primitive".into()))]),
1106 obj(vec![("conflict", obj(vec![("nested", Value::String("fb".into()))]))]),
1107 obj(vec![("conflict", Value::String("primitive".into()))])
1108 )]
1109 fn test_with_fallback(#[case] base: Value, #[case] fallback: Value, #[case] expected: Value) {
1110 let result = base.with_fallback(fallback);
1111 assert_eq!(result, expected);
1112 }
1113
1114 #[test]
1115 fn test_as_mut() {
1116 let mut object = HashMap::new();
1117 object.insert("hello".into(), Value::String("world".into()));
1118 let mut value = Value::Object(object);
1119 let object = value.as_object_mut().unwrap();
1120 object.insert("array".into(), Value::Array(vec![]));
1121 let array = object.get_mut("array").unwrap();
1122 let array = array.as_array_mut().unwrap();
1123 array.push(Value::Null);
1124 }
1125
1126 #[test]
1127 fn test_get_by_path_mut_stops_at_non_object() {
1128 let mut value = obj(vec![("leaf", Value::String("value".into()))]);
1129
1130 assert!(value.get_by_path_mut(["leaf", "child"]).is_none());
1131 }
1132
1133 #[test]
1134 fn test_into() {
1135 let value = Value::Object(HashMap::default());
1136 let _ = value.into_object().unwrap();
1137 let value = Value::Array(vec![]);
1138 let _ = value.into_array().unwrap();
1139 let value = Value::Number(1.into());
1140 let _ = value.into_number().unwrap();
1141 let value = Value::Boolean(false);
1142 let _ = value.into_boolean().unwrap();
1143 let value = Value::String("hello".into());
1144 let _ = value.into_string().unwrap();
1145 }
1146}