Skip to main content

hocon_rs/
value.rs

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    /// Attempts to interpret the current [`Value`] as an array by applying
90    /// HOCON's "numerically-indexed object to array" conversion rule.
91    ///
92    /// # Behavior
93    ///
94    /// - If the value is already an array (`Value::Array`), this simply
95    ///   returns a reference to its elements as a `Vec<&Value>`.
96    ///
97    /// - If the value is an object (`Value::Object`) whose keys are strings
98    ///   representing integers (e.g. `"0"`, `"1"`, `"2"`), it is converted
99    ///   into an array:
100    ///   - Keys are filtered to include only those that can be parsed as `usize`.
101    ///   - The key–value pairs are sorted by their numeric key.
102    ///   - The values are collected into a `Vec<&Value>` in ascending key order.
103    ///
104    /// - For any other kind of value, the function returns `None`.
105    ///
106    /// # Example
107    ///
108    /// ```hocon
109    /// {
110    ///   "0": "first",
111    ///   "2": "third",
112    ///   "1": "second"
113    /// }
114    /// ```
115    ///
116    /// Will be interpreted as:
117    ///
118    /// ```hocon
119    /// [ "first", "second", "third" ]
120    /// ```
121    pub fn as_array_numerically(&self) -> Option<Vec<&Value>> {
122        match self {
123            // Already an array → just return the elements.
124            Value::Array(array) => Some(array.iter().collect()),
125
126            // If it's an object, try to convert it to an array using numeric keys.
127            Value::Object(object) => {
128                // Keep only entries whose keys can be parsed as integers.
129                let mut object_array = object
130                    .iter()
131                    .filter(|(key, _)| key.parse::<usize>().is_ok())
132                    .collect::<Vec<_>>();
133
134                // Sort by numeric key so the order is consistent with array semantics.
135                object_array.sort_by(|a, b| a.0.cmp(b.0));
136
137                // Extract values in order, discarding the string keys.
138                let array = object_array
139                    .into_iter()
140                    .map(|(_, value)| value)
141                    .collect::<Vec<_>>();
142
143                Some(array)
144            }
145
146            // Not an array and not an object → cannot convert.
147            _ => None,
148        }
149    }
150
151    /// Attempts to interpret the current [`Value`] as a boolean, following
152    /// HOCON's relaxed truthy/falsey rules.
153    ///
154    /// # Behavior
155    ///
156    /// - If the value is a `Value::Boolean`, returns the inner `bool`.
157    ///
158    /// - If the value is a `Value::String`, accepts several textual
159    ///   representations:
160    ///   - `"true"`, `"on"`, `"yes"` → `Some(true)`
161    ///   - `"false"`, `"off"`, `"no"` → `Some(false)`
162    ///
163    /// - For all other values (numbers, arrays, objects, or strings that
164    ///   don't match the above), returns `None`.
165    ///
166    /// # Notes
167    /// - The matching is **case-sensitive** (`"True"` will not be recognized).
168    /// - This conversion is specific to HOCON and goes beyond JSON’s strict
169    ///   boolean representation.
170    pub fn as_boolean(&self) -> Option<bool> {
171        match self {
172            // Direct boolean value
173            Value::Boolean(boolean) => Some(*boolean),
174
175            // String representations of truthy values
176            Value::String(boolean) if boolean == "true" || boolean == "on" || boolean == "yes" => {
177                Some(true)
178            }
179
180            // String representations of falsey values
181            Value::String(boolean) if boolean == "false" || boolean == "off" || boolean == "no" => {
182                Some(false)
183            }
184
185            // Everything else → not interpretable as boolean
186            _ => 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    /// Checks whether the current [`Value`] represents `null` in HOCON.
238    ///
239    /// # Behavior
240    ///
241    /// - Returns `true` if the value is explicitly `Value::Null`.
242    /// - Returns `true` if the value is a `Value::String` equal to `"null"`.
243    /// - Otherwise, returns `false`.
244    ///
245    /// # Notes
246    /// - The check for `"null"` is **case-sensitive**. `"Null"` or `"NULL"`
247    ///   will not be considered null.
248    /// - This deviates from strict JSON, where only a literal `null` is valid.
249    ///   HOCON allows the string `"null"` to be treated as a null value.
250    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    /// Retrieves a value from a nested `Value::Object` by following a HOCON-style path.
305    ///
306    /// # Arguments
307    ///
308    /// * `paths` - A sequence of keys representing the path to the desired value.
309    ///   The path should already be split by `.` (dot).
310    ///
311    /// # Returns
312    ///
313    /// * `Some(&Value)` if the full path exists in the object tree.
314    /// * `None` if any key in the path does not exist or if a non-object value is encountered
315    ///   before reaching the end of the path.
316    ///
317    /// # Example
318    ///
319    /// ```text
320    /// // Assuming the following HOCON-like structure:
321    /// // {
322    /// //   database: {
323    /// //     connection: {
324    /// //       timeout: 30
325    /// //     }
326    /// //   }
327    /// // }
328    ///
329    /// let val = root.get_by_path(&["database", "connection", "timeout"]);
330    /// assert_eq!(val, Some(&hocon_rs::Value::Number(30.into())));
331    /// ```
332    pub fn get_by_path<'a>(&self, paths: impl AsRef<[&'a str]>) -> Option<&Value> {
333        let paths = paths.as_ref();
334
335        // An empty path cannot resolve to a value
336        if paths.is_empty() {
337            return None;
338        }
339
340        // Start traversal from the current value
341        let mut current = self;
342
343        // Traverse the object tree step by step
344        for &path in paths {
345            current = match current {
346                Value::Object(obj) => obj.get(path)?,
347                // Current value is not an object, so the path cannot continue
348                _ => 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    /// Merge this `Value` with a fallback `Value`, following HOCON's `withFallback` semantics.
371    ///
372    /// - If both `self` and `fallback` are `Object`s, they are merged key by key:
373    ///   - If a key exists in both objects:
374    ///     - If both values are objects, merge them recursively.
375    ///     - Otherwise, keep the value from `self` (ignore the fallback).
376    ///   - If a key exists only in the fallback, insert it into `self`.
377    /// - For all other cases (non-object values), `self` takes precedence
378    ///   and the fallback is ignored.
379    pub fn with_fallback(self, fallback: Value) -> Value {
380        match (self, fallback) {
381            // Case 1: Both values are objects -> perform deep merge
382            (Value::Object(mut obj), Value::Object(fb_obj)) => {
383                for (k, fb_val) in fb_obj {
384                    match obj.entry(k) {
385                        // If key already exists in `self`
386                        Entry::Occupied(mut occupied_entry) => {
387                            let existing_val = occupied_entry.get_mut();
388
389                            // If both values are objects -> merge recursively
390                            if let (Value::Object(_), Value::Object(_)) = (&existing_val, &fb_val) {
391                                // Temporarily move out the existing value to avoid borrow conflicts
392                                let mut temp = Value::Null;
393                                std::mem::swap(&mut temp, existing_val);
394
395                                // Recursively merge and store back
396                                *existing_val = temp.with_fallback(fb_val);
397                            }
398                            // Otherwise: keep `self`'s value, ignore fallback
399                        }
400
401                        // If key is missing in `self` -> insert fallback value
402                        Entry::Vacant(vacant_entry) => {
403                            vacant_entry.insert(fb_val);
404                        }
405                    }
406                }
407                Value::Object(obj)
408            }
409
410            // Case 2: Non-object values -> always prefer `self`
411            (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)))] // 测试小数
802    #[case(Value::String("0.5MiB".into()), Some(BigUint::from(512u32 * 1024)))] // 小数二进制单位
803    #[case(Value::String("999999999YB".into()), Some(BigUint::from(999_999_999u128) * BigUint::from(10u128).pow(24)
804    ))] // 巨大 SI 单位
805    #[case(Value::String("999999999YiB".into()), Some(BigUint::from(999_999_999u128) * (BigUint::from(2u32).pow(80))
806    ))] // 巨大二进制单位
807    #[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))] // 2500ms
944    #[case(Value::String("999us".into()), Some(0))] // <1ms 舍入为 0 毫秒
945    #[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-sensitive
1036    #[case(Value::String("1".into()), None)] // not accepted
1037    #[case(Value::String("maybe".into()), None)] // invalid
1038    #[case(Value::Array(vec![]), None)] // wrong type
1039    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-sensitive
1047    #[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 1: Simple fallback
1057    #[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 2: Conflict on primitive key -> self wins
1066    #[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 3: Nested objects -> deep merge
1072    #[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 4: Self is non-object -> fallback ignored
1081    #[case(Value::String("self".into()), obj(vec![("a", Value::String("fb".into()))]), Value::String("self".into()))]
1082    // Case 5: Empty object -> fallback copied over
1083    #[case(obj(vec![]), obj(vec![("z", Value::String("fb".into()))]), obj(vec![("z", Value::String("fb".into()))]))]
1084    // Case 6: Multi-level nested merge
1085    #[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 7: Primitive in self vs. object in fallback -> self wins
1104    #[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}