Skip to main content

yaml_rt_serde/
ser.rs

1use std::io::Write;
2
3use serde::{Serialize, ser};
4
5use crate::{Error, Result};
6
7/// Serializes a value to a UTF-8 YAML string.
8pub fn to_string<T>(value: &T) -> Result<String>
9where
10    T: ?Sized + Serialize,
11{
12    let mut output = Vec::new();
13    to_writer(&mut output, value)?;
14    String::from_utf8(output).map_err(|error| Error::message(error.to_string()))
15}
16
17/// Serializes a value as one YAML document.
18pub fn to_writer<W, T>(writer: W, value: &T) -> Result<()>
19where
20    W: Write,
21    T: ?Sized + Serialize,
22{
23    let mut serializer = Serializer::new(writer);
24    value.serialize(&mut serializer)
25}
26
27/// A YAML serializer writing one or more documents to an `io::Write` sink.
28pub struct Serializer<W> {
29    writer: W,
30    documents: usize,
31}
32
33impl<W> Serializer<W>
34where
35    W: Write,
36{
37    /// Creates a serializer around `writer`.
38    pub const fn new(writer: W) -> Self {
39        Self {
40            writer,
41            documents: 0,
42        }
43    }
44
45    /// Flushes the underlying writer.
46    pub fn flush(&mut self) -> Result<()> {
47        self.writer.flush().map_err(Error::io)
48    }
49
50    /// Flushes and returns the underlying writer.
51    pub fn into_inner(mut self) -> Result<W> {
52        self.flush()?;
53        Ok(self.writer)
54    }
55
56    fn write_document(&mut self, value: SerValue) -> Result<()> {
57        if self.documents > 0 {
58            self.writer.write_all(b"---\n").map_err(Error::io)?;
59        }
60        let mut output = String::new();
61        render_value(&value, 0, &mut output);
62        if !output.ends_with('\n') {
63            output.push('\n');
64        }
65        self.writer
66            .write_all(output.as_bytes())
67            .map_err(Error::io)?;
68        self.documents += 1;
69        Ok(())
70    }
71
72    fn collect<T>(&mut self, value: &T) -> Result<()>
73    where
74        T: ?Sized + Serialize,
75    {
76        self.write_document(value.serialize(ValueSerializer)?)
77    }
78}
79
80#[derive(Debug)]
81pub enum SerValue {
82    Null,
83    Bool(bool),
84    Signed(i128),
85    Unsigned(u128),
86    Float(f64),
87    String(String),
88    Sequence(Vec<SerValue>),
89    Mapping(Vec<(SerValue, SerValue)>),
90    Tagged(String, Box<SerValue>),
91}
92
93struct ValueSerializer;
94
95impl ser::Serializer for ValueSerializer {
96    type Ok = SerValue;
97    type Error = Error;
98    type SerializeSeq = ValueSequence;
99    type SerializeTuple = ValueSequence;
100    type SerializeTupleStruct = ValueSequence;
101    type SerializeTupleVariant = ValueSequence;
102    type SerializeMap = ValueMapping;
103    type SerializeStruct = ValueMapping;
104    type SerializeStructVariant = ValueMapping;
105
106    fn serialize_bool(self, value: bool) -> Result<SerValue> {
107        Ok(SerValue::Bool(value))
108    }
109    fn serialize_i8(self, value: i8) -> Result<SerValue> {
110        self.serialize_i128(value.into())
111    }
112    fn serialize_i16(self, value: i16) -> Result<SerValue> {
113        self.serialize_i128(value.into())
114    }
115    fn serialize_i32(self, value: i32) -> Result<SerValue> {
116        self.serialize_i128(value.into())
117    }
118    fn serialize_i64(self, value: i64) -> Result<SerValue> {
119        self.serialize_i128(value.into())
120    }
121    fn serialize_i128(self, value: i128) -> Result<SerValue> {
122        Ok(SerValue::Signed(value))
123    }
124    fn serialize_u8(self, value: u8) -> Result<SerValue> {
125        self.serialize_u128(value.into())
126    }
127    fn serialize_u16(self, value: u16) -> Result<SerValue> {
128        self.serialize_u128(value.into())
129    }
130    fn serialize_u32(self, value: u32) -> Result<SerValue> {
131        self.serialize_u128(value.into())
132    }
133    fn serialize_u64(self, value: u64) -> Result<SerValue> {
134        self.serialize_u128(value.into())
135    }
136    fn serialize_u128(self, value: u128) -> Result<SerValue> {
137        Ok(SerValue::Unsigned(value))
138    }
139    fn serialize_f32(self, value: f32) -> Result<SerValue> {
140        Ok(SerValue::Float(value.into()))
141    }
142    fn serialize_f64(self, value: f64) -> Result<SerValue> {
143        Ok(SerValue::Float(value))
144    }
145    fn serialize_char(self, value: char) -> Result<SerValue> {
146        Ok(SerValue::String(value.to_string()))
147    }
148    fn serialize_str(self, value: &str) -> Result<SerValue> {
149        Ok(SerValue::String(value.to_owned()))
150    }
151    fn serialize_bytes(self, _value: &[u8]) -> Result<SerValue> {
152        Err(Error::message(
153            "serialization and deserialization of bytes in YAML is not implemented",
154        ))
155    }
156    fn serialize_none(self) -> Result<SerValue> {
157        Ok(SerValue::Null)
158    }
159    fn serialize_some<T>(self, value: &T) -> Result<SerValue>
160    where
161        T: ?Sized + Serialize,
162    {
163        value.serialize(self)
164    }
165    fn serialize_unit(self) -> Result<SerValue> {
166        Ok(SerValue::Null)
167    }
168    fn serialize_unit_struct(self, _name: &'static str) -> Result<SerValue> {
169        Ok(SerValue::Null)
170    }
171    fn serialize_unit_variant(
172        self,
173        _name: &'static str,
174        _index: u32,
175        variant: &'static str,
176    ) -> Result<SerValue> {
177        Ok(SerValue::String(variant.to_owned()))
178    }
179    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<SerValue>
180    where
181        T: ?Sized + Serialize,
182    {
183        value.serialize(self)
184    }
185    fn serialize_newtype_variant<T>(
186        self,
187        _name: &'static str,
188        _index: u32,
189        variant: &'static str,
190        value: &T,
191    ) -> Result<SerValue>
192    where
193        T: ?Sized + Serialize,
194    {
195        let value = value.serialize(self)?;
196        if matches!(value, SerValue::Tagged(..)) {
197            return Err(Error::message(
198                "serializing nested enums in YAML is not supported",
199            ));
200        }
201        Ok(SerValue::Tagged(variant.to_owned(), Box::new(value)))
202    }
203    fn serialize_seq(self, len: Option<usize>) -> Result<ValueSequence> {
204        Ok(ValueSequence::new(len, None))
205    }
206    fn serialize_tuple(self, len: usize) -> Result<ValueSequence> {
207        Ok(ValueSequence::new(Some(len), None))
208    }
209    fn serialize_tuple_struct(self, _name: &'static str, len: usize) -> Result<ValueSequence> {
210        Ok(ValueSequence::new(Some(len), None))
211    }
212    fn serialize_tuple_variant(
213        self,
214        _name: &'static str,
215        _index: u32,
216        variant: &'static str,
217        len: usize,
218    ) -> Result<ValueSequence> {
219        Ok(ValueSequence::new(Some(len), Some(variant.to_owned())))
220    }
221    fn serialize_map(self, len: Option<usize>) -> Result<ValueMapping> {
222        Ok(ValueMapping::new(len, None))
223    }
224    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<ValueMapping> {
225        Ok(ValueMapping::new(Some(len), None))
226    }
227    fn serialize_struct_variant(
228        self,
229        _name: &'static str,
230        _index: u32,
231        variant: &'static str,
232        len: usize,
233    ) -> Result<ValueMapping> {
234        Ok(ValueMapping::new(Some(len), Some(variant.to_owned())))
235    }
236    fn collect_str<T>(self, value: &T) -> Result<SerValue>
237    where
238        T: ?Sized + std::fmt::Display,
239    {
240        Ok(SerValue::String(value.to_string()))
241    }
242    fn is_human_readable(&self) -> bool {
243        true
244    }
245}
246
247pub struct ValueSequence {
248    values: Vec<SerValue>,
249    tag: Option<String>,
250}
251
252impl ValueSequence {
253    fn new(len: Option<usize>, tag: Option<String>) -> Self {
254        Self {
255            values: Vec::with_capacity(len.unwrap_or(0)),
256            tag,
257        }
258    }
259
260    fn push<T>(&mut self, value: &T) -> Result<()>
261    where
262        T: ?Sized + Serialize,
263    {
264        self.values.push(value.serialize(ValueSerializer)?);
265        Ok(())
266    }
267
268    fn finish(self) -> SerValue {
269        let value = SerValue::Sequence(self.values);
270        match self.tag {
271            Some(tag) => SerValue::Tagged(tag, Box::new(value)),
272            None => value,
273        }
274    }
275}
276
277impl ser::SerializeSeq for ValueSequence {
278    type Ok = SerValue;
279    type Error = Error;
280    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
281    where
282        T: ?Sized + Serialize,
283    {
284        self.push(value)
285    }
286    fn end(self) -> Result<SerValue> {
287        Ok(self.finish())
288    }
289}
290impl ser::SerializeTuple for ValueSequence {
291    type Ok = SerValue;
292    type Error = Error;
293    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
294    where
295        T: ?Sized + Serialize,
296    {
297        self.push(value)
298    }
299    fn end(self) -> Result<SerValue> {
300        Ok(self.finish())
301    }
302}
303impl ser::SerializeTupleStruct for ValueSequence {
304    type Ok = SerValue;
305    type Error = Error;
306    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
307    where
308        T: ?Sized + Serialize,
309    {
310        self.push(value)
311    }
312    fn end(self) -> Result<SerValue> {
313        Ok(self.finish())
314    }
315}
316impl ser::SerializeTupleVariant for ValueSequence {
317    type Ok = SerValue;
318    type Error = Error;
319    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
320    where
321        T: ?Sized + Serialize,
322    {
323        self.push(value)
324    }
325    fn end(self) -> Result<SerValue> {
326        Ok(self.finish())
327    }
328}
329
330pub struct ValueMapping {
331    entries: Vec<(SerValue, SerValue)>,
332    pending: Option<SerValue>,
333    tag: Option<String>,
334}
335
336impl ValueMapping {
337    fn new(len: Option<usize>, tag: Option<String>) -> Self {
338        Self {
339            entries: Vec::with_capacity(len.unwrap_or(0)),
340            pending: None,
341            tag,
342        }
343    }
344
345    fn finish(self) -> Result<SerValue> {
346        if self.pending.is_some() {
347            return Err(Error::message("map ended before serializing a value"));
348        }
349        let value = SerValue::Mapping(self.entries);
350        Ok(match self.tag {
351            Some(tag) => SerValue::Tagged(tag, Box::new(value)),
352            None => value,
353        })
354    }
355}
356
357impl ser::SerializeMap for ValueMapping {
358    type Ok = SerValue;
359    type Error = Error;
360    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
361    where
362        T: ?Sized + Serialize,
363    {
364        if self.pending.is_some() {
365            return Err(Error::message("map key serialized before its value"));
366        }
367        self.pending = Some(key.serialize(ValueSerializer)?);
368        Ok(())
369    }
370    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
371    where
372        T: ?Sized + Serialize,
373    {
374        let key = self
375            .pending
376            .take()
377            .ok_or_else(|| Error::message("map value serialized before its key"))?;
378        self.entries.push((key, value.serialize(ValueSerializer)?));
379        Ok(())
380    }
381    fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<()>
382    where
383        K: ?Sized + Serialize,
384        V: ?Sized + Serialize,
385    {
386        self.entries.push((
387            key.serialize(ValueSerializer)?,
388            value.serialize(ValueSerializer)?,
389        ));
390        Ok(())
391    }
392    fn end(self) -> Result<SerValue> {
393        self.finish()
394    }
395}
396
397impl ser::SerializeStruct for ValueMapping {
398    type Ok = SerValue;
399    type Error = Error;
400    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
401    where
402        T: ?Sized + Serialize,
403    {
404        self.entries.push((
405            SerValue::String(key.to_owned()),
406            value.serialize(ValueSerializer)?,
407        ));
408        Ok(())
409    }
410    fn end(self) -> Result<SerValue> {
411        self.finish()
412    }
413}
414
415impl ser::SerializeStructVariant for ValueMapping {
416    type Ok = SerValue;
417    type Error = Error;
418    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
419    where
420        T: ?Sized + Serialize,
421    {
422        self.entries.push((
423            SerValue::String(key.to_owned()),
424            value.serialize(ValueSerializer)?,
425        ));
426        Ok(())
427    }
428    fn end(self) -> Result<SerValue> {
429        self.finish()
430    }
431}
432
433pub enum DocumentSequence<'a, W> {
434    Sequence {
435        serializer: &'a mut Serializer<W>,
436        values: ValueSequence,
437    },
438    Mapping {
439        serializer: &'a mut Serializer<W>,
440        values: ValueMapping,
441    },
442}
443
444impl<'a, W: Write> DocumentSequence<'a, W> {
445    fn sequence(
446        serializer: &'a mut Serializer<W>,
447        len: Option<usize>,
448        tag: Option<String>,
449    ) -> Self {
450        Self::Sequence {
451            serializer,
452            values: ValueSequence::new(len, tag),
453        }
454    }
455    fn mapping(serializer: &'a mut Serializer<W>, len: Option<usize>, tag: Option<String>) -> Self {
456        Self::Mapping {
457            serializer,
458            values: ValueMapping::new(len, tag),
459        }
460    }
461}
462
463impl<W: Write> ser::SerializeSeq for DocumentSequence<'_, W> {
464    type Ok = ();
465    type Error = Error;
466    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
467    where
468        T: ?Sized + Serialize,
469    {
470        match self {
471            Self::Sequence { values, .. } => values.push(value),
472            _ => unreachable!(),
473        }
474    }
475    fn end(self) -> Result<()> {
476        match self {
477            Self::Sequence { serializer, values } => serializer.write_document(values.finish()),
478            _ => unreachable!(),
479        }
480    }
481}
482impl<W: Write> ser::SerializeTuple for DocumentSequence<'_, W> {
483    type Ok = ();
484    type Error = Error;
485    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
486    where
487        T: ?Sized + Serialize,
488    {
489        ser::SerializeSeq::serialize_element(self, value)
490    }
491    fn end(self) -> Result<()> {
492        ser::SerializeSeq::end(self)
493    }
494}
495impl<W: Write> ser::SerializeTupleStruct for DocumentSequence<'_, W> {
496    type Ok = ();
497    type Error = Error;
498    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
499    where
500        T: ?Sized + Serialize,
501    {
502        ser::SerializeSeq::serialize_element(self, value)
503    }
504    fn end(self) -> Result<()> {
505        ser::SerializeSeq::end(self)
506    }
507}
508impl<W: Write> ser::SerializeTupleVariant for DocumentSequence<'_, W> {
509    type Ok = ();
510    type Error = Error;
511    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
512    where
513        T: ?Sized + Serialize,
514    {
515        ser::SerializeSeq::serialize_element(self, value)
516    }
517    fn end(self) -> Result<()> {
518        ser::SerializeSeq::end(self)
519    }
520}
521impl<W: Write> ser::SerializeMap for DocumentSequence<'_, W> {
522    type Ok = ();
523    type Error = Error;
524    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
525    where
526        T: ?Sized + Serialize,
527    {
528        match self {
529            Self::Mapping { values, .. } => ser::SerializeMap::serialize_key(values, key),
530            _ => unreachable!(),
531        }
532    }
533    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
534    where
535        T: ?Sized + Serialize,
536    {
537        match self {
538            Self::Mapping { values, .. } => ser::SerializeMap::serialize_value(values, value),
539            _ => unreachable!(),
540        }
541    }
542    fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<()>
543    where
544        K: ?Sized + Serialize,
545        V: ?Sized + Serialize,
546    {
547        match self {
548            Self::Mapping { values, .. } => ser::SerializeMap::serialize_entry(values, key, value),
549            _ => unreachable!(),
550        }
551    }
552    fn end(self) -> Result<()> {
553        match self {
554            Self::Mapping { serializer, values } => serializer.write_document(values.finish()?),
555            _ => unreachable!(),
556        }
557    }
558}
559impl<W: Write> ser::SerializeStruct for DocumentSequence<'_, W> {
560    type Ok = ();
561    type Error = Error;
562    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
563    where
564        T: ?Sized + Serialize,
565    {
566        match self {
567            Self::Mapping { values, .. } => {
568                ser::SerializeStruct::serialize_field(values, key, value)
569            }
570            _ => unreachable!(),
571        }
572    }
573    fn end(self) -> Result<()> {
574        ser::SerializeMap::end(self)
575    }
576}
577impl<W: Write> ser::SerializeStructVariant for DocumentSequence<'_, W> {
578    type Ok = ();
579    type Error = Error;
580    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
581    where
582        T: ?Sized + Serialize,
583    {
584        match self {
585            Self::Mapping { values, .. } => {
586                ser::SerializeStruct::serialize_field(values, key, value)
587            }
588            _ => unreachable!(),
589        }
590    }
591    fn end(self) -> Result<()> {
592        ser::SerializeMap::end(self)
593    }
594}
595
596impl<'a, W> ser::Serializer for &'a mut Serializer<W>
597where
598    W: Write,
599{
600    type Ok = ();
601    type Error = Error;
602    type SerializeSeq = DocumentSequence<'a, W>;
603    type SerializeTuple = DocumentSequence<'a, W>;
604    type SerializeTupleStruct = DocumentSequence<'a, W>;
605    type SerializeTupleVariant = DocumentSequence<'a, W>;
606    type SerializeMap = DocumentSequence<'a, W>;
607    type SerializeStruct = DocumentSequence<'a, W>;
608    type SerializeStructVariant = DocumentSequence<'a, W>;
609
610    fn serialize_bool(self, value: bool) -> Result<()> {
611        self.write_document(SerValue::Bool(value))
612    }
613    fn serialize_i8(self, value: i8) -> Result<()> {
614        self.serialize_i128(value.into())
615    }
616    fn serialize_i16(self, value: i16) -> Result<()> {
617        self.serialize_i128(value.into())
618    }
619    fn serialize_i32(self, value: i32) -> Result<()> {
620        self.serialize_i128(value.into())
621    }
622    fn serialize_i64(self, value: i64) -> Result<()> {
623        self.serialize_i128(value.into())
624    }
625    fn serialize_i128(self, value: i128) -> Result<()> {
626        self.write_document(SerValue::Signed(value))
627    }
628    fn serialize_u8(self, value: u8) -> Result<()> {
629        self.serialize_u128(value.into())
630    }
631    fn serialize_u16(self, value: u16) -> Result<()> {
632        self.serialize_u128(value.into())
633    }
634    fn serialize_u32(self, value: u32) -> Result<()> {
635        self.serialize_u128(value.into())
636    }
637    fn serialize_u64(self, value: u64) -> Result<()> {
638        self.serialize_u128(value.into())
639    }
640    fn serialize_u128(self, value: u128) -> Result<()> {
641        self.write_document(SerValue::Unsigned(value))
642    }
643    fn serialize_f32(self, value: f32) -> Result<()> {
644        self.write_document(SerValue::Float(value.into()))
645    }
646    fn serialize_f64(self, value: f64) -> Result<()> {
647        self.write_document(SerValue::Float(value))
648    }
649    fn serialize_char(self, value: char) -> Result<()> {
650        self.write_document(SerValue::String(value.to_string()))
651    }
652    fn serialize_str(self, value: &str) -> Result<()> {
653        self.write_document(SerValue::String(value.to_owned()))
654    }
655    fn serialize_bytes(self, _value: &[u8]) -> Result<()> {
656        Err(Error::message(
657            "serialization and deserialization of bytes in YAML is not implemented",
658        ))
659    }
660    fn serialize_none(self) -> Result<()> {
661        self.write_document(SerValue::Null)
662    }
663    fn serialize_some<T>(self, value: &T) -> Result<()>
664    where
665        T: ?Sized + Serialize,
666    {
667        self.collect(value)
668    }
669    fn serialize_unit(self) -> Result<()> {
670        self.write_document(SerValue::Null)
671    }
672    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
673        self.serialize_unit()
674    }
675    fn serialize_unit_variant(
676        self,
677        _name: &'static str,
678        _index: u32,
679        variant: &'static str,
680    ) -> Result<()> {
681        self.write_document(SerValue::String(variant.to_owned()))
682    }
683    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
684    where
685        T: ?Sized + Serialize,
686    {
687        self.collect(value)
688    }
689    fn serialize_newtype_variant<T>(
690        self,
691        _name: &'static str,
692        _index: u32,
693        variant: &'static str,
694        value: &T,
695    ) -> Result<()>
696    where
697        T: ?Sized + Serialize,
698    {
699        let value = value.serialize(ValueSerializer)?;
700        if matches!(value, SerValue::Tagged(..)) {
701            return Err(Error::message(
702                "serializing nested enums in YAML is not supported",
703            ));
704        }
705        self.write_document(SerValue::Tagged(variant.to_owned(), Box::new(value)))
706    }
707    fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
708        Ok(DocumentSequence::sequence(self, len, None))
709    }
710    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
711        Ok(DocumentSequence::sequence(self, Some(len), None))
712    }
713    fn serialize_tuple_struct(
714        self,
715        _name: &'static str,
716        len: usize,
717    ) -> Result<Self::SerializeTupleStruct> {
718        Ok(DocumentSequence::sequence(self, Some(len), None))
719    }
720    fn serialize_tuple_variant(
721        self,
722        _name: &'static str,
723        _index: u32,
724        variant: &'static str,
725        len: usize,
726    ) -> Result<Self::SerializeTupleVariant> {
727        Ok(DocumentSequence::sequence(
728            self,
729            Some(len),
730            Some(variant.to_owned()),
731        ))
732    }
733    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
734        Ok(DocumentSequence::mapping(self, len, None))
735    }
736    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
737        Ok(DocumentSequence::mapping(self, Some(len), None))
738    }
739    fn serialize_struct_variant(
740        self,
741        _name: &'static str,
742        _index: u32,
743        variant: &'static str,
744        len: usize,
745    ) -> Result<Self::SerializeStructVariant> {
746        Ok(DocumentSequence::mapping(
747            self,
748            Some(len),
749            Some(variant.to_owned()),
750        ))
751    }
752    fn collect_str<T>(self, value: &T) -> Result<()>
753    where
754        T: ?Sized + std::fmt::Display,
755    {
756        self.serialize_str(&value.to_string())
757    }
758    fn is_human_readable(&self) -> bool {
759        true
760    }
761}
762
763fn render_value(value: &SerValue, indent: usize, output: &mut String) {
764    match value {
765        SerValue::Null
766        | SerValue::Bool(_)
767        | SerValue::Signed(_)
768        | SerValue::Unsigned(_)
769        | SerValue::Float(_)
770        | SerValue::String(_) => {
771            push_indent(output, indent);
772            render_scalar(value, output);
773        }
774        SerValue::Sequence(values) => render_sequence(values, indent, output),
775        SerValue::Mapping(entries) => render_mapping(entries, indent, output),
776        SerValue::Tagged(tag, inner) => {
777            push_indent(output, indent);
778            output.push('!');
779            output.push_str(tag);
780            if is_inline(inner) {
781                output.push(' ');
782                render_inline(inner, output);
783            } else {
784                output.push('\n');
785                render_value(inner, indent, output);
786            }
787        }
788    }
789}
790
791fn render_sequence(values: &[SerValue], indent: usize, output: &mut String) {
792    if values.is_empty() {
793        push_indent(output, indent);
794        output.push_str("[]");
795        return;
796    }
797    for (index, value) in values.iter().enumerate() {
798        if index > 0 {
799            output.push('\n');
800        }
801        push_indent(output, indent);
802        output.push('-');
803        render_nested(value, indent + 2, output);
804    }
805}
806
807fn render_mapping(entries: &[(SerValue, SerValue)], indent: usize, output: &mut String) {
808    if entries.is_empty() {
809        push_indent(output, indent);
810        output.push_str("{}");
811        return;
812    }
813    for (index, (key, value)) in entries.iter().enumerate() {
814        if index > 0 {
815            output.push('\n');
816        }
817        if is_inline(key) {
818            push_indent(output, indent);
819            render_inline(key, output);
820            output.push(':');
821        } else {
822            push_indent(output, indent);
823            output.push('?');
824            render_nested(key, indent + 2, output);
825            output.push('\n');
826            push_indent(output, indent);
827            output.push(':');
828        }
829        render_nested(value, indent + 2, output);
830    }
831}
832
833fn render_nested(value: &SerValue, indent: usize, output: &mut String) {
834    match value {
835        SerValue::Tagged(tag, inner) if !is_inline(inner) => {
836            output.push(' ');
837            output.push('!');
838            output.push_str(tag);
839            output.push('\n');
840            render_value(inner, indent, output);
841        }
842        _ if is_inline(value) => {
843            output.push(' ');
844            render_inline(value, output);
845        }
846        _ => {
847            output.push('\n');
848            render_value(value, indent, output);
849        }
850    }
851}
852
853fn is_inline(value: &SerValue) -> bool {
854    matches!(
855        value,
856        SerValue::Null
857            | SerValue::Bool(_)
858            | SerValue::Signed(_)
859            | SerValue::Unsigned(_)
860            | SerValue::Float(_)
861            | SerValue::String(_)
862    ) || matches!(value, SerValue::Sequence(values) if values.is_empty())
863        || matches!(value, SerValue::Mapping(entries) if entries.is_empty())
864        || matches!(value, SerValue::Tagged(_, inner) if is_inline(inner))
865}
866
867fn render_inline(value: &SerValue, output: &mut String) {
868    match value {
869        SerValue::Sequence(values) if values.is_empty() => output.push_str("[]"),
870        SerValue::Mapping(entries) if entries.is_empty() => output.push_str("{}"),
871        SerValue::Tagged(tag, inner) => {
872            output.push('!');
873            output.push_str(tag);
874            output.push(' ');
875            render_inline(inner, output);
876        }
877        _ => render_scalar(value, output),
878    }
879}
880
881fn render_scalar(value: &SerValue, output: &mut String) {
882    match value {
883        SerValue::Null => output.push_str("null"),
884        SerValue::Bool(value) => output.push_str(if *value { "true" } else { "false" }),
885        SerValue::Signed(value) => output.push_str(&value.to_string()),
886        SerValue::Unsigned(value) => output.push_str(&value.to_string()),
887        SerValue::Float(value) => render_float(*value, output),
888        SerValue::String(value) => render_string(value, output),
889        _ => unreachable!("collections are not scalars"),
890    }
891}
892
893fn render_float(value: f64, output: &mut String) {
894    if value.is_nan() {
895        output.push_str(".nan");
896    } else if value == f64::INFINITY {
897        output.push_str(".inf");
898    } else if value == f64::NEG_INFINITY {
899        output.push_str("-.inf");
900    } else {
901        let text = value.to_string();
902        output.push_str(&text);
903        if !text.contains(['.', 'e', 'E']) {
904            output.push_str(".0");
905        }
906    }
907}
908
909fn render_string(value: &str, output: &mut String) {
910    if is_safe_plain(value) {
911        output.push_str(value);
912        return;
913    }
914    output.push('"');
915    for character in value.chars() {
916        match character {
917            '"' => output.push_str("\\\""),
918            '\\' => output.push_str("\\\\"),
919            '\n' => output.push_str("\\n"),
920            '\r' => output.push_str("\\r"),
921            '\t' => output.push_str("\\t"),
922            '\u{08}' => output.push_str("\\b"),
923            '\u{0C}' => output.push_str("\\f"),
924            character if character.is_control() => {
925                use std::fmt::Write as _;
926                let _ = write!(output, "\\u{:04X}", character as u32);
927            }
928            character => output.push(character),
929        }
930    }
931    output.push('"');
932}
933
934fn is_safe_plain(value: &str) -> bool {
935    if value.is_empty() || value.trim() != value || value.contains(['\n', '\r', '\t']) {
936        return false;
937    }
938    if value.starts_with([
939        '-', '?', ':', ',', '[', ']', '{', '}', '#', '&', '*', '!', '|', '>', '\'', '"', '%', '@',
940        '`',
941    ]) {
942        return false;
943    }
944    if value.contains(": ") || value.contains(" #") || value == "---" || value == "..." {
945        return false;
946    }
947    if matches!(
948        value,
949        "~" | "null"
950            | "Null"
951            | "NULL"
952            | "true"
953            | "True"
954            | "TRUE"
955            | "false"
956            | "False"
957            | "FALSE"
958            | ".inf"
959            | ".Inf"
960            | ".INF"
961            | "-.inf"
962            | "-.Inf"
963            | "-.INF"
964            | ".nan"
965            | ".NaN"
966            | ".NAN"
967    ) {
968        return false;
969    }
970    !looks_numeric(value)
971}
972
973fn looks_numeric(value: &str) -> bool {
974    let value = value.replace('_', "");
975    let unsigned = value.strip_prefix(['+', '-']).unwrap_or(&value);
976    if unsigned
977        .strip_prefix("0x")
978        .is_some_and(|v| !v.is_empty() && v.chars().all(|c| c.is_ascii_hexdigit()))
979    {
980        return true;
981    }
982    if unsigned
983        .strip_prefix("0o")
984        .is_some_and(|v| !v.is_empty() && v.chars().all(|c| matches!(c, '0'..='7')))
985    {
986        return true;
987    }
988    if unsigned
989        .strip_prefix("0b")
990        .is_some_and(|v| !v.is_empty() && v.chars().all(|c| matches!(c, '0' | '1')))
991    {
992        return true;
993    }
994    value.parse::<i128>().is_ok() || value.parse::<u128>().is_ok() || value.parse::<f64>().is_ok()
995}
996
997fn push_indent(output: &mut String, indent: usize) {
998    output.extend(std::iter::repeat_n(' ', indent));
999}