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