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