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, TaggedValue, Value};
7use crate::prelude::*;
8use indexmap::map::Iter;
9use serde::{Deserialize, Serialize};
10
11impl<'de> Deserialize<'de> for Value {
12    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
13    where
14        D: serde::Deserializer<'de>,
15    {
16        use serde::de::{MapAccess, SeqAccess, Visitor};
17
18        struct ValueVisitor;
19
20        impl<'de> Visitor<'de> for ValueVisitor {
21            type Value = Value;
22
23            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
24                formatter.write_str("any valid YAML value")
25            }
26
27            fn visit_bool<E>(self, v: bool) -> Result<Value, E> {
28                Ok(Value::Bool(v))
29            }
30
31            fn visit_i64<E>(self, v: i64) -> Result<Value, E> {
32                Ok(Value::Number(Number::Integer(v)))
33            }
34
35            fn visit_u64<E>(self, v: u64) -> Result<Value, E> {
36                Ok(Value::Number(Number::from(v)))
37            }
38
39            fn visit_f64<E>(self, v: f64) -> Result<Value, E> {
40                Ok(Value::Number(Number::Float(v)))
41            }
42
43            fn visit_str<E>(self, v: &str) -> Result<Value, E> {
44                Ok(Value::String(v.to_owned()))
45            }
46
47            fn visit_string<E>(self, v: String) -> Result<Value, E> {
48                Ok(Value::String(v))
49            }
50
51            fn visit_none<E>(self) -> Result<Value, E> {
52                Ok(Value::Null)
53            }
54
55            fn visit_unit<E>(self) -> Result<Value, E> {
56                Ok(Value::Null)
57            }
58
59            fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
60            where
61                A: SeqAccess<'de>,
62            {
63                // Pre-size from the SeqAccess size_hint when
64                // available — saves up to ~11 reallocations on a
65                // 2 000-element sequence (Vec doubles on each
66                // grow). Falls back to the default growth strategy
67                // when the hint isn't reliable.
68                let mut vec = match seq.size_hint() {
69                    Some(n) if n > 0 && n < 1 << 20 => Vec::with_capacity(n),
70                    _ => Vec::new(),
71                };
72                while let Some(elem) = seq.next_element()? {
73                    vec.push(elem);
74                }
75                Ok(Value::Sequence(vec))
76            }
77
78            fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
79            where
80                A: MapAccess<'de>,
81            {
82                let first_key: Option<String> = map.next_key()?;
83                // Regular mapping path — collect every (k, v) pair
84                // including the (k, v) we already consumed.
85                // Pre-size when the MapAccess provides a usable
86                // hint; saves ~10 IndexMap rehashes on large
87                // mappings (capacity grows by ~doubling).
88                let mut mapping = match map.size_hint() {
89                    Some(n) if n > 0 && n < 1 << 20 => Mapping::with_capacity(n),
90                    _ => Mapping::new(),
91                };
92                if let Some(k) = first_key {
93                    let v: Value = map.next_value()?;
94                    let _ = mapping.insert(k, v);
95                }
96                while let Some((key, value)) = map.next_entry::<String, Value>()? {
97                    let _ = mapping.insert(key, value);
98                }
99                Ok(Value::Mapping(mapping))
100            }
101        }
102
103        deserializer.deserialize_any(ValueVisitor)
104    }
105}
106
107impl Serialize for Value {
108    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109    where
110        S: serde::Serializer,
111    {
112        match self {
113            Value::Null => serializer.serialize_none(),
114            Value::Bool(b) => serializer.serialize_bool(*b),
115            Value::Number(Number::Integer(n)) => serializer.serialize_i64(*n),
116            #[cfg(feature = "lossless-u64")]
117            Value::Number(Number::Unsigned(n)) => serializer.serialize_u64(*n),
118            Value::Number(Number::Float(n)) => serializer.serialize_f64(*n),
119            Value::String(s) => serializer.serialize_str(s),
120            Value::Sequence(s) => s.serialize(serializer),
121            Value::Mapping(m) => {
122                use serde::ser::SerializeMap;
123                let mut map = serializer.serialize_map(Some(m.len()))?;
124                for (k, v) in m {
125                    map.serialize_entry(k, v)?;
126                }
127                map.end()
128            }
129            Value::Tagged(tagged) => {
130                // Serialize as a single-entry map with tag as key
131                use serde::ser::SerializeMap;
132                let mut map = serializer.serialize_map(Some(1))?;
133                map.serialize_entry(tagged.tag().as_str(), tagged.value())?;
134                map.end()
135            }
136        }
137    }
138}
139
140// ============================================================================
141// Deserializer implementation for &Value
142// ============================================================================
143
144impl<'de> serde::de::IntoDeserializer<'de, crate::Error> for &'de Value {
145    type Deserializer = Self;
146
147    fn into_deserializer(self) -> Self::Deserializer {
148        self
149    }
150}
151
152struct ValueSeqAccess<'de> {
153    iter: core::slice::Iter<'de, Value>,
154}
155
156impl<'de> serde::de::SeqAccess<'de> for ValueSeqAccess<'de> {
157    type Error = crate::Error;
158
159    fn next_element_seed<T>(&mut self, seed: T) -> crate::Result<Option<T::Value>>
160    where
161        T: serde::de::DeserializeSeed<'de>,
162    {
163        match self.iter.next() {
164            Some(value) => seed.deserialize(value).map(Some),
165            None => Ok(None),
166        }
167    }
168}
169
170struct ValueMapAccess<'de> {
171    iter: Iter<'de, String, Value>,
172    value: Option<&'de Value>,
173}
174
175impl<'de> serde::de::MapAccess<'de> for ValueMapAccess<'de> {
176    type Error = crate::Error;
177
178    fn next_key_seed<K>(&mut self, seed: K) -> crate::Result<Option<K::Value>>
179    where
180        K: serde::de::DeserializeSeed<'de>,
181    {
182        match self.iter.next() {
183            Some((key, value)) => {
184                self.value = Some(value);
185                seed.deserialize(serde::de::value::BorrowedStrDeserializer::new(key))
186                    .map(Some)
187            }
188            None => Ok(None),
189        }
190    }
191
192    fn next_value_seed<V>(&mut self, seed: V) -> crate::Result<V::Value>
193    where
194        V: serde::de::DeserializeSeed<'de>,
195    {
196        match self.value.take() {
197            Some(value) => seed.deserialize(value),
198            None => Err(serde::de::Error::custom("value is missing")),
199        }
200    }
201}
202
203impl<'de> serde::Deserializer<'de> for &'de Value {
204    type Error = crate::Error;
205
206    fn deserialize_any<V>(self, visitor: V) -> crate::Result<V::Value>
207    where
208        V: serde::de::Visitor<'de>,
209    {
210        match self {
211            Value::Null => visitor.visit_unit(),
212            Value::Bool(b) => visitor.visit_bool(*b),
213            Value::Number(Number::Integer(n)) => visitor.visit_i64(*n),
214            #[cfg(feature = "lossless-u64")]
215            Value::Number(Number::Unsigned(n)) => visitor.visit_u64(*n),
216            Value::Number(Number::Float(n)) => visitor.visit_f64(*n),
217            Value::String(s) => visitor.visit_borrowed_str(s),
218            Value::Sequence(seq) => visitor.visit_seq(ValueSeqAccess { iter: seq.iter() }),
219            Value::Mapping(map) => visitor.visit_map(ValueMapAccess {
220                iter: map.iter(),
221                value: None,
222            }),
223            Value::Tagged(tagged) => {
224                let tagged_ref: &'de TaggedValue = tagged;
225                serde::Deserializer::deserialize_any(tagged_ref, visitor)
226            }
227        }
228    }
229
230    fn deserialize_enum<V>(
231        self,
232        name: &'static str,
233        variants: &'static [&'static str],
234        visitor: V,
235    ) -> crate::Result<V::Value>
236    where
237        V: serde::de::Visitor<'de>,
238    {
239        match self {
240            Value::Tagged(tagged) => {
241                let tagged_ref: &'de TaggedValue = tagged;
242                serde::Deserializer::deserialize_enum(tagged_ref, name, variants, visitor)
243            }
244            Value::String(s) => visitor
245                .visit_enum(serde::de::value::BorrowedStrDeserializer::<crate::Error>::new(s)),
246            _ => serde::Deserializer::deserialize_any(self, visitor),
247        }
248    }
249
250    fn deserialize_seq<V>(self, visitor: V) -> crate::Result<V::Value>
251    where
252        V: serde::de::Visitor<'de>,
253    {
254        match self {
255            Value::Sequence(seq) => visitor.visit_seq(ValueSeqAccess { iter: seq.iter() }),
256            _ => serde::Deserializer::deserialize_any(self, visitor),
257        }
258    }
259
260    fn deserialize_map<V>(self, visitor: V) -> crate::Result<V::Value>
261    where
262        V: serde::de::Visitor<'de>,
263    {
264        match self {
265            Value::Mapping(map) => visitor.visit_map(ValueMapAccess {
266                iter: map.iter(),
267                value: None,
268            }),
269            _ => serde::Deserializer::deserialize_any(self, visitor),
270        }
271    }
272
273    fn deserialize_struct<V>(
274        self,
275        name: &'static str,
276        _fields: &'static [&'static str],
277        visitor: V,
278    ) -> crate::Result<V::Value>
279    where
280        V: serde::de::Visitor<'de>,
281    {
282        if name == crate::spanned::SPANNED_TYPE_NAME {
283            return visitor.visit_map(crate::de::SpannedMapAccess::new(self, None));
284        }
285        serde::Deserializer::deserialize_map(self, visitor)
286    }
287
288    serde::forward_to_deserialize_any! {
289        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
290        byte_buf option unit unit_struct newtype_struct tuple
291        tuple_struct identifier ignored_any
292    }
293}