Skip to main content

serde_structprop/
ser.rs

1//! Serde [`Serializer`](serde::Serializer) for the structprop format.
2//!
3//! The public entry point is [`to_string`].  Internally a `Serializer` walks
4//! the serde data model and writes structprop text directly into an output
5//! [`String`].
6//!
7//! # Type mapping
8//!
9//! | Rust / serde | Structprop output |
10//! |---|---|
11//! | `bool` | `true` or `false` scalar |
12//! | `i8`–`i64`, `u8`–`u64` | bare integer scalar (e.g. `42`, `-7`) |
13//! | `f32`, `f64` | bare float scalar (e.g. `3.14`) |
14//! | `char` | bare single-character scalar (quoted if the character is special) |
15//! | `String` / `&str` | bare scalar, or `"quoted"` if it contains spaces, tabs, newlines, carriage returns, `#`, `{`, `}`, or `=`, or is empty; yields `Error::UnsupportedType` if the value requires quoting and contains `"`, or if the value starts with `"` |
16//! | `None` / `()` / unit struct | `null` scalar |
17//! | newtype struct | transparent — serializes as the inner value |
18//! | struct / map | `key { … }` block at the current indentation level |
19//! | `Vec<T>` / sequence / tuple / tuple struct | `= { … }` inline list |
20//! | unit enum variant | bare variant name scalar |
21//! | newtype enum variant | `variant_name = <scalar or list>` |
22//! | tuple enum variant | `variant_name = { … }` list |
23//! | struct enum variant | `variant_name { … }` block |
24
25use std::fmt::Write as FmtWrite;
26
27use crate::error::{Error, Result};
28use serde::ser::{self, Serialize};
29
30// ---------------------------------------------------------------------------
31// Public entry point
32// ---------------------------------------------------------------------------
33
34/// Serialize `value` into a structprop-formatted [`String`].
35///
36/// Top-level structs and maps produce a flat sequence of `key = value` /
37/// `key { … }` entries with no enclosing braces.  Sequences produce a bare
38/// `{\n … \n}` block.
39///
40/// # Errors
41///
42/// Returns [`Error::UnsupportedType`] if `T` contains raw byte slices, or
43/// [`Error::Message`] for any other serde-level serialization error.
44///
45/// # Examples
46///
47/// ```
48/// use serde::Serialize;
49/// use serde_structprop::to_string;
50///
51/// #[derive(Serialize)]
52/// struct Cfg { host: String, port: u16 }
53///
54/// let s = to_string(&Cfg { host: "localhost".into(), port: 8080 }).unwrap();
55/// assert!(s.contains("host = localhost"));
56/// assert!(s.contains("port = 8080"));
57/// ```
58pub fn to_string<T: Serialize>(value: &T) -> Result<String> {
59    let mut ser = Serializer::new(0);
60    value.serialize(&mut ser)?;
61    Ok(ser.output)
62}
63
64// ---------------------------------------------------------------------------
65// Serializer
66// ---------------------------------------------------------------------------
67
68/// Core serializer that accumulates structprop text in `output`.
69///
70/// `indent` is the current nesting depth; each level adds two spaces of
71/// leading whitespace to each emitted line.
72pub struct Serializer {
73    /// The accumulated output string.
74    pub(crate) output: String,
75    /// Current indentation level in spaces.
76    indent: usize,
77    /// Set to `true` when the top-level call was `serialize_struct` or
78    /// `serialize_map`.  Used by [`SeqSerializer`] to distinguish object
79    /// items (which must be wrapped in inner `{ … }` braces) from scalars.
80    is_object: bool,
81}
82
83impl Serializer {
84    /// Create a new [`Serializer`] starting at `indent` spaces of indentation.
85    fn new(indent: usize) -> Self {
86        Serializer {
87            output: String::new(),
88            indent,
89            is_object: false,
90        }
91    }
92
93    /// Return a string of `self.indent` spaces.
94    fn pad(&self) -> String {
95        " ".repeat(self.indent)
96    }
97}
98
99// ---------------------------------------------------------------------------
100// Helpers
101// ---------------------------------------------------------------------------
102
103/// Wrap `s` in double quotes if it is empty or contains any of the following
104/// characters: space (` `), tab (`\t`), newline (`\n`), carriage return
105/// (`\r`), `#`, `{`, `}`, or `=`.  Otherwise return it unchanged.
106///
107/// Empty strings are always quoted so that they survive a round-trip: a bare
108/// empty value would produce `key = ` with no token after `=`, which the
109/// parser cannot recover from.
110///
111/// The structprop format has no escape sequences.  A `"` character that
112/// appears in the interior of a value (not as the first character) can
113/// survive as part of a bare (unquoted) term.  However two cases are
114/// unrepresentable and return [`Error::UnsupportedType`]:
115///
116/// * A value that **requires quoting** (contains a special character or is
117///   empty) **and also contains `"`** — there is no way to embed `"` inside
118///   a quoted term.
119/// * A value whose **first character is `"`** — the lexer always interprets
120///   a leading `"` as the start of a quoted term, so the value would be
121///   mis-parsed.
122///
123/// # Errors
124///
125/// Returns [`Error::UnsupportedType`] if `s` requires quoting and also
126/// contains a `"` character.
127fn escape(s: &str) -> Result<String> {
128    let needs_quoting = s.is_empty()
129        || s.starts_with('"')
130        || s.chars()
131            .any(|c| matches!(c, ' ' | '\t' | '\n' | '\r' | '#' | '{' | '}' | '='));
132
133    if needs_quoting && s.contains('"') {
134        return Err(Error::UnsupportedType(
135            "string containing '\"' cannot be represented in quoted form (format has no escape sequences)",
136        ));
137    }
138
139    if needs_quoting {
140        Ok(format!("\"{s}\""))
141    } else {
142        Ok(s.to_owned())
143    }
144}
145
146// ---------------------------------------------------------------------------
147// serde::Serializer impl
148// ---------------------------------------------------------------------------
149
150impl<'a> ser::Serializer for &'a mut Serializer {
151    type Ok = ();
152    type Error = Error;
153
154    /// Compound serializer types.
155    type SerializeSeq = SeqSerializer<'a>;
156    /// Compound serializer types.
157    type SerializeTuple = SeqSerializer<'a>;
158    /// Compound serializer types.
159    type SerializeTupleStruct = SeqSerializer<'a>;
160    /// Compound serializer types.
161    type SerializeTupleVariant = SeqSerializer<'a>;
162    /// Compound serializer types.
163    type SerializeMap = MapSerializer<'a>;
164    /// Compound serializer types.
165    type SerializeStruct = MapSerializer<'a>;
166    /// Compound serializer types.
167    type SerializeStructVariant = MapSerializer<'a>;
168
169    fn serialize_bool(self, v: bool) -> Result<()> {
170        self.output.push_str(if v { "true" } else { "false" });
171        Ok(())
172    }
173
174    fn serialize_i8(self, v: i8) -> Result<()> {
175        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
176    }
177
178    fn serialize_i16(self, v: i16) -> Result<()> {
179        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
180    }
181
182    fn serialize_i32(self, v: i32) -> Result<()> {
183        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
184    }
185
186    fn serialize_i64(self, v: i64) -> Result<()> {
187        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
188    }
189
190    fn serialize_u8(self, v: u8) -> Result<()> {
191        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
192    }
193
194    fn serialize_u16(self, v: u16) -> Result<()> {
195        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
196    }
197
198    fn serialize_u32(self, v: u32) -> Result<()> {
199        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
200    }
201
202    fn serialize_u64(self, v: u64) -> Result<()> {
203        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
204    }
205
206    fn serialize_f32(self, v: f32) -> Result<()> {
207        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
208    }
209
210    fn serialize_f64(self, v: f64) -> Result<()> {
211        write!(self.output, "{v}").map_err(|e| Error::Message(e.to_string()))
212    }
213
214    fn serialize_char(self, v: char) -> Result<()> {
215        // Route through escape() so special characters are quoted.
216        self.output.push_str(&escape(&v.to_string())?);
217        Ok(())
218    }
219
220    fn serialize_str(self, v: &str) -> Result<()> {
221        self.output.push_str(&escape(v)?);
222        Ok(())
223    }
224
225    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
226        Err(Error::UnsupportedType("bytes"))
227    }
228
229    fn serialize_none(self) -> Result<()> {
230        self.output.push_str("null");
231        Ok(())
232    }
233
234    fn serialize_some<T: Serialize + ?Sized>(self, value: &T) -> Result<()> {
235        value.serialize(self)
236    }
237
238    fn serialize_unit(self) -> Result<()> {
239        self.output.push_str("null");
240        Ok(())
241    }
242
243    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
244        self.serialize_unit()
245    }
246
247    fn serialize_unit_variant(
248        self,
249        _name: &'static str,
250        _index: u32,
251        variant: &'static str,
252    ) -> Result<()> {
253        self.serialize_str(variant)
254    }
255
256    fn serialize_newtype_struct<T: Serialize + ?Sized>(
257        self,
258        _name: &'static str,
259        value: &T,
260    ) -> Result<()> {
261        value.serialize(self)
262    }
263
264    fn serialize_newtype_variant<T: Serialize + ?Sized>(
265        self,
266        _name: &'static str,
267        _index: u32,
268        variant: &'static str,
269        value: &T,
270    ) -> Result<()> {
271        // Encode as `variant = <payload>` (scalar) or `variant { … }` (object block)
272        // so the parser produces Object({"variant": payload}), which is exactly what
273        // deserialize_enum expects for newtype variants.
274        let start_pos = self.output.len();
275        let mut ms = MapSerializer {
276            ser: self,
277            current_key: None,
278            variant_name: None,
279            start_pos,
280        };
281        ms.write_kv(variant, value)
282    }
283
284    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
285        Ok(SeqSerializer {
286            parent: self,
287            items: Vec::new(),
288            variant: None,
289        })
290    }
291
292    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
293        self.serialize_seq(Some(len))
294    }
295
296    fn serialize_tuple_struct(
297        self,
298        _name: &'static str,
299        len: usize,
300    ) -> Result<Self::SerializeTupleStruct> {
301        self.serialize_seq(Some(len))
302    }
303
304    fn serialize_tuple_variant(
305        self,
306        _name: &'static str,
307        _index: u32,
308        variant: &'static str,
309        _len: usize,
310    ) -> Result<Self::SerializeTupleVariant> {
311        Ok(SeqSerializer {
312            parent: self,
313            items: Vec::new(),
314            variant: Some(variant.to_owned()),
315        })
316    }
317
318    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
319        self.is_object = true;
320        let start_pos = self.output.len();
321        Ok(MapSerializer {
322            ser: self,
323            current_key: None,
324            variant_name: None,
325            start_pos,
326        })
327    }
328
329    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
330        self.serialize_map(Some(len))
331    }
332
333    fn serialize_struct_variant(
334        self,
335        _name: &'static str,
336        _index: u32,
337        variant: &'static str,
338        _len: usize,
339    ) -> Result<Self::SerializeStructVariant> {
340        let start_pos = self.output.len();
341        // Fields inside the variant wrapper must sit two levels deeper than the
342        // wrapper header itself, so bump indent before handing `self` over to
343        // the MapSerializer.  `end()` will derive the header/footer pad from
344        // `ser.indent.saturating_sub(2)`, which then equals the original indent.
345        self.indent += 2;
346        Ok(MapSerializer {
347            ser: self,
348            current_key: None,
349            variant_name: Some(variant.to_owned()),
350            start_pos,
351        })
352    }
353}
354
355// ---------------------------------------------------------------------------
356// SeqSerializer – handles sequences / arrays
357// ---------------------------------------------------------------------------
358
359/// [`ser::SerializeSeq`] (and related tuple impls) that collects rendered items
360/// then emits them as a `{ … }` block.
361pub struct SeqSerializer<'a> {
362    parent: &'a mut Serializer,
363    /// Each element serialized to a string plus a flag indicating whether it
364    /// is a struct/map (object) that needs wrapping in inner `{ … }` braces.
365    items: Vec<(bool, String)>,
366    /// Set for tuple variants: the variant name to wrap the array under.
367    variant: Option<String>,
368}
369
370impl ser::SerializeSeq for SeqSerializer<'_> {
371    type Ok = ();
372    type Error = Error;
373
374    fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
375        let mut inner = Serializer::new(0);
376        value.serialize(&mut inner)?;
377        self.items.push((inner.is_object, inner.output));
378        Ok(())
379    }
380
381    fn end(self) -> Result<()> {
382        let pad = self.parent.pad();
383        let inner_pad = " ".repeat(self.parent.indent + 2);
384        let deep_pad = " ".repeat(self.parent.indent + 4);
385        writeln!(self.parent.output, "{{").map_err(|e| Error::Message(e.to_string()))?;
386        for (is_object, item) in &self.items {
387            let trimmed = item.trim_end();
388            if *is_object {
389                // Struct/map item: wrap in inner `{ … }` braces, indenting each
390                // field line by an extra two spaces (matching the Python reference).
391                writeln!(self.parent.output, "{inner_pad}{{")
392                    .map_err(|e| Error::Message(e.to_string()))?;
393                for line in trimmed.lines() {
394                    writeln!(self.parent.output, "{deep_pad}{line}")
395                        .map_err(|e| Error::Message(e.to_string()))?;
396                }
397                writeln!(self.parent.output, "{inner_pad}}}")
398                    .map_err(|e| Error::Message(e.to_string()))?;
399            } else {
400                // Scalar item: emit on a single indented line.
401                writeln!(self.parent.output, "{inner_pad}{trimmed}")
402                    .map_err(|e| Error::Message(e.to_string()))?;
403            }
404        }
405        writeln!(self.parent.output, "{pad}}}").map_err(|e| Error::Message(e.to_string()))
406    }
407}
408
409impl ser::SerializeTuple for SeqSerializer<'_> {
410    type Ok = ();
411    type Error = Error;
412
413    fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
414        ser::SerializeSeq::serialize_element(self, value)
415    }
416
417    fn end(self) -> Result<()> {
418        ser::SerializeSeq::end(self)
419    }
420}
421
422impl ser::SerializeTupleStruct for SeqSerializer<'_> {
423    type Ok = ();
424    type Error = Error;
425
426    fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
427        ser::SerializeSeq::serialize_element(self, value)
428    }
429
430    fn end(self) -> Result<()> {
431        ser::SerializeSeq::end(self)
432    }
433}
434
435impl ser::SerializeTupleVariant for SeqSerializer<'_> {
436    type Ok = ();
437    type Error = Error;
438
439    fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
440        ser::SerializeSeq::serialize_element(self, value)
441    }
442
443    fn end(self) -> Result<()> {
444        // Emit as `variant = { item1\n  item2\n … }` so the parser produces
445        // Object({"variant": Array([…])}), matching what deserialize_enum expects.
446        let variant = self.variant.ok_or_else(|| {
447            Error::Message("variant name missing in SerializeTupleVariant::end".into())
448        })?;
449        let pad = self.parent.pad();
450        let inner_pad = " ".repeat(self.parent.indent + 2);
451        let deep_pad = " ".repeat(self.parent.indent + 4);
452        writeln!(self.parent.output, "{pad}{} = {{", escape(&variant)?)
453            .map_err(|e| Error::Message(e.to_string()))?;
454        for (is_object, item) in &self.items {
455            let trimmed = item.trim_end();
456            if *is_object {
457                writeln!(self.parent.output, "{inner_pad}{{")
458                    .map_err(|e| Error::Message(e.to_string()))?;
459                for line in trimmed.lines() {
460                    writeln!(self.parent.output, "{deep_pad}{line}")
461                        .map_err(|e| Error::Message(e.to_string()))?;
462                }
463                writeln!(self.parent.output, "{inner_pad}}}")
464                    .map_err(|e| Error::Message(e.to_string()))?;
465            } else {
466                writeln!(self.parent.output, "{inner_pad}{trimmed}")
467                    .map_err(|e| Error::Message(e.to_string()))?;
468            }
469        }
470        writeln!(self.parent.output, "{pad}}}").map_err(|e| Error::Message(e.to_string()))
471    }
472}
473
474// ---------------------------------------------------------------------------
475// KeySerializer – accepts only string keys; rejects everything else
476// ---------------------------------------------------------------------------
477
478/// A minimal serializer that collects a `str`/`String` map key and returns
479/// [`Error::KeyMustBeString`] for every other type, including `char` and
480/// unit-enum variants.  Only `serialize_str` (and `serialize_newtype_struct`
481/// delegating to it) succeed.
482struct KeySerializer(String);
483
484impl ser::Serializer for &mut KeySerializer {
485    type Ok = ();
486    type Error = Error;
487    type SerializeSeq = ser::Impossible<(), Error>;
488    type SerializeTuple = ser::Impossible<(), Error>;
489    type SerializeTupleStruct = ser::Impossible<(), Error>;
490    type SerializeTupleVariant = ser::Impossible<(), Error>;
491    type SerializeMap = ser::Impossible<(), Error>;
492    type SerializeStruct = ser::Impossible<(), Error>;
493    type SerializeStructVariant = ser::Impossible<(), Error>;
494
495    fn serialize_str(self, v: &str) -> Result<()> {
496        v.clone_into(&mut self.0);
497        Ok(())
498    }
499
500    fn serialize_bool(self, _v: bool) -> Result<()> {
501        Err(Error::KeyMustBeString)
502    }
503    fn serialize_i8(self, _v: i8) -> Result<()> {
504        Err(Error::KeyMustBeString)
505    }
506    fn serialize_i16(self, _v: i16) -> Result<()> {
507        Err(Error::KeyMustBeString)
508    }
509    fn serialize_i32(self, _v: i32) -> Result<()> {
510        Err(Error::KeyMustBeString)
511    }
512    fn serialize_i64(self, _v: i64) -> Result<()> {
513        Err(Error::KeyMustBeString)
514    }
515    fn serialize_u8(self, _v: u8) -> Result<()> {
516        Err(Error::KeyMustBeString)
517    }
518    fn serialize_u16(self, _v: u16) -> Result<()> {
519        Err(Error::KeyMustBeString)
520    }
521    fn serialize_u32(self, _v: u32) -> Result<()> {
522        Err(Error::KeyMustBeString)
523    }
524    fn serialize_u64(self, _v: u64) -> Result<()> {
525        Err(Error::KeyMustBeString)
526    }
527    fn serialize_f32(self, _v: f32) -> Result<()> {
528        Err(Error::KeyMustBeString)
529    }
530    fn serialize_f64(self, _v: f64) -> Result<()> {
531        Err(Error::KeyMustBeString)
532    }
533    fn serialize_char(self, _v: char) -> Result<()> {
534        Err(Error::KeyMustBeString)
535    }
536    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
537        Err(Error::KeyMustBeString)
538    }
539    fn serialize_none(self) -> Result<()> {
540        Err(Error::KeyMustBeString)
541    }
542    fn serialize_some<T: Serialize + ?Sized>(self, _v: &T) -> Result<()> {
543        Err(Error::KeyMustBeString)
544    }
545    fn serialize_unit(self) -> Result<()> {
546        Err(Error::KeyMustBeString)
547    }
548    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
549        Err(Error::KeyMustBeString)
550    }
551    fn serialize_unit_variant(
552        self,
553        _name: &'static str,
554        _idx: u32,
555        _variant: &'static str,
556    ) -> Result<()> {
557        Err(Error::KeyMustBeString)
558    }
559    fn serialize_newtype_struct<T: Serialize + ?Sized>(
560        self,
561        _name: &'static str,
562        value: &T,
563    ) -> Result<()> {
564        value.serialize(self)
565    }
566    fn serialize_newtype_variant<T: Serialize + ?Sized>(
567        self,
568        _name: &'static str,
569        _idx: u32,
570        _variant: &'static str,
571        _value: &T,
572    ) -> Result<()> {
573        Err(Error::KeyMustBeString)
574    }
575    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
576        Err(Error::KeyMustBeString)
577    }
578    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
579        Err(Error::KeyMustBeString)
580    }
581    fn serialize_tuple_struct(
582        self,
583        _name: &'static str,
584        _len: usize,
585    ) -> Result<Self::SerializeTupleStruct> {
586        Err(Error::KeyMustBeString)
587    }
588    fn serialize_tuple_variant(
589        self,
590        _name: &'static str,
591        _idx: u32,
592        _variant: &'static str,
593        _len: usize,
594    ) -> Result<Self::SerializeTupleVariant> {
595        Err(Error::KeyMustBeString)
596    }
597    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
598        Err(Error::KeyMustBeString)
599    }
600    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
601        Err(Error::KeyMustBeString)
602    }
603    fn serialize_struct_variant(
604        self,
605        _name: &'static str,
606        _idx: u32,
607        _variant: &'static str,
608        _len: usize,
609    ) -> Result<Self::SerializeStructVariant> {
610        Err(Error::KeyMustBeString)
611    }
612}
613
614// ---------------------------------------------------------------------------
615// MapSerializer – handles maps and structs
616// ---------------------------------------------------------------------------
617
618/// [`ser::SerializeMap`] (and struct impls) that writes `key = value` /
619/// `key { … }` entries one at a time.
620pub struct MapSerializer<'a> {
621    ser: &'a mut Serializer,
622    /// The most recently serialized key, waiting for its value.
623    current_key: Option<String>,
624    /// If `Some`, wrap all emitted content in a `variant_name { … }` block.
625    variant_name: Option<String>,
626    /// Byte offset into `ser.output` at which this value began being written.
627    /// Used by struct-variant serialization to insert the header at the correct
628    /// position rather than at the start of the entire output buffer.
629    start_pos: usize,
630}
631
632impl MapSerializer<'_> {
633    /// Serialize a single `key = value` or `key { … }` entry into `self.ser`.
634    fn write_kv<T: Serialize + ?Sized>(&mut self, key: &str, value: &T) -> Result<()> {
635        let indent = self.ser.indent;
636        let pad = " ".repeat(indent);
637
638        // Serialize the value at the *current* indentation level.  This single
639        // call is sufficient for scalars and for array blocks, whose output is
640        // already formatted correctly:
641        //
642        //   scalar  →  no newlines, used directly as the RHS of `key = value`
643        //   array   →  `{\n<items at indent+2>\n<indent>}\n`, written inline
644        //               as `key = {…}` by `writeln!` below
645        //
646        // Only struct/map (multi-line, not starting with `{` or `"`) needs the
647        // content indented two levels deeper than the current key, so we
648        // re-serialize those at `indent+2`.  This is the only case where
649        // `Serialize` is invoked twice.
650        let mut first = Serializer::new(indent);
651        value.serialize(&mut first)?;
652        let rendered = first.output;
653
654        if rendered.contains('\n')
655            && !rendered.trim_start().starts_with('{')
656            && !rendered.trim_start().starts_with('"')
657        {
658            // Multi-line object block → `key {\n  <fields at indent+2>\n}\n`
659            // Re-serialize at the correct child indentation so nested fields
660            // sit two levels deeper than the enclosing key.  We must not
661            // blindly re-indent the first-pass output line-by-line because
662            // doing so would corrupt any quoted scalar whose value contains a
663            // literal newline (the continuation line is not a separate field).
664            writeln!(self.ser.output, "{pad}{} {{", escape(key)?)
665                .map_err(|e| Error::Message(e.to_string()))?;
666            let mut inner = Serializer::new(indent + 2);
667            value.serialize(&mut inner)?;
668            self.ser.output.push_str(&inner.output);
669            writeln!(self.ser.output, "{pad}}}").map_err(|e| Error::Message(e.to_string()))?;
670        } else if rendered.contains('\n') {
671            // Multi-line array block starting with `{`.
672            // The first-pass output is already at the right indentation
673            // (`{` inline, items at `indent+2`, `}` at `indent`), so we
674            // reuse it without a second `serialize` call.
675            writeln!(
676                self.ser.output,
677                "{pad}{} = {}",
678                escape(key)?,
679                rendered.trim_end()
680            )
681            .map_err(|e| Error::Message(e.to_string()))?;
682        } else {
683            // Scalar (no newlines, or a quoted scalar — both fit on one line).
684            let rendered = rendered.trim_end_matches('\n');
685            writeln!(self.ser.output, "{pad}{} = {rendered}", escape(key)?)
686                .map_err(|e| Error::Message(e.to_string()))?;
687        }
688        Ok(())
689    }
690}
691
692impl ser::SerializeMap for MapSerializer<'_> {
693    type Ok = ();
694    type Error = Error;
695
696    fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<()> {
697        let mut ks = KeySerializer(String::new());
698        key.serialize(&mut ks)?;
699        self.current_key = Some(ks.0);
700        Ok(())
701    }
702
703    fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
704        let key = self
705            .current_key
706            .take()
707            .ok_or_else(|| Error::Parse("serialize_value called before serialize_key".into()))?;
708        self.write_kv(&key, value)
709    }
710
711    fn end(self) -> Result<()> {
712        if let Some(variant) = self.variant_name {
713            // Wrap the content we already wrote in `variant { … }`.
714            let pad = " ".repeat(self.ser.indent.saturating_sub(2));
715            let header = format!("{pad}{} {{\n", escape(&variant)?);
716            let footer = format!("{pad}}}\n");
717            self.ser.output.insert_str(self.start_pos, &header);
718            self.ser.output.push_str(&footer);
719        }
720        Ok(())
721    }
722}
723
724impl ser::SerializeStruct for MapSerializer<'_> {
725    type Ok = ();
726    type Error = Error;
727
728    fn serialize_field<T: Serialize + ?Sized>(
729        &mut self,
730        key: &'static str,
731        value: &T,
732    ) -> Result<()> {
733        self.write_kv(key, value)
734    }
735
736    fn end(self) -> Result<()> {
737        ser::SerializeMap::end(self)
738    }
739}
740
741impl ser::SerializeStructVariant for MapSerializer<'_> {
742    type Ok = ();
743    type Error = Error;
744
745    fn serialize_field<T: Serialize + ?Sized>(
746        &mut self,
747        key: &'static str,
748        value: &T,
749    ) -> Result<()> {
750        self.write_kv(key, value)
751    }
752
753    fn end(self) -> Result<()> {
754        ser::SerializeMap::end(self)
755    }
756}