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 mut ms = MapSerializer {
275            ser: self,
276            current_key: None,
277            variant_name: None,
278        };
279        ms.write_kv(variant, value)
280    }
281
282    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
283        Ok(SeqSerializer {
284            parent: self,
285            items: Vec::new(),
286            variant: None,
287        })
288    }
289
290    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
291        self.serialize_seq(Some(len))
292    }
293
294    fn serialize_tuple_struct(
295        self,
296        _name: &'static str,
297        len: usize,
298    ) -> Result<Self::SerializeTupleStruct> {
299        self.serialize_seq(Some(len))
300    }
301
302    fn serialize_tuple_variant(
303        self,
304        _name: &'static str,
305        _index: u32,
306        variant: &'static str,
307        _len: usize,
308    ) -> Result<Self::SerializeTupleVariant> {
309        Ok(SeqSerializer {
310            parent: self,
311            items: Vec::new(),
312            variant: Some(variant.to_owned()),
313        })
314    }
315
316    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
317        self.is_object = true;
318        Ok(MapSerializer {
319            ser: self,
320            current_key: None,
321            variant_name: None,
322        })
323    }
324
325    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
326        self.serialize_map(Some(len))
327    }
328
329    fn serialize_struct_variant(
330        self,
331        _name: &'static str,
332        _index: u32,
333        variant: &'static str,
334        _len: usize,
335    ) -> Result<Self::SerializeStructVariant> {
336        Ok(MapSerializer {
337            ser: self,
338            current_key: None,
339            variant_name: Some(variant.to_owned()),
340        })
341    }
342}
343
344// ---------------------------------------------------------------------------
345// SeqSerializer – handles sequences / arrays
346// ---------------------------------------------------------------------------
347
348/// [`ser::SerializeSeq`] (and related tuple impls) that collects rendered items
349/// then emits them as a `{ … }` block.
350pub struct SeqSerializer<'a> {
351    parent: &'a mut Serializer,
352    /// Each element serialized to a string plus a flag indicating whether it
353    /// is a struct/map (object) that needs wrapping in inner `{ … }` braces.
354    items: Vec<(bool, String)>,
355    /// Set for tuple variants: the variant name to wrap the array under.
356    variant: Option<String>,
357}
358
359impl ser::SerializeSeq for SeqSerializer<'_> {
360    type Ok = ();
361    type Error = Error;
362
363    fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
364        let mut inner = Serializer::new(0);
365        value.serialize(&mut inner)?;
366        self.items.push((inner.is_object, inner.output));
367        Ok(())
368    }
369
370    fn end(self) -> Result<()> {
371        let pad = self.parent.pad();
372        let inner_pad = " ".repeat(self.parent.indent + 2);
373        let deep_pad = " ".repeat(self.parent.indent + 4);
374        writeln!(self.parent.output, "{{").map_err(|e| Error::Message(e.to_string()))?;
375        for (is_object, item) in &self.items {
376            let trimmed = item.trim_end();
377            if *is_object {
378                // Struct/map item: wrap in inner `{ … }` braces, indenting each
379                // field line by an extra two spaces (matching the Python reference).
380                writeln!(self.parent.output, "{inner_pad}{{")
381                    .map_err(|e| Error::Message(e.to_string()))?;
382                for line in trimmed.lines() {
383                    writeln!(self.parent.output, "{deep_pad}{line}")
384                        .map_err(|e| Error::Message(e.to_string()))?;
385                }
386                writeln!(self.parent.output, "{inner_pad}}}")
387                    .map_err(|e| Error::Message(e.to_string()))?;
388            } else {
389                // Scalar item: emit on a single indented line.
390                writeln!(self.parent.output, "{inner_pad}{trimmed}")
391                    .map_err(|e| Error::Message(e.to_string()))?;
392            }
393        }
394        writeln!(self.parent.output, "{pad}}}").map_err(|e| Error::Message(e.to_string()))
395    }
396}
397
398impl ser::SerializeTuple for SeqSerializer<'_> {
399    type Ok = ();
400    type Error = Error;
401
402    fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
403        ser::SerializeSeq::serialize_element(self, value)
404    }
405
406    fn end(self) -> Result<()> {
407        ser::SerializeSeq::end(self)
408    }
409}
410
411impl ser::SerializeTupleStruct for SeqSerializer<'_> {
412    type Ok = ();
413    type Error = Error;
414
415    fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
416        ser::SerializeSeq::serialize_element(self, value)
417    }
418
419    fn end(self) -> Result<()> {
420        ser::SerializeSeq::end(self)
421    }
422}
423
424impl ser::SerializeTupleVariant for SeqSerializer<'_> {
425    type Ok = ();
426    type Error = Error;
427
428    fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
429        ser::SerializeSeq::serialize_element(self, value)
430    }
431
432    fn end(self) -> Result<()> {
433        // Emit as `variant = { item1\n  item2\n … }` so the parser produces
434        // Object({"variant": Array([…])}), matching what deserialize_enum expects.
435        let variant = self.variant.ok_or_else(|| {
436            Error::Message("variant name missing in SerializeTupleVariant::end".into())
437        })?;
438        let pad = self.parent.pad();
439        let inner_pad = " ".repeat(self.parent.indent + 2);
440        let deep_pad = " ".repeat(self.parent.indent + 4);
441        writeln!(self.parent.output, "{pad}{} = {{", escape(&variant)?)
442            .map_err(|e| Error::Message(e.to_string()))?;
443        for (is_object, item) in &self.items {
444            let trimmed = item.trim_end();
445            if *is_object {
446                writeln!(self.parent.output, "{inner_pad}{{")
447                    .map_err(|e| Error::Message(e.to_string()))?;
448                for line in trimmed.lines() {
449                    writeln!(self.parent.output, "{deep_pad}{line}")
450                        .map_err(|e| Error::Message(e.to_string()))?;
451                }
452                writeln!(self.parent.output, "{inner_pad}}}")
453                    .map_err(|e| Error::Message(e.to_string()))?;
454            } else {
455                writeln!(self.parent.output, "{inner_pad}{trimmed}")
456                    .map_err(|e| Error::Message(e.to_string()))?;
457            }
458        }
459        writeln!(self.parent.output, "{pad}}}").map_err(|e| Error::Message(e.to_string()))
460    }
461}
462
463// ---------------------------------------------------------------------------
464// KeySerializer – accepts only string keys; rejects everything else
465// ---------------------------------------------------------------------------
466
467/// A minimal serializer that collects a `str`/`String` map key and returns
468/// [`Error::KeyMustBeString`] for every other type, including `char` and
469/// unit-enum variants.  Only `serialize_str` (and `serialize_newtype_struct`
470/// delegating to it) succeed.
471struct KeySerializer(String);
472
473impl ser::Serializer for &mut KeySerializer {
474    type Ok = ();
475    type Error = Error;
476    type SerializeSeq = ser::Impossible<(), Error>;
477    type SerializeTuple = ser::Impossible<(), Error>;
478    type SerializeTupleStruct = ser::Impossible<(), Error>;
479    type SerializeTupleVariant = ser::Impossible<(), Error>;
480    type SerializeMap = ser::Impossible<(), Error>;
481    type SerializeStruct = ser::Impossible<(), Error>;
482    type SerializeStructVariant = ser::Impossible<(), Error>;
483
484    fn serialize_str(self, v: &str) -> Result<()> {
485        v.clone_into(&mut self.0);
486        Ok(())
487    }
488
489    fn serialize_bool(self, _v: bool) -> Result<()> {
490        Err(Error::KeyMustBeString)
491    }
492    fn serialize_i8(self, _v: i8) -> Result<()> {
493        Err(Error::KeyMustBeString)
494    }
495    fn serialize_i16(self, _v: i16) -> Result<()> {
496        Err(Error::KeyMustBeString)
497    }
498    fn serialize_i32(self, _v: i32) -> Result<()> {
499        Err(Error::KeyMustBeString)
500    }
501    fn serialize_i64(self, _v: i64) -> Result<()> {
502        Err(Error::KeyMustBeString)
503    }
504    fn serialize_u8(self, _v: u8) -> Result<()> {
505        Err(Error::KeyMustBeString)
506    }
507    fn serialize_u16(self, _v: u16) -> Result<()> {
508        Err(Error::KeyMustBeString)
509    }
510    fn serialize_u32(self, _v: u32) -> Result<()> {
511        Err(Error::KeyMustBeString)
512    }
513    fn serialize_u64(self, _v: u64) -> Result<()> {
514        Err(Error::KeyMustBeString)
515    }
516    fn serialize_f32(self, _v: f32) -> Result<()> {
517        Err(Error::KeyMustBeString)
518    }
519    fn serialize_f64(self, _v: f64) -> Result<()> {
520        Err(Error::KeyMustBeString)
521    }
522    fn serialize_char(self, _v: char) -> Result<()> {
523        Err(Error::KeyMustBeString)
524    }
525    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
526        Err(Error::KeyMustBeString)
527    }
528    fn serialize_none(self) -> Result<()> {
529        Err(Error::KeyMustBeString)
530    }
531    fn serialize_some<T: Serialize + ?Sized>(self, _v: &T) -> Result<()> {
532        Err(Error::KeyMustBeString)
533    }
534    fn serialize_unit(self) -> Result<()> {
535        Err(Error::KeyMustBeString)
536    }
537    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
538        Err(Error::KeyMustBeString)
539    }
540    fn serialize_unit_variant(
541        self,
542        _name: &'static str,
543        _idx: u32,
544        _variant: &'static str,
545    ) -> Result<()> {
546        Err(Error::KeyMustBeString)
547    }
548    fn serialize_newtype_struct<T: Serialize + ?Sized>(
549        self,
550        _name: &'static str,
551        value: &T,
552    ) -> Result<()> {
553        value.serialize(self)
554    }
555    fn serialize_newtype_variant<T: Serialize + ?Sized>(
556        self,
557        _name: &'static str,
558        _idx: u32,
559        _variant: &'static str,
560        _value: &T,
561    ) -> Result<()> {
562        Err(Error::KeyMustBeString)
563    }
564    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
565        Err(Error::KeyMustBeString)
566    }
567    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
568        Err(Error::KeyMustBeString)
569    }
570    fn serialize_tuple_struct(
571        self,
572        _name: &'static str,
573        _len: usize,
574    ) -> Result<Self::SerializeTupleStruct> {
575        Err(Error::KeyMustBeString)
576    }
577    fn serialize_tuple_variant(
578        self,
579        _name: &'static str,
580        _idx: u32,
581        _variant: &'static str,
582        _len: usize,
583    ) -> Result<Self::SerializeTupleVariant> {
584        Err(Error::KeyMustBeString)
585    }
586    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
587        Err(Error::KeyMustBeString)
588    }
589    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
590        Err(Error::KeyMustBeString)
591    }
592    fn serialize_struct_variant(
593        self,
594        _name: &'static str,
595        _idx: u32,
596        _variant: &'static str,
597        _len: usize,
598    ) -> Result<Self::SerializeStructVariant> {
599        Err(Error::KeyMustBeString)
600    }
601}
602
603// ---------------------------------------------------------------------------
604// MapSerializer – handles maps and structs
605// ---------------------------------------------------------------------------
606
607/// [`ser::SerializeMap`] (and struct impls) that writes `key = value` /
608/// `key { … }` entries one at a time.
609pub struct MapSerializer<'a> {
610    ser: &'a mut Serializer,
611    /// The most recently serialized key, waiting for its value.
612    current_key: Option<String>,
613    /// If `Some`, wrap all emitted content in a `variant_name { … }` block.
614    variant_name: Option<String>,
615}
616
617impl MapSerializer<'_> {
618    /// Serialize a single `key = value` or `key { … }` entry into `self.ser`.
619    fn write_kv<T: Serialize + ?Sized>(&mut self, key: &str, value: &T) -> Result<()> {
620        let indent = self.ser.indent;
621        let pad = " ".repeat(indent);
622
623        // Serialize the value at the *current* indentation level.  This single
624        // call is sufficient for scalars and for array blocks, whose output is
625        // already formatted correctly:
626        //
627        //   scalar  →  no newlines, used directly as the RHS of `key = value`
628        //   array   →  `{\n<items at indent+2>\n<indent>}\n`, written inline
629        //               as `key = {…}` by `writeln!` below
630        //
631        // Only struct/map (multi-line, not starting with `{` or `"`) needs the
632        // content indented two levels deeper than the current key, so we
633        // re-serialize those at `indent+2`.  This is the only case where
634        // `Serialize` is invoked twice.
635        let mut first = Serializer::new(indent);
636        value.serialize(&mut first)?;
637        let rendered = first.output;
638
639        if rendered.contains('\n')
640            && !rendered.trim_start().starts_with('{')
641            && !rendered.trim_start().starts_with('"')
642        {
643            // Multi-line object block → `key {\n  <fields at indent+2>\n}\n`
644            // Re-serialize at the correct child indentation so nested fields
645            // sit two levels deeper than the enclosing key.  We must not
646            // blindly re-indent the first-pass output line-by-line because
647            // doing so would corrupt any quoted scalar whose value contains a
648            // literal newline (the continuation line is not a separate field).
649            writeln!(self.ser.output, "{pad}{} {{", escape(key)?)
650                .map_err(|e| Error::Message(e.to_string()))?;
651            let mut inner = Serializer::new(indent + 2);
652            value.serialize(&mut inner)?;
653            self.ser.output.push_str(&inner.output);
654            writeln!(self.ser.output, "{pad}}}").map_err(|e| Error::Message(e.to_string()))?;
655        } else if rendered.contains('\n') {
656            // Multi-line array block starting with `{`.
657            // The first-pass output is already at the right indentation
658            // (`{` inline, items at `indent+2`, `}` at `indent`), so we
659            // reuse it without a second `serialize` call.
660            writeln!(
661                self.ser.output,
662                "{pad}{} = {}",
663                escape(key)?,
664                rendered.trim_end()
665            )
666            .map_err(|e| Error::Message(e.to_string()))?;
667        } else {
668            // Scalar (no newlines, or a quoted scalar — both fit on one line).
669            let rendered = rendered.trim_end_matches('\n');
670            writeln!(self.ser.output, "{pad}{} = {rendered}", escape(key)?)
671                .map_err(|e| Error::Message(e.to_string()))?;
672        }
673        Ok(())
674    }
675}
676
677impl ser::SerializeMap for MapSerializer<'_> {
678    type Ok = ();
679    type Error = Error;
680
681    fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<()> {
682        let mut ks = KeySerializer(String::new());
683        key.serialize(&mut ks)?;
684        self.current_key = Some(ks.0);
685        Ok(())
686    }
687
688    fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
689        let key = self
690            .current_key
691            .take()
692            .ok_or_else(|| Error::Parse("serialize_value called before serialize_key".into()))?;
693        self.write_kv(&key, value)
694    }
695
696    fn end(self) -> Result<()> {
697        if let Some(variant) = self.variant_name {
698            // Wrap the content we already wrote in `variant { … }`.
699            let pad = " ".repeat(self.ser.indent.saturating_sub(2));
700            let header = format!("{pad}{} {{\n", escape(&variant)?);
701            let footer = format!("{pad}}}\n");
702            self.ser.output.insert_str(0, &header);
703            self.ser.output.push_str(&footer);
704        }
705        Ok(())
706    }
707}
708
709impl ser::SerializeStruct for MapSerializer<'_> {
710    type Ok = ();
711    type Error = Error;
712
713    fn serialize_field<T: Serialize + ?Sized>(
714        &mut self,
715        key: &'static str,
716        value: &T,
717    ) -> Result<()> {
718        self.write_kv(key, value)
719    }
720
721    fn end(self) -> Result<()> {
722        ser::SerializeMap::end(self)
723    }
724}
725
726impl ser::SerializeStructVariant for MapSerializer<'_> {
727    type Ok = ();
728    type Error = Error;
729
730    fn serialize_field<T: Serialize + ?Sized>(
731        &mut self,
732        key: &'static str,
733        value: &T,
734    ) -> Result<()> {
735        self.write_kv(key, value)
736    }
737
738    fn end(self) -> Result<()> {
739        ser::SerializeMap::end(self)
740    }
741}