rust_yaml/serde_integration/
ser.rs1use crate::{Error, Value, Yaml};
8use indexmap::IndexMap;
9use serde::ser::{
10 Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
11 SerializeTupleStruct, SerializeTupleVariant, Serializer,
12};
13
14pub 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 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
201pub 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
256pub 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
281pub 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
340pub 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
374pub 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
386pub 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}