Skip to main content

rust_yaml/serde_integration/
ser.rs

1//! serde::Serializer that builds a `Value` tree.
2//!
3//! The public `to_string` / `to_writer` entry points (Task 8) will serialize
4//! `T` into a `Value` via this serializer, then delegate to the existing
5//! `dump_str` pipeline.
6
7use crate::{Error, Value, Yaml};
8use indexmap::IndexMap;
9use serde::ser::{
10    Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
11    SerializeTupleStruct, SerializeTupleVariant, Serializer,
12};
13
14/// Serializer that emits a `Value`. Stateless; one per call.
15pub struct ValueSerializer;
16
17impl Serializer for ValueSerializer {
18    type Ok = Value;
19    type Error = Error;
20
21    type SerializeSeq = SeqBuilder;
22    type SerializeTuple = SeqBuilder;
23    type SerializeTupleStruct = SeqBuilder;
24    type SerializeTupleVariant = TupleVariantBuilder;
25    type SerializeMap = MapBuilder;
26    type SerializeStruct = MapBuilder;
27    type SerializeStructVariant = StructVariantBuilder;
28
29    fn serialize_bool(self, v: bool) -> Result<Value, Error> {
30        Ok(Value::Bool(v))
31    }
32
33    fn serialize_i8(self, v: i8) -> Result<Value, Error> {
34        Ok(Value::Int(i64::from(v)))
35    }
36
37    fn serialize_i16(self, v: i16) -> Result<Value, Error> {
38        Ok(Value::Int(i64::from(v)))
39    }
40
41    fn serialize_i32(self, v: i32) -> Result<Value, Error> {
42        Ok(Value::Int(i64::from(v)))
43    }
44
45    fn serialize_i64(self, v: i64) -> Result<Value, Error> {
46        Ok(Value::Int(v))
47    }
48
49    fn serialize_i128(self, v: i128) -> Result<Value, Error> {
50        i64::try_from(v)
51            .map(Value::Int)
52            .map_err(|_| <Error as serde::ser::Error>::custom("integer out of range for i64"))
53    }
54
55    fn serialize_u8(self, v: u8) -> Result<Value, Error> {
56        Ok(Value::Int(i64::from(v)))
57    }
58
59    fn serialize_u16(self, v: u16) -> Result<Value, Error> {
60        Ok(Value::Int(i64::from(v)))
61    }
62
63    fn serialize_u32(self, v: u32) -> Result<Value, Error> {
64        Ok(Value::Int(i64::from(v)))
65    }
66
67    fn serialize_u64(self, v: u64) -> Result<Value, Error> {
68        i64::try_from(v)
69            .map(Value::Int)
70            .map_err(|_| <Error as serde::ser::Error>::custom("u64 above i64::MAX"))
71    }
72
73    fn serialize_u128(self, v: u128) -> Result<Value, Error> {
74        i64::try_from(v)
75            .map(Value::Int)
76            .map_err(|_| <Error as serde::ser::Error>::custom("integer out of range for i64"))
77    }
78
79    fn serialize_f32(self, v: f32) -> Result<Value, Error> {
80        Ok(Value::Float(f64::from(v)))
81    }
82
83    fn serialize_f64(self, v: f64) -> Result<Value, Error> {
84        Ok(Value::Float(v))
85    }
86
87    fn serialize_char(self, c: char) -> Result<Value, Error> {
88        Ok(Value::String(c.to_string()))
89    }
90
91    fn serialize_str(self, s: &str) -> Result<Value, Error> {
92        Ok(Value::String(s.to_owned()))
93    }
94
95    fn serialize_bytes(self, b: &[u8]) -> Result<Value, Error> {
96        // v1.1.0: bytes as Sequence<Int>. !!binary tagged form deferred.
97        Ok(Value::Sequence(
98            b.iter().map(|x| Value::Int(i64::from(*x))).collect(),
99        ))
100    }
101
102    fn serialize_none(self) -> Result<Value, Error> {
103        Ok(Value::Null)
104    }
105
106    fn serialize_some<T: ?Sized + Serialize>(self, v: &T) -> Result<Value, Error> {
107        v.serialize(self)
108    }
109
110    fn serialize_unit(self) -> Result<Value, Error> {
111        Ok(Value::Null)
112    }
113
114    fn serialize_unit_struct(self, _: &'static str) -> Result<Value, Error> {
115        Ok(Value::Null)
116    }
117
118    fn serialize_unit_variant(
119        self,
120        _: &'static str,
121        _: u32,
122        variant: &'static str,
123    ) -> Result<Value, Error> {
124        Ok(Value::String(variant.to_owned()))
125    }
126
127    fn serialize_newtype_struct<T: ?Sized + Serialize>(
128        self,
129        _: &'static str,
130        v: &T,
131    ) -> Result<Value, Error> {
132        v.serialize(self)
133    }
134
135    fn serialize_newtype_variant<T: ?Sized + Serialize>(
136        self,
137        _: &'static str,
138        _: u32,
139        variant: &'static str,
140        v: &T,
141    ) -> Result<Value, Error> {
142        let mut m = IndexMap::new();
143        m.insert(
144            Value::String(variant.to_owned()),
145            v.serialize(ValueSerializer)?,
146        );
147        Ok(Value::Mapping(m))
148    }
149
150    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
151        Ok(SeqBuilder::with_capacity(len.unwrap_or(0)))
152    }
153
154    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
155        Ok(SeqBuilder::with_capacity(len))
156    }
157
158    fn serialize_tuple_struct(
159        self,
160        _: &'static str,
161        len: usize,
162    ) -> Result<Self::SerializeTupleStruct, Error> {
163        Ok(SeqBuilder::with_capacity(len))
164    }
165
166    fn serialize_tuple_variant(
167        self,
168        _: &'static str,
169        _: u32,
170        variant: &'static str,
171        len: usize,
172    ) -> Result<Self::SerializeTupleVariant, Error> {
173        Ok(TupleVariantBuilder {
174            variant,
175            items: Vec::with_capacity(len),
176        })
177    }
178
179    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Error> {
180        Ok(MapBuilder::with_capacity(len.unwrap_or(0)))
181    }
182
183    fn serialize_struct(self, _: &'static str, len: usize) -> Result<Self::SerializeStruct, Error> {
184        Ok(MapBuilder::with_capacity(len))
185    }
186
187    fn serialize_struct_variant(
188        self,
189        _: &'static str,
190        _: u32,
191        variant: &'static str,
192        len: usize,
193    ) -> Result<Self::SerializeStructVariant, Error> {
194        Ok(StructVariantBuilder {
195            variant,
196            fields: IndexMap::with_capacity(len),
197        })
198    }
199}
200
201/// Accumulates elements for sequences, tuples, and tuple structs.
202pub struct SeqBuilder {
203    items: Vec<Value>,
204}
205
206impl SeqBuilder {
207    fn with_capacity(n: usize) -> Self {
208        Self {
209            items: Vec::with_capacity(n),
210        }
211    }
212}
213
214impl SerializeSeq for SeqBuilder {
215    type Ok = Value;
216    type Error = Error;
217
218    fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Error> {
219        self.items.push(v.serialize(ValueSerializer)?);
220        Ok(())
221    }
222
223    fn end(self) -> Result<Value, Error> {
224        Ok(Value::Sequence(self.items))
225    }
226}
227
228impl SerializeTuple for SeqBuilder {
229    type Ok = Value;
230    type Error = Error;
231
232    fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Error> {
233        self.items.push(v.serialize(ValueSerializer)?);
234        Ok(())
235    }
236
237    fn end(self) -> Result<Value, Error> {
238        Ok(Value::Sequence(self.items))
239    }
240}
241
242impl SerializeTupleStruct for SeqBuilder {
243    type Ok = Value;
244    type Error = Error;
245
246    fn serialize_field<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Error> {
247        self.items.push(v.serialize(ValueSerializer)?);
248        Ok(())
249    }
250
251    fn end(self) -> Result<Value, Error> {
252        Ok(Value::Sequence(self.items))
253    }
254}
255
256/// Accumulates elements for an externally-tagged tuple variant.
257pub struct TupleVariantBuilder {
258    variant: &'static str,
259    items: Vec<Value>,
260}
261
262impl SerializeTupleVariant for TupleVariantBuilder {
263    type Ok = Value;
264    type Error = Error;
265
266    fn serialize_field<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Error> {
267        self.items.push(v.serialize(ValueSerializer)?);
268        Ok(())
269    }
270
271    fn end(self) -> Result<Value, Error> {
272        let mut m = IndexMap::with_capacity(1);
273        m.insert(
274            Value::String(self.variant.to_owned()),
275            Value::Sequence(self.items),
276        );
277        Ok(Value::Mapping(m))
278    }
279}
280
281/// Accumulates key-value pairs for maps and structs.
282pub struct MapBuilder {
283    map: IndexMap<Value, Value>,
284    next_key: Option<Value>,
285}
286
287impl MapBuilder {
288    fn with_capacity(n: usize) -> Self {
289        Self {
290            map: IndexMap::with_capacity(n),
291            next_key: None,
292        }
293    }
294}
295
296impl SerializeMap for MapBuilder {
297    type Ok = Value;
298    type Error = Error;
299
300    fn serialize_key<T: ?Sized + Serialize>(&mut self, k: &T) -> Result<(), Error> {
301        self.next_key = Some(k.serialize(ValueSerializer)?);
302        Ok(())
303    }
304
305    fn serialize_value<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<(), Error> {
306        let key = self
307            .next_key
308            .take()
309            .ok_or_else(|| <Error as serde::ser::Error>::custom("serialize_value without key"))?;
310        self.map.insert(key, v.serialize(ValueSerializer)?);
311        Ok(())
312    }
313
314    fn end(self) -> Result<Value, Error> {
315        Ok(Value::Mapping(self.map))
316    }
317}
318
319impl SerializeStruct for MapBuilder {
320    type Ok = Value;
321    type Error = Error;
322
323    fn serialize_field<T: ?Sized + Serialize>(
324        &mut self,
325        name: &'static str,
326        v: &T,
327    ) -> Result<(), Error> {
328        self.map.insert(
329            Value::String(name.to_owned()),
330            v.serialize(ValueSerializer)?,
331        );
332        Ok(())
333    }
334
335    fn end(self) -> Result<Value, Error> {
336        Ok(Value::Mapping(self.map))
337    }
338}
339
340/// Accumulates fields for an externally-tagged struct variant.
341pub struct StructVariantBuilder {
342    variant: &'static str,
343    fields: IndexMap<Value, Value>,
344}
345
346impl SerializeStructVariant for StructVariantBuilder {
347    type Ok = Value;
348    type Error = Error;
349
350    fn serialize_field<T: ?Sized + Serialize>(
351        &mut self,
352        name: &'static str,
353        v: &T,
354    ) -> Result<(), Error> {
355        self.fields.insert(
356            Value::String(name.to_owned()),
357            v.serialize(ValueSerializer)?,
358        );
359        Ok(())
360    }
361
362    fn end(self) -> Result<Value, Error> {
363        let mut outer = IndexMap::with_capacity(1);
364        outer.insert(
365            Value::String(self.variant.to_owned()),
366            Value::Mapping(self.fields),
367        );
368        Ok(Value::Mapping(outer))
369    }
370}
371
372use std::io::Write;
373
374/// Serialize `T` to a YAML string.
375///
376/// Source-compatible with `serde_yaml::to_string`.
377///
378/// # Errors
379///
380/// Returns an error if `T`'s `Serialize` impl fails or if YAML emission fails.
381pub fn to_string<T: ?Sized + Serialize>(v: &T) -> Result<String, Error> {
382    let val = v.serialize(ValueSerializer)?;
383    Yaml::new().dump_str(&val)
384}
385
386/// Serialize `T` into the given writer as YAML.
387///
388/// Source-compatible with `serde_yaml::to_writer`.
389///
390/// # Errors
391///
392/// Returns an error if serialization fails or if writing to `w` fails.
393pub fn to_writer<W: Write, T: ?Sized + Serialize>(mut w: W, v: &T) -> Result<(), Error> {
394    let s = to_string(v)?;
395    write_all_or_io_error(&mut w, s.as_bytes())
396}
397
398fn write_all_or_io_error<W: Write>(w: &mut W, bytes: &[u8]) -> Result<(), Error> {
399    w.write_all(bytes).map_err(Error::from)
400}
401
402#[cfg(test)]
403mod tests {
404    use super::*;
405    use crate::Value;
406    use serde::Serialize;
407
408    fn ser<T: Serialize>(v: T) -> Value {
409        v.serialize(ValueSerializer).expect("serialize")
410    }
411
412    #[test]
413    fn primitives_round_trip_to_value() {
414        assert_eq!(ser(()), Value::Null);
415        assert_eq!(ser(Option::<i32>::None), Value::Null);
416        assert_eq!(ser(true), Value::Bool(true));
417        assert_eq!(ser(7i32), Value::Int(7));
418        assert_eq!(ser(7u32), Value::Int(7));
419        assert_eq!(ser(1.5f32), Value::Float(1.5));
420        assert_eq!(ser("hi"), Value::String("hi".into()));
421        assert_eq!(ser('x'), Value::String("x".into()));
422    }
423
424    #[test]
425    fn u64_above_i64_max_errors() {
426        let huge: u64 = (i64::MAX as u64) + 1;
427        assert!(huge.serialize(ValueSerializer).is_err());
428    }
429
430    #[test]
431    fn vec_and_tuple_serialize_to_sequence() {
432        assert_eq!(
433            ser(vec![1i32, 2, 3]),
434            Value::Sequence(vec![Value::Int(1), Value::Int(2), Value::Int(3)])
435        );
436        assert_eq!(
437            ser((10u8, "x", true)),
438            Value::Sequence(vec![
439                Value::Int(10),
440                Value::String("x".into()),
441                Value::Bool(true)
442            ])
443        );
444    }
445
446    #[test]
447    fn tuple_variant_serializes_to_externally_tagged_map() {
448        #[derive(serde::Serialize)]
449        enum E {
450            Pair(i32, i32),
451        }
452        let v = ser(E::Pair(1, 2));
453        let m = v.as_mapping().expect("mapping");
454        assert_eq!(
455            m.get(&Value::String("Pair".into())),
456            Some(&Value::Sequence(vec![Value::Int(1), Value::Int(2)]))
457        );
458    }
459
460    #[test]
461    fn struct_serializes_to_mapping_preserving_field_order() {
462        #[derive(serde::Serialize)]
463        struct Cfg {
464            name: String,
465            version: u32,
466            enabled: bool,
467        }
468        let v = ser(Cfg {
469            name: "rust".into(),
470            version: 11,
471            enabled: true,
472        });
473        let m = v.as_mapping().expect("mapping");
474        let keys: Vec<&Value> = m.keys().collect();
475        assert_eq!(
476            keys,
477            vec![
478                &Value::String("name".into()),
479                &Value::String("version".into()),
480                &Value::String("enabled".into())
481            ]
482        );
483        assert_eq!(
484            m.get(&Value::String("version".into())),
485            Some(&Value::Int(11))
486        );
487    }
488
489    #[test]
490    fn struct_variant_serializes_to_externally_tagged_map() {
491        #[derive(serde::Serialize)]
492        enum E {
493            Point { x: i32, y: i32 },
494        }
495        let v = ser(E::Point { x: 3, y: 4 });
496        let m = v.as_mapping().expect("outer map");
497        let inner = m
498            .get(&Value::String("Point".into()))
499            .expect("Point variant")
500            .as_mapping()
501            .expect("inner map");
502        assert_eq!(inner.get(&Value::String("x".into())), Some(&Value::Int(3)));
503        assert_eq!(inner.get(&Value::String("y".into())), Some(&Value::Int(4)));
504    }
505
506    #[test]
507    fn to_string_emits_yaml_for_struct() {
508        #[derive(serde::Serialize)]
509        struct Cfg {
510            name: String,
511            version: u32,
512        }
513        let yaml = to_string(&Cfg {
514            name: "rust".into(),
515            version: 11,
516        })
517        .expect("to_string");
518        assert!(yaml.contains("name: rust"));
519        assert!(yaml.contains("version: 11"));
520    }
521
522    #[test]
523    fn to_writer_writes_same_output_as_to_string() {
524        let v = vec![1i32, 2, 3];
525        let s = to_string(&v).unwrap();
526        let mut buf = Vec::<u8>::new();
527        to_writer(&mut buf, &v).unwrap();
528        assert_eq!(std::str::from_utf8(&buf).unwrap(), s);
529    }
530}