1use std::io::Write;
2
3use serde::{Serialize, ser};
4
5use crate::{Error, Result};
6
7pub 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
21pub 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
35pub struct Serializer<W> {
37 writer: W,
38 documents: usize,
39}
40
41impl<W> Serializer<W>
42where
43 W: Write,
44{
45 pub const fn new(writer: W) -> Self {
47 Self {
48 writer,
49 documents: 0,
50 }
51 }
52
53 pub fn flush(&mut self) -> Result<()> {
59 self.writer.flush().map_err(Error::io)
60 }
61
62 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}