hocon_rs/
value.rs

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    /// Attempts to interpret the current [`Value`] as an array by applying
76    /// HOCON's "numerically-indexed object to array" conversion rule.
77    ///
78    /// # Behavior
79    ///
80    /// - If the value is already an array (`Value::Array`), this simply
81    ///   returns a reference to its elements as a `Vec<&Value>`.
82    ///
83    /// - If the value is an object (`Value::Object`) whose keys are strings
84    ///   representing integers (e.g. `"0"`, `"1"`, `"2"`), it is converted
85    ///   into an array:
86    ///   - Keys are filtered to include only those that can be parsed as `usize`.
87    ///   - The key–value pairs are sorted by their numeric key.
88    ///   - The values are collected into a `Vec<&Value>` in ascending key order.
89    ///
90    /// - For any other kind of value, the function returns `None`.
91    ///
92    /// # Example
93    ///
94    /// ```hocon
95    /// {
96    ///   "0": "first",
97    ///   "2": "third",
98    ///   "1": "second"
99    /// }
100    /// ```
101    ///
102    /// Will be interpreted as:
103    ///
104    /// ```hocon
105    /// [ "first", "second", "third" ]
106    /// ```
107    pub fn as_array_numerically(&self) -> Option<Vec<&Value>> {
108        match self {
109            // Already an array → just return the elements.
110            Value::Array(array) => Some(array.iter().collect()),
111
112            // If it's an object, try to convert it to an array using numeric keys.
113            Value::Object(object) => {
114                // Keep only entries whose keys can be parsed as integers.
115                let mut object_array = object
116                    .iter()
117                    .filter(|(key, _)| key.parse::<usize>().is_ok())
118                    .collect::<Vec<_>>();
119
120                // Sort by numeric key so the order is consistent with array semantics.
121                object_array.sort_by(|a, b| a.0.cmp(b.0));
122
123                // Extract values in order, discarding the string keys.
124                let array = object_array
125                    .into_iter()
126                    .map(|(_, value)| value)
127                    .collect::<Vec<_>>();
128
129                Some(array)
130            }
131
132            // Not an array and not an object → cannot convert.
133            _ => None,
134        }
135    }
136
137    /// Attempts to interpret the current [`Value`] as a boolean, following
138    /// HOCON's relaxed truthy/falsey rules.
139    ///
140    /// # Behavior
141    ///
142    /// - If the value is a `Value::Boolean`, returns the inner `bool`.
143    ///
144    /// - If the value is a `Value::String`, accepts several textual
145    ///   representations:
146    ///   - `"true"`, `"on"`, `"yes"` → `Some(true)`
147    ///   - `"false"`, `"off"`, `"no"` → `Some(false)`
148    ///
149    /// - For all other values (numbers, arrays, objects, or strings that
150    ///   don't match the above), returns `None`.
151    ///
152    /// # Notes
153    /// - The matching is **case-sensitive** (`"True"` will not be recognized).
154    /// - This conversion is specific to HOCON and goes beyond JSON’s strict
155    ///   boolean representation.
156    pub fn as_boolean(&self) -> Option<bool> {
157        match self {
158            // Direct boolean value
159            Value::Boolean(boolean) => Some(*boolean),
160
161            // String representations of truthy values
162            Value::String(boolean) if boolean == "true" || boolean == "on" || boolean == "yes" => {
163                Some(true)
164            }
165
166            // String representations of falsey values
167            Value::String(boolean) if boolean == "false" || boolean == "off" || boolean == "no" => {
168                Some(false)
169            }
170
171            // Everything else → not interpretable as boolean
172            _ => 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    /// Checks whether the current [`Value`] represents `null` in HOCON.
224    ///
225    /// # Behavior
226    ///
227    /// - Returns `true` if the value is explicitly `Value::Null`.
228    /// - Returns `true` if the value is a `Value::String` equal to `"null"`.
229    /// - Otherwise, returns `false`.
230    ///
231    /// # Notes
232    /// - The check for `"null"` is **case-sensitive**. `"Null"` or `"NULL"`
233    ///   will not be considered null.
234    /// - This deviates from strict JSON, where only a literal `null` is valid.
235    ///   HOCON allows the string `"null"` to be treated as a null value.
236    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    /// Retrieves a value from a nested `Value::Object` by following a HOCON-style path.
291    ///
292    /// # Arguments
293    ///
294    /// * `paths` - A sequence of keys representing the path to the desired value.
295    ///   The path should already be split by `.` (dot).
296    ///
297    /// # Returns
298    ///
299    /// * `Some(&Value)` if the full path exists in the object tree.
300    /// * `None` if any key in the path does not exist or if a non-object value is encountered
301    ///   before reaching the end of the path.
302    ///
303    /// # Example
304    ///
305    /// ```text
306    /// // Assuming the following HOCON-like structure:
307    /// // {
308    /// //   database: {
309    /// //     connection: {
310    /// //       timeout: 30
311    /// //     }
312    /// //   }
313    /// // }
314    ///
315    /// let val = root.get_by_path(&["database", "connection", "timeout"]);
316    /// assert_eq!(val, Some(&hocon_rs::Value::Number(30.into())));
317    /// ```
318    pub fn get_by_path<'a>(&self, paths: impl AsRef<[&'a str]>) -> Option<&Value> {
319        let paths = paths.as_ref();
320
321        // An empty path cannot resolve to a value
322        if paths.is_empty() {
323            return None;
324        }
325
326        // Start traversal from the current value
327        let mut current = self;
328
329        // Traverse the object tree step by step
330        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                    // Key not found in the current object
336                    return None;
337                }
338            } else {
339                // Current value is not an object, so the path cannot continue
340                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    /// Merge this `Value` with a fallback `Value`, following HOCON's `withFallback` semantics.
366    ///
367    /// - If both `self` and `fallback` are `Object`s, they are merged key by key:
368    ///   - If a key exists in both objects:
369    ///     - If both values are objects, merge them recursively.
370    ///     - Otherwise, keep the value from `self` (ignore the fallback).
371    ///   - If a key exists only in the fallback, insert it into `self`.
372    /// - For all other cases (non-object values), `self` takes precedence
373    ///   and the fallback is ignored.
374    pub fn with_fallback(self, fallback: Value) -> Value {
375        match (self, fallback) {
376            // Case 1: Both values are objects -> perform deep merge
377            (Value::Object(mut obj), Value::Object(fb_obj)) => {
378                for (k, fb_val) in fb_obj {
379                    match obj.entry(k) {
380                        // If key already exists in `self`
381                        Entry::Occupied(mut occupied_entry) => {
382                            let existing_val = occupied_entry.get_mut();
383
384                            // If both values are objects -> merge recursively
385                            if let (Value::Object(_), Value::Object(_)) = (&existing_val, &fb_val) {
386                                // Temporarily move out the existing value to avoid borrow conflicts
387                                let mut temp = Value::Null;
388                                std::mem::swap(&mut temp, existing_val);
389
390                                // Recursively merge and store back
391                                *existing_val = temp.with_fallback(fb_val);
392                            }
393                            // Otherwise: keep `self`'s value, ignore fallback
394                        }
395
396                        // If key is missing in `self` -> insert fallback value
397                        Entry::Vacant(vacant_entry) => {
398                            vacant_entry.insert(fb_val);
399                        }
400                    }
401                }
402                Value::Object(obj)
403            }
404
405            // Case 2: Non-object values -> always prefer `self`
406            (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)))] // 测试小数
795    #[case(Value::String("0.5MiB".into()), Some(BigUint::from(512u32 * 1024)))] // 小数二进制单位
796    #[case(Value::String("999999999YB".into()), Some(BigUint::from(999_999_999u128) * BigUint::from(10u128).pow(24)
797    ))] // 巨大 SI 单位
798    #[case(Value::String("999999999YiB".into()), Some(BigUint::from(999_999_999u128) * (BigUint::from(2u32).pow(80))
799    ))] // 巨大二进制单位
800    #[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))] // 2500ms
937    #[case(Value::String("999us".into()), Some(0))] // <1ms 舍入为 0 毫秒
938    #[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-sensitive
1029    #[case(Value::String("1".into()), None)] // not accepted
1030    #[case(Value::String("maybe".into()), None)] // invalid
1031    #[case(Value::Array(vec![]), None)] // wrong type
1032    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-sensitive
1040    #[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 1: Simple fallback
1050    #[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 2: Conflict on primitive key -> self wins
1059    #[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 3: Nested objects -> deep merge
1065    #[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 4: Self is non-object -> fallback ignored
1074    #[case(Value::String("self".into()), obj(vec![("a", Value::String("fb".into()))]), Value::String("self".into()))]
1075    // Case 5: Empty object -> fallback copied over
1076    #[case(obj(vec![]), obj(vec![("z", Value::String("fb".into()))]), obj(vec![("z", Value::String("fb".into()))]))]
1077    // Case 6: Multi-level nested merge
1078    #[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 7: Primitive in self vs. object in fallback -> self wins
1097    #[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}