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