Skip to main content

noyalib/value/
serde_impl.rs

1//! serde `Serialize`/`Deserialize` for `Value`.
2
3// SPDX-License-Identifier: MIT OR Apache-2.0
4// Copyright (c) 2026 Noyalib. All rights reserved.
5
6use super::{Mapping, Number, Tag, TaggedValue, Value};
7use crate::prelude::*;
8use indexmap::map::Iter;
9
10impl<'de> serde_core::Deserialize<'de> for Value {
11    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
12    where
13        D: serde_core::Deserializer<'de>,
14    {
15        serde_core::de::DeserializeSeed::deserialize(ValueSeed { depth: 0 }, deserializer)
16    }
17}
18
19/// Deserializes one [`Value`] nested `depth` collections deep.
20///
21/// Every nested element goes through a seed one level deeper, so a
22/// `Value` read from any serde format, not only YAML, stops at
23/// [`MAX_DEPTH_CEILING`](crate::parser::budget::MAX_DEPTH_CEILING)
24/// instead of building a value too deep to drop on a small stack.
25#[derive(Clone, Copy)]
26struct ValueSeed {
27    depth: usize,
28}
29
30impl<'de> serde_core::de::DeserializeSeed<'de> for ValueSeed {
31    type Value = Value;
32
33    fn deserialize<D>(self, deserializer: D) -> Result<Value, D::Error>
34    where
35        D: serde_core::Deserializer<'de>,
36    {
37        deserializer.deserialize_any(ValueVisitor { depth: self.depth })
38    }
39}
40
41struct ValueVisitor {
42    depth: usize,
43}
44
45impl ValueVisitor {
46    /// The seed for a child of the collection being visited, or the
47    /// error once that child would pass the ceiling.
48    fn child<E: serde_core::de::Error>(&self) -> Result<ValueSeed, E> {
49        let depth = self.depth + 1;
50        if crate::parser::budget::depth_exceeded(depth, usize::MAX) {
51            return Err(E::custom(format_args!(
52                "recursion depth limit exceeded: {depth}"
53            )));
54        }
55        Ok(ValueSeed { depth })
56    }
57}
58
59impl<'de> serde_core::de::Visitor<'de> for ValueVisitor {
60    type Value = Value;
61
62    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
63        formatter.write_str("any valid YAML value")
64    }
65
66    fn visit_bool<E>(self, v: bool) -> Result<Value, E> {
67        Ok(Value::Bool(v))
68    }
69
70    fn visit_i64<E>(self, v: i64) -> Result<Value, E> {
71        Ok(Value::Number(Number::Integer(v)))
72    }
73
74    fn visit_u64<E>(self, v: u64) -> Result<Value, E> {
75        Ok(Value::Number(Number::from(v)))
76    }
77
78    fn visit_f64<E>(self, v: f64) -> Result<Value, E> {
79        Ok(Value::Number(Number::Float(v)))
80    }
81
82    fn visit_str<E>(self, v: &str) -> Result<Value, E> {
83        Ok(Value::String(v.to_owned()))
84    }
85
86    fn visit_string<E>(self, v: String) -> Result<Value, E> {
87        Ok(Value::String(v))
88    }
89
90    fn visit_none<E>(self) -> Result<Value, E> {
91        Ok(Value::Null)
92    }
93
94    fn visit_unit<E>(self) -> Result<Value, E> {
95        Ok(Value::Null)
96    }
97
98    fn visit_enum<A>(self, data: A) -> Result<Value, A::Error>
99    where
100        A: serde_core::de::EnumAccess<'de>,
101    {
102        // The AST `Deserializer`'s `deserialize_any` routes a
103        // tagged node here (variant name = the YAML tag, payload
104        // = the untagged inner value) instead of transparently
105        // descending into it, so a `Value` reached through serde
106        // — nested inside a `Mapping`, a `Sequence`/`Vec<Value>`,
107        // or a struct field of type `Value` — keeps its tag the
108        // same way the top-level `Value` target already does.
109        // See #350.
110        use serde_core::de::VariantAccess as _;
111        let seed = self.child()?;
112        let (tag, variant): (String, A::Variant) = data.variant()?;
113        let value: Value = variant.newtype_variant_seed(seed)?;
114        Ok(Value::Tagged(Box::new(TaggedValue::new(
115            Tag::new(tag),
116            value,
117        ))))
118    }
119
120    fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
121    where
122        A: serde_core::de::SeqAccess<'de>,
123    {
124        let seed = self.child()?;
125        // Pre-size from the SeqAccess size_hint when
126        // available — saves up to ~11 reallocations on a
127        // 2 000-element sequence (Vec doubles on each
128        // grow). Falls back to the default growth strategy
129        // when the hint isn't reliable.
130        let mut vec = match seq.size_hint() {
131            Some(n) if n > 0 && n < 1 << 20 => Vec::with_capacity(n),
132            _ => Vec::new(),
133        };
134        while let Some(elem) = seq.next_element_seed(seed)? {
135            vec.push(elem);
136        }
137        Ok(Value::Sequence(vec))
138    }
139
140    fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
141    where
142        A: serde_core::de::MapAccess<'de>,
143    {
144        let seed = self.child()?;
145        // Pre-size when the MapAccess provides a usable
146        // hint; saves ~10 IndexMap rehashes on large
147        // mappings (capacity grows by ~doubling).
148        let mut mapping = match map.size_hint() {
149            Some(n) if n > 0 && n < 1 << 20 => Mapping::with_capacity(n),
150            _ => Mapping::new(),
151        };
152        while let Some(key) = map.next_key::<String>()? {
153            let value = map.next_value_seed(seed)?;
154            let _ = mapping.insert(key, value);
155        }
156        Ok(Value::Mapping(mapping))
157    }
158}
159
160impl serde_core::Serialize for Value {
161    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
162    where
163        S: serde_core::Serializer,
164    {
165        match self {
166            Self::Null => serializer.serialize_none(),
167            Self::Bool(b) => serializer.serialize_bool(*b),
168            Self::Number(Number::Integer(n)) => serializer.serialize_i64(*n),
169            #[cfg(feature = "lossless-u64")]
170            Self::Number(Number::Unsigned(n)) => serializer.serialize_u64(*n),
171            Self::Number(Number::Float(n)) => serializer.serialize_f64(*n),
172            Self::String(s) => serializer.serialize_str(s),
173            Self::Sequence(s) => s.serialize(serializer),
174            Self::Mapping(m) => {
175                use serde_core::ser::SerializeMap as _;
176                let mut map = serializer.serialize_map(Some(m.len()))?;
177                for (k, v) in m {
178                    map.serialize_entry(k, v)?;
179                }
180                map.end()
181            }
182            // `TaggedValue::serialize` owns the wire form (a marker newtype
183            // around a single-entry map keyed by the tag string); one
184            // definition keeps this arm and the standalone impl in step.
185            Self::Tagged(tagged) => serde_core::Serialize::serialize(tagged.as_ref(), serializer),
186        }
187    }
188}
189
190// ============================================================================
191// Deserializer implementation for &Value
192// ============================================================================
193
194impl<'de> serde_core::de::IntoDeserializer<'de, crate::Error> for &'de Value {
195    type Deserializer = Self;
196
197    fn into_deserializer(self) -> Self::Deserializer {
198        self
199    }
200}
201
202struct ValueSeqAccess<'de> {
203    iter: core::slice::Iter<'de, Value>,
204}
205
206impl<'de> serde_core::de::SeqAccess<'de> for ValueSeqAccess<'de> {
207    type Error = crate::Error;
208
209    fn next_element_seed<T>(&mut self, seed: T) -> crate::Result<Option<T::Value>>
210    where
211        T: serde_core::de::DeserializeSeed<'de>,
212    {
213        match self.iter.next() {
214            Some(value) => seed.deserialize(value).map(Some),
215            None => Ok(None),
216        }
217    }
218}
219
220struct ValueMapAccess<'de> {
221    iter: Iter<'de, String, Value>,
222    value: Option<&'de Value>,
223}
224
225impl<'de> serde_core::de::MapAccess<'de> for ValueMapAccess<'de> {
226    type Error = crate::Error;
227
228    fn next_key_seed<K>(&mut self, seed: K) -> crate::Result<Option<K::Value>>
229    where
230        K: serde_core::de::DeserializeSeed<'de>,
231    {
232        match self.iter.next() {
233            Some((key, value)) => {
234                self.value = Some(value);
235                seed.deserialize(serde_core::de::value::BorrowedStrDeserializer::new(key))
236                    .map(Some)
237            }
238            None => Ok(None),
239        }
240    }
241
242    fn next_value_seed<V>(&mut self, seed: V) -> crate::Result<V::Value>
243    where
244        V: serde_core::de::DeserializeSeed<'de>,
245    {
246        match self.value.take() {
247            Some(value) => seed.deserialize(value),
248            None => Err(serde_core::de::Error::custom("value is missing")),
249        }
250    }
251}
252
253impl<'de> serde_core::Deserializer<'de> for &'de Value {
254    type Error = crate::Error;
255
256    fn deserialize_any<V>(self, visitor: V) -> crate::Result<V::Value>
257    where
258        V: serde_core::de::Visitor<'de>,
259    {
260        match self {
261            Value::Null => visitor.visit_unit(),
262            Value::Bool(b) => visitor.visit_bool(*b),
263            Value::Number(Number::Integer(n)) => visitor.visit_i64(*n),
264            #[cfg(feature = "lossless-u64")]
265            Value::Number(Number::Unsigned(n)) => visitor.visit_u64(*n),
266            Value::Number(Number::Float(n)) => visitor.visit_f64(*n),
267            Value::String(s) => visitor.visit_borrowed_str(s),
268            Value::Sequence(seq) => visitor.visit_seq(ValueSeqAccess { iter: seq.iter() }),
269            Value::Mapping(map) => visitor.visit_map(ValueMapAccess {
270                iter: map.iter(),
271                value: None,
272            }),
273            Value::Tagged(tagged) => {
274                let tagged_ref: &'de TaggedValue = tagged;
275                serde_core::Deserializer::deserialize_any(tagged_ref, visitor)
276            }
277        }
278    }
279
280    fn deserialize_enum<V>(
281        self,
282        name: &'static str,
283        variants: &'static [&'static str],
284        visitor: V,
285    ) -> crate::Result<V::Value>
286    where
287        V: serde_core::de::Visitor<'de>,
288    {
289        match self {
290            Value::Tagged(tagged) => {
291                let tagged_ref: &'de TaggedValue = tagged;
292                serde_core::Deserializer::deserialize_enum(tagged_ref, name, variants, visitor)
293            }
294            Value::String(s) => visitor
295                .visit_enum(serde_core::de::value::BorrowedStrDeserializer::<crate::Error>::new(s)),
296            _ => serde_core::Deserializer::deserialize_any(self, visitor),
297        }
298    }
299
300    fn deserialize_seq<V>(self, visitor: V) -> crate::Result<V::Value>
301    where
302        V: serde_core::de::Visitor<'de>,
303    {
304        match self {
305            Value::Sequence(seq) => visitor.visit_seq(ValueSeqAccess { iter: seq.iter() }),
306            _ => serde_core::Deserializer::deserialize_any(self, visitor),
307        }
308    }
309
310    fn deserialize_map<V>(self, visitor: V) -> crate::Result<V::Value>
311    where
312        V: serde_core::de::Visitor<'de>,
313    {
314        match self {
315            Value::Mapping(map) => visitor.visit_map(ValueMapAccess {
316                iter: map.iter(),
317                value: None,
318            }),
319            _ => serde_core::Deserializer::deserialize_any(self, visitor),
320        }
321    }
322
323    fn deserialize_struct<V>(
324        self,
325        name: &'static str,
326        _fields: &'static [&'static str],
327        visitor: V,
328    ) -> crate::Result<V::Value>
329    where
330        V: serde_core::de::Visitor<'de>,
331    {
332        if name == crate::spanned::SPANNED_TYPE_NAME {
333            // Deserializing straight from a `Value` carries no
334            // `ParserConfig`, so the per-call toggles are off by
335            // definition here — unlike the `from_str` paths, which
336            // now pass their own through.
337            return visitor.visit_map(crate::de::SpannedMapAccess::new(self, None, false, false));
338        }
339        serde_core::Deserializer::deserialize_map(self, visitor)
340    }
341
342    fn deserialize_option<V>(self, visitor: V) -> crate::Result<V::Value>
343    where
344        V: serde_core::de::Visitor<'de>,
345    {
346        // `option` used to be in the `forward_to_deserialize_any!` list
347        // below, which sent every value straight to `deserialize_any`.
348        // For anything other than null that hands the visitor a concrete
349        // scalar — `visit_borrowed_str`, `visit_i64` — and serde's
350        // `Option` visitor rejects it:
351        //
352        //     invalid type: string "hello", expected option
353        //
354        // Only `~` happened to work, because `deserialize_any` maps
355        // `Value::Null` to `visit_unit` and the `Option` visitor accepts
356        // that as `None`. Every *populated* Option field failed, for any
357        // `T`. See #239, which reported it for `Option<String>`; it was
358        // never specific to strings or to empty ones.
359        match self {
360            Value::Null => visitor.visit_none(),
361            _ => visitor.visit_some(self),
362        }
363    }
364
365    serde_core::forward_to_deserialize_any! {
366        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
367        byte_buf unit unit_struct newtype_struct tuple
368        tuple_struct identifier ignored_any
369    }
370}