Skip to main content

buffa_types/
value_ext.rs

1//! Ergonomic helpers for [`google::protobuf::Value`](crate::google::protobuf::Value),
2//! [`google::protobuf::Struct`](crate::google::protobuf::Struct), and
3//! [`google::protobuf::ListValue`](crate::google::protobuf::ListValue).
4
5use alloc::boxed::Box;
6use alloc::string::{String, ToString};
7
8use crate::google::protobuf::__buffa::oneof::value::Kind as KindOneof;
9use crate::google::protobuf::{ListValue, NullValue, Struct, Value};
10
11impl Value {
12    /// Construct a [`Value`] that represents a protobuf `null`.
13    pub fn null() -> Self {
14        Self {
15            kind: Some(KindOneof::NullValue(buffa::EnumValue::from(
16                NullValue::NULL_VALUE,
17            ))),
18            ..Default::default()
19        }
20    }
21
22    /// Returns `true` if this value is the null variant.
23    pub fn is_null(&self) -> bool {
24        matches!(self.kind, Some(KindOneof::NullValue(_)))
25    }
26
27    /// Returns the `f64` value if this is a number, otherwise `None`.
28    pub fn as_number(&self) -> Option<f64> {
29        match &self.kind {
30            Some(KindOneof::NumberValue(n)) => Some(*n),
31            _ => None,
32        }
33    }
34
35    /// Returns the string value if this is a string, otherwise `None`.
36    pub fn as_str(&self) -> Option<&str> {
37        match &self.kind {
38            Some(KindOneof::StringValue(s)) => Some(s.as_str()),
39            _ => None,
40        }
41    }
42
43    /// Returns the bool value if this is a bool, otherwise `None`.
44    pub fn as_bool(&self) -> Option<bool> {
45        match &self.kind {
46            Some(KindOneof::BoolValue(b)) => Some(*b),
47            _ => None,
48        }
49    }
50
51    /// Returns a reference to the [`Struct`] if this is a struct value.
52    pub fn as_struct(&self) -> Option<&Struct> {
53        match &self.kind {
54            Some(KindOneof::StructValue(s)) => Some(s),
55            _ => None,
56        }
57    }
58
59    /// Returns a reference to the [`ListValue`] if this is a list value.
60    pub fn as_list(&self) -> Option<&ListValue> {
61        match &self.kind {
62            Some(KindOneof::ListValue(l)) => Some(l),
63            _ => None,
64        }
65    }
66
67    /// Returns a mutable reference to the [`Struct`] if this is a struct value.
68    pub fn as_struct_mut(&mut self) -> Option<&mut Struct> {
69        match &mut self.kind {
70            Some(KindOneof::StructValue(s)) => Some(s),
71            _ => None,
72        }
73    }
74
75    /// Returns a mutable reference to the [`ListValue`] if this is a list value.
76    pub fn as_list_mut(&mut self) -> Option<&mut ListValue> {
77        match &mut self.kind {
78            Some(KindOneof::ListValue(l)) => Some(l),
79            _ => None,
80        }
81    }
82}
83
84impl From<f64> for Value {
85    fn from(n: f64) -> Self {
86        Self {
87            kind: Some(KindOneof::NumberValue(n)),
88            ..Default::default()
89        }
90    }
91}
92
93impl From<String> for Value {
94    fn from(s: String) -> Self {
95        Self {
96            kind: Some(KindOneof::StringValue(s)),
97            ..Default::default()
98        }
99    }
100}
101
102impl From<&str> for Value {
103    fn from(s: &str) -> Self {
104        Self {
105            kind: Some(KindOneof::StringValue(s.to_string())),
106            ..Default::default()
107        }
108    }
109}
110
111impl From<f32> for Value {
112    /// Converts an `f32` to a [`Value`] via `f64` widening.
113    ///
114    /// The conversion is lossless for values representable as both `f32` and
115    /// `f64`; the extra precision bits are filled with zeros.
116    fn from(n: f32) -> Self {
117        Self::from(n as f64)
118    }
119}
120
121impl From<bool> for Value {
122    fn from(b: bool) -> Self {
123        Self {
124            kind: Some(KindOneof::BoolValue(b)),
125            ..Default::default()
126        }
127    }
128}
129
130impl From<i32> for Value {
131    /// Converts an `i32` to a [`Value`] via `f64`.
132    ///
133    /// All `i32` values are representable exactly as `f64`.
134    fn from(n: i32) -> Self {
135        Self::from(n as f64)
136    }
137}
138
139impl From<u32> for Value {
140    /// Converts a `u32` to a [`Value`] via `f64`.
141    ///
142    /// All `u32` values are representable exactly as `f64`.
143    fn from(n: u32) -> Self {
144        Self::from(n as f64)
145    }
146}
147
148impl From<i64> for Value {
149    /// Converts an `i64` to a [`Value`] via `f64`.
150    ///
151    /// # Precision
152    ///
153    /// `f64` has 53 bits of mantissa. `i64` values outside `[-2^53, 2^53]`
154    /// will be rounded to the nearest representable `f64`.
155    fn from(n: i64) -> Self {
156        Self::from(n as f64)
157    }
158}
159
160impl From<u64> for Value {
161    /// Converts a `u64` to a [`Value`] via `f64`.
162    ///
163    /// # Precision
164    ///
165    /// `f64` has 53 bits of mantissa. `u64` values greater than `2^53`
166    /// will be rounded to the nearest representable `f64`.
167    fn from(n: u64) -> Self {
168        Self::from(n as f64)
169    }
170}
171
172impl From<Struct> for Value {
173    fn from(s: Struct) -> Self {
174        Self {
175            kind: Some(KindOneof::StructValue(Box::new(s))),
176            ..Default::default()
177        }
178    }
179}
180
181impl From<ListValue> for Value {
182    fn from(l: ListValue) -> Self {
183        Self {
184            kind: Some(KindOneof::ListValue(Box::new(l))),
185            ..Default::default()
186        }
187    }
188}
189
190impl ListValue {
191    /// Construct a [`ListValue`] from an iterator of items convertible to [`Value`].
192    pub fn from_values(values: impl IntoIterator<Item = impl Into<Value>>) -> Self {
193        Self {
194            values: values.into_iter().map(Into::into).collect(),
195            ..Default::default()
196        }
197    }
198
199    /// Returns the number of elements in the list.
200    #[inline]
201    pub fn len(&self) -> usize {
202        self.values.len()
203    }
204
205    /// Returns `true` if the list contains no elements.
206    #[inline]
207    pub fn is_empty(&self) -> bool {
208        self.values.is_empty()
209    }
210
211    /// Returns an iterator over the values in the list.
212    #[inline]
213    pub fn iter(&self) -> core::slice::Iter<'_, Value> {
214        self.values.iter()
215    }
216}
217
218impl<'a> IntoIterator for &'a ListValue {
219    type Item = &'a Value;
220    type IntoIter = core::slice::Iter<'a, Value>;
221
222    fn into_iter(self) -> Self::IntoIter {
223        self.values.iter()
224    }
225}
226
227impl IntoIterator for ListValue {
228    type Item = Value;
229    type IntoIter = alloc::vec::IntoIter<Value>;
230
231    fn into_iter(self) -> Self::IntoIter {
232        self.values.into_iter()
233    }
234}
235
236impl FromIterator<Value> for ListValue {
237    /// Collect [`Value`] items into a [`ListValue`].
238    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
239        Self {
240            values: iter.into_iter().collect(),
241            ..Default::default()
242        }
243    }
244}
245
246impl Struct {
247    /// Construct a new empty [`Struct`].
248    pub fn new() -> Self {
249        Self::default()
250    }
251
252    /// Construct a [`Struct`] from an iterator of key-value pairs.
253    ///
254    /// # Example
255    ///
256    /// ```rust
257    /// use buffa_types::google::protobuf::{Struct, Value};
258    ///
259    /// let s = Struct::from_fields([("x", Value::from(1.0_f64)), ("y", Value::from(2.0_f64))]);
260    /// assert!(s.get("x").is_some());
261    /// ```
262    pub fn from_fields(
263        fields: impl IntoIterator<Item = (impl Into<String>, impl Into<Value>)>,
264    ) -> Self {
265        let mut s = Self::new();
266        for (k, v) in fields {
267            s.insert(k, v);
268        }
269        s
270    }
271
272    /// Insert a key-value pair into the struct.
273    pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
274        self.fields.insert(key.into(), value.into());
275    }
276
277    /// Returns the value for `key` if present.
278    pub fn get(&self, key: &str) -> Option<&Value> {
279        self.fields.get(key)
280    }
281}
282
283impl FromIterator<(String, Value)> for Struct {
284    /// Collect key-value pairs into a [`Struct`].
285    fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
286        Self::from_fields(iter)
287    }
288}
289
290// ── serde impls ─────────────────────────────────────────────────────────────
291
292#[cfg(feature = "json")]
293use alloc::vec::Vec;
294
295#[cfg(feature = "json")]
296impl serde::Serialize for Value {
297    /// Serializes as the corresponding JSON value.
298    ///
299    /// The `null`, bool, string, object, and array variants map directly to
300    /// their JSON counterparts.  The `number` variant serializes as a JSON
301    /// number via `serialize_f64`.
302    ///
303    /// # Errors
304    ///
305    /// Serialization fails if the `number` variant holds a non-finite value
306    /// (`NaN`, `Infinity`, `-Infinity`), because JSON numbers cannot represent
307    /// those values.  Use [`DoubleValue`](crate::google::protobuf::DoubleValue) if you need to
308    /// serialize non-finite floating-point values (which uses the proto3 JSON
309    /// string encoding `"NaN"` / `"Infinity"` / `"-Infinity"`).
310    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
311        match &self.kind {
312            None | Some(KindOneof::NullValue(_)) => s.serialize_unit(),
313            Some(KindOneof::NumberValue(n)) => {
314                if !n.is_finite() {
315                    return Err(serde::ser::Error::custom(
316                        "Value.number_value must be finite; NaN and Infinity are not valid JSON numbers",
317                    ));
318                }
319                s.serialize_f64(*n)
320            }
321            Some(KindOneof::StringValue(v)) => s.serialize_str(v),
322            Some(KindOneof::BoolValue(b)) => s.serialize_bool(*b),
323            Some(KindOneof::StructValue(st)) => st.serialize(s),
324            Some(KindOneof::ListValue(l)) => l.serialize(s),
325        }
326    }
327}
328
329#[cfg(feature = "json")]
330impl<'de> serde::Deserialize<'de> for Value {
331    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
332        use serde::de::{MapAccess, SeqAccess, Visitor};
333        struct V;
334        impl<'de> Visitor<'de> for V {
335            type Value = Value;
336            fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
337                f.write_str("any JSON value")
338            }
339            fn visit_unit<E>(self) -> Result<Value, E> {
340                Ok(Value::null())
341            }
342            fn visit_none<E>(self) -> Result<Value, E> {
343                Ok(Value::null())
344            }
345            fn visit_bool<E>(self, v: bool) -> Result<Value, E> {
346                Ok(Value::from(v))
347            }
348            fn visit_f64<E>(self, v: f64) -> Result<Value, E> {
349                Ok(Value::from(v))
350            }
351            fn visit_i64<E>(self, v: i64) -> Result<Value, E> {
352                Ok(Value::from(v as f64))
353            }
354            fn visit_u64<E>(self, v: u64) -> Result<Value, E> {
355                Ok(Value::from(v as f64))
356            }
357            fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Value, E> {
358                Ok(Value::from(v))
359            }
360            fn visit_string<E>(self, v: String) -> Result<Value, E> {
361                Ok(Value::from(v))
362            }
363            fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Value, A::Error> {
364                let mut st = Struct::default();
365                while let Some((k, v)) = map.next_entry::<String, Value>()? {
366                    st.fields.insert(k, v);
367                }
368                Ok(Value::from(st))
369            }
370            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value, A::Error> {
371                let mut values = Vec::new();
372                while let Some(v) = seq.next_element::<Value>()? {
373                    values.push(v);
374                }
375                Ok(Value::from(ListValue {
376                    values,
377                    ..Default::default()
378                }))
379            }
380        }
381        d.deserialize_any(V)
382    }
383}
384
385#[cfg(feature = "json")]
386impl serde::Serialize for Struct {
387    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
388        use serde::ser::SerializeMap;
389        let mut map = s.serialize_map(Some(self.fields.len()))?;
390        for (k, v) in &self.fields {
391            map.serialize_entry(k, v)?;
392        }
393        map.end()
394    }
395}
396
397#[cfg(feature = "json")]
398impl<'de> serde::Deserialize<'de> for Struct {
399    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
400        use serde::de::{MapAccess, Visitor};
401        struct V;
402        impl<'de> Visitor<'de> for V {
403            type Value = Struct;
404            fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
405                f.write_str("a JSON object")
406            }
407            fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Struct, A::Error> {
408                let mut st = Struct::default();
409                while let Some((k, v)) = map.next_entry::<String, Value>()? {
410                    st.fields.insert(k, v);
411                }
412                Ok(st)
413            }
414        }
415        d.deserialize_map(V)
416    }
417}
418
419#[cfg(feature = "json")]
420impl serde::Serialize for ListValue {
421    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
422        use serde::ser::SerializeSeq;
423        let mut seq = s.serialize_seq(Some(self.values.len()))?;
424        for v in &self.values {
425            seq.serialize_element(v)?;
426        }
427        seq.end()
428    }
429}
430
431#[cfg(feature = "json")]
432impl<'de> serde::Deserialize<'de> for ListValue {
433    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
434        use serde::de::{SeqAccess, Visitor};
435        struct V;
436        impl<'de> Visitor<'de> for V {
437            type Value = ListValue;
438            fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
439                f.write_str("a JSON array")
440            }
441            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<ListValue, A::Error> {
442                let mut values = Vec::new();
443                while let Some(v) = seq.next_element::<Value>()? {
444                    values.push(v);
445                }
446                Ok(ListValue {
447                    values,
448                    ..Default::default()
449                })
450            }
451        }
452        d.deserialize_seq(V)
453    }
454}
455
456#[cfg(test)]
457mod tests {
458    use super::*;
459
460    #[test]
461    fn value_null() {
462        let v = Value::null();
463        assert!(v.is_null());
464    }
465
466    #[test]
467    fn value_from_f64() {
468        let v = Value::from(2.5_f64);
469        assert_eq!(v.as_number(), Some(2.5));
470    }
471
472    #[test]
473    fn value_from_string() {
474        let v = Value::from("hello".to_string());
475        assert_eq!(v.as_str(), Some("hello"));
476    }
477
478    #[test]
479    fn value_from_str_ref() {
480        let v = Value::from("world");
481        assert_eq!(v.as_str(), Some("world"));
482    }
483
484    #[test]
485    fn value_from_bool() {
486        assert_eq!(Value::from(true).as_bool(), Some(true));
487        assert_eq!(Value::from(false).as_bool(), Some(false));
488    }
489
490    #[test]
491    fn value_from_struct() {
492        let mut s = Struct::new();
493        s.insert("x", 1.0_f64);
494        let v = Value::from(s);
495        assert!(v.as_struct().is_some());
496    }
497
498    #[test]
499    fn value_from_list() {
500        let l = ListValue::from_values([1.0_f64, 2.0, 3.0]);
501        let v = Value::from(l);
502        assert!(v.as_list().is_some());
503        assert_eq!(v.as_list().unwrap().values.len(), 3);
504    }
505
506    #[test]
507    fn struct_insert_get() {
508        let mut s = Struct::new();
509        s.insert("key", "value");
510        assert_eq!(s.get("key").and_then(|v| v.as_str()), Some("value"));
511        assert!(s.get("missing").is_none());
512    }
513
514    #[test]
515    fn struct_from_fields() {
516        let s = Struct::from_fields([("a", Value::from(1.0_f64)), ("b", Value::from(2.0_f64))]);
517        assert_eq!(s.get("a").and_then(|v| v.as_number()), Some(1.0));
518        assert_eq!(s.get("b").and_then(|v| v.as_number()), Some(2.0));
519    }
520
521    #[test]
522    fn struct_from_fields_empty() {
523        let s = Struct::from_fields(core::iter::empty::<(&str, Value)>());
524        assert!(s.fields.is_empty());
525    }
526
527    #[test]
528    fn struct_from_iter() {
529        let pairs = vec![
530            ("x".to_string(), Value::from("hello")),
531            ("y".to_string(), Value::from(true)),
532        ];
533        let s: Struct = pairs.into_iter().collect();
534        assert_eq!(s.get("x").and_then(|v| v.as_str()), Some("hello"));
535        assert_eq!(s.get("y").and_then(|v| v.as_bool()), Some(true));
536    }
537
538    #[test]
539    fn list_value_from_values() {
540        let l = ListValue::from_values(["a", "b", "c"]);
541        assert_eq!(l.values.len(), 3);
542    }
543
544    // ---- From<f32> --------------------------------------------------------
545
546    #[test]
547    fn value_from_f32() {
548        let v = Value::from(1.5_f32);
549        assert_eq!(v.as_number(), Some(1.5_f64));
550    }
551
552    // ---- ListValue collection methods ------------------------------------
553
554    #[test]
555    fn list_value_len_and_is_empty() {
556        let empty = ListValue::from_values(core::iter::empty::<f64>());
557        assert!(empty.is_empty());
558        assert_eq!(empty.len(), 0);
559
560        let three = ListValue::from_values([1.0_f64, 2.0, 3.0]);
561        assert!(!three.is_empty());
562        assert_eq!(three.len(), 3);
563    }
564
565    #[test]
566    fn list_value_iter() {
567        let l = ListValue::from_values([1.0_f64, 2.0]);
568        let nums: Vec<f64> = l.iter().map(|v| v.as_number().unwrap()).collect();
569        assert_eq!(nums, [1.0, 2.0]);
570    }
571
572    #[test]
573    fn list_value_ref_into_iter() {
574        let l = ListValue::from_values(["a", "b"]);
575        let strs: Vec<&str> = (&l).into_iter().map(|v| v.as_str().unwrap()).collect();
576        assert_eq!(strs, ["a", "b"]);
577    }
578
579    #[test]
580    fn list_value_owned_into_iter() {
581        let l = ListValue::from_values([true, false]);
582        let bools: Vec<bool> = l.into_iter().map(|v| v.as_bool().unwrap()).collect();
583        assert_eq!(bools, [true, false]);
584    }
585
586    // ---- From<integer> ----------------------------------------------------
587
588    #[test]
589    fn value_from_i32() {
590        let v = Value::from(42_i32);
591        assert_eq!(v.as_number(), Some(42.0));
592    }
593
594    #[test]
595    fn value_from_u32() {
596        let v = Value::from(u32::MAX);
597        assert_eq!(v.as_number(), Some(u32::MAX as f64));
598    }
599
600    #[test]
601    fn value_from_i64_small() {
602        // Small i64 values are representable exactly as f64.
603        let v = Value::from(-100_i64);
604        assert_eq!(v.as_number(), Some(-100.0));
605    }
606
607    #[test]
608    fn value_from_u64_small() {
609        let v = Value::from(1_000_000_u64);
610        assert_eq!(v.as_number(), Some(1_000_000.0));
611    }
612
613    // ---- mutable accessors ------------------------------------------------
614
615    #[test]
616    fn as_struct_mut_returns_some_for_struct_value() {
617        let mut s = Struct::new();
618        s.insert("a", 1.0_f64);
619        let mut v = Value::from(s);
620        let m = v.as_struct_mut().unwrap();
621        m.insert("b", 2.0_f64);
622        assert_eq!(v.as_struct().unwrap().fields.len(), 2);
623    }
624
625    #[test]
626    fn as_struct_mut_returns_none_for_non_struct() {
627        let mut v = Value::from(1.0_f64);
628        assert!(v.as_struct_mut().is_none());
629    }
630
631    #[test]
632    fn as_list_mut_returns_some_for_list_value() {
633        let l = ListValue::from_values([1.0_f64]);
634        let mut v = Value::from(l);
635        let m = v.as_list_mut().unwrap();
636        m.values.push(Value::from(2.0_f64));
637        assert_eq!(v.as_list().unwrap().values.len(), 2);
638    }
639
640    #[test]
641    fn as_list_mut_returns_none_for_non_list() {
642        let mut v = Value::from(true);
643        assert!(v.as_list_mut().is_none());
644    }
645
646    // ── serde ───────────────────────────────────────────────────────────────
647
648    #[cfg(feature = "json")]
649    mod serde_tests {
650        use super::*;
651
652        #[test]
653        fn value_null_roundtrip() {
654            let v = Value::null();
655            let json = serde_json::to_string(&v).unwrap();
656            assert_eq!(json, "null");
657            let back: Value = serde_json::from_str(&json).unwrap();
658            assert!(back.is_null());
659        }
660
661        #[test]
662        fn value_number_roundtrip() {
663            let v = Value::from(2.5_f64);
664            let json = serde_json::to_string(&v).unwrap();
665            let back: Value = serde_json::from_str(&json).unwrap();
666            assert!((back.as_number().unwrap() - 2.5).abs() < 1e-10);
667        }
668
669        #[test]
670        fn value_string_roundtrip() {
671            let v = Value::from("hello");
672            let json = serde_json::to_string(&v).unwrap();
673            assert_eq!(json, r#""hello""#);
674            let back: Value = serde_json::from_str(&json).unwrap();
675            assert_eq!(back.as_str(), Some("hello"));
676        }
677
678        #[test]
679        fn value_bool_roundtrip() {
680            let v = Value::from(true);
681            let json = serde_json::to_string(&v).unwrap();
682            assert_eq!(json, "true");
683            let back: Value = serde_json::from_str(&json).unwrap();
684            assert_eq!(back.as_bool(), Some(true));
685        }
686
687        #[test]
688        fn struct_value_roundtrip() {
689            let s = Struct::from_fields([("x", Value::from(1.0_f64))]);
690            let v = Value::from(s);
691            let json = serde_json::to_string(&v).unwrap();
692            assert_eq!(json, r#"{"x":1.0}"#);
693            let back: Value = serde_json::from_str(&json).unwrap();
694            assert!(back.as_struct().is_some());
695            assert_eq!(
696                back.as_struct()
697                    .unwrap()
698                    .get("x")
699                    .and_then(|v| v.as_number()),
700                Some(1.0)
701            );
702        }
703
704        #[test]
705        fn list_value_roundtrip() {
706            let l = ListValue::from_values([1.0_f64, 2.0]);
707            let v = Value::from(l);
708            let json = serde_json::to_string(&v).unwrap();
709            assert_eq!(json, "[1.0,2.0]");
710            let back: Value = serde_json::from_str(&json).unwrap();
711            assert_eq!(back.as_list().unwrap().values.len(), 2);
712        }
713
714        #[test]
715        fn struct_roundtrip() {
716            let s = Struct::from_fields([("a", Value::from("b"))]);
717            let json = serde_json::to_string(&s).unwrap();
718            let back: Struct = serde_json::from_str(&json).unwrap();
719            assert_eq!(back.get("a").and_then(|v| v.as_str()), Some("b"));
720        }
721
722        #[test]
723        fn value_nan_serialize_is_error() {
724            let v = Value::from(f64::NAN);
725            let result = serde_json::to_string(&v);
726            assert!(result.is_err(), "NaN must fail serialization");
727        }
728
729        #[test]
730        fn value_infinity_serialize_is_error() {
731            let v = Value::from(f64::INFINITY);
732            assert!(
733                serde_json::to_string(&v).is_err(),
734                "Infinity must fail serialization"
735            );
736
737            let v = Value::from(f64::NEG_INFINITY);
738            assert!(
739                serde_json::to_string(&v).is_err(),
740                "-Infinity must fail serialization"
741            );
742        }
743
744        #[test]
745        fn list_value_deserializes_from_array() {
746            let json = r#"[null, 1, "s", true]"#;
747            let l: ListValue = serde_json::from_str(json).unwrap();
748            assert_eq!(l.values.len(), 4);
749            assert!(l.values[0].is_null());
750        }
751
752        #[test]
753        fn value_deserializes_integer() {
754            // JSON integer → visit_i64 / visit_u64 → NumberValue(f64)
755            let v: Value = serde_json::from_str("42").unwrap();
756            assert_eq!(v.as_number(), Some(42.0));
757        }
758
759        #[test]
760        fn value_deserializes_negative_integer() {
761            let v: Value = serde_json::from_str("-100").unwrap();
762            assert_eq!(v.as_number(), Some(-100.0));
763        }
764
765        #[test]
766        fn value_deserializes_large_integer() {
767            // 2^53 is exactly representable in f64.
768            let v: Value = serde_json::from_str("9007199254740992").unwrap();
769            assert_eq!(v.as_number(), Some(9007199254740992.0));
770        }
771
772        #[test]
773        fn value_deep_nesting_binary_respects_recursion_limit() {
774            // Value → ListValue → Value is recursive. Binary decode must
775            // hit our RECURSION_LIMIT, not stack-overflow.
776            use buffa::{DecodeError, Message};
777            // Build a deeply-nested ListValue chain via wire bytes.
778            // Each level: Value{list:ListValue{values:[Value{list:...}]}}
779            // Value.list (field 6, oneof, wire type 2 length-delimited):
780            //   tag=0x32, len, <ListValue bytes>
781            // ListValue.values (field 1, repeated Value, length-delimited):
782            //   tag=0x0a, len, <Value bytes>
783            // Innermost: empty Value (0 bytes).
784            let mut payload = alloc::vec::Vec::new();
785            for _ in 0..200 {
786                // Wrap: ListValue { values: [current payload as Value] }
787                let mut lv = alloc::vec::Vec::new();
788                lv.push(0x0a); // tag: field 1 wire 2
789                lv.push(payload.len() as u8); // assumes < 128 — fine for small depth
790                lv.extend_from_slice(&payload);
791                // Wrap: Value { list_value: lv }
792                let mut v = alloc::vec::Vec::new();
793                v.push(0x32); // tag: field 6 wire 2
794                v.push(lv.len() as u8);
795                v.extend_from_slice(&lv);
796                payload = v;
797                // Stop growing once payload length exceeds single-byte varint.
798                if payload.len() >= 120 {
799                    break;
800                }
801            }
802            // At ~120 bytes we have ~30 levels. Need to go deeper. Use proper
803            // varint encoding for larger lengths.
804            use buffa::encoding::encode_varint;
805            for _ in 0..200 {
806                let mut lv = alloc::vec::Vec::new();
807                lv.push(0x0a);
808                encode_varint(payload.len() as u64, &mut lv);
809                lv.extend_from_slice(&payload);
810                let mut v = alloc::vec::Vec::new();
811                v.push(0x32);
812                encode_varint(lv.len() as u64, &mut v);
813                v.extend_from_slice(&lv);
814                payload = v;
815            }
816            // ~230 levels of Value/ListValue nesting, each level consumes 2
817            // from the depth budget (Value + ListValue are each a merge).
818            // Default RECURSION_LIMIT is 100, so this should be rejected.
819            let result = Value::decode(&mut payload.as_slice());
820            assert!(
821                matches!(result, Err(DecodeError::RecursionLimitExceeded)),
822                "deep nesting must hit recursion limit, got: {result:?}"
823            );
824        }
825
826        #[test]
827        fn value_deep_nesting_json_bounded() {
828            // serde_json has its own recursion limit (default 128). A deeply-
829            // nested JSON array deserialize into Value must error cleanly,
830            // not stack-overflow. serde_json returns its own error type, not
831            // our DecodeError, so just assert is_err().
832            let deep = alloc::format!("{}null{}", "[".repeat(200), "]".repeat(200));
833            let result: Result<Value, _> = serde_json::from_str(&deep);
834            assert!(result.is_err(), "200-level JSON nesting must be rejected");
835        }
836    }
837}