serde_saphyr/
ser.rs

1//! Single-pass YAML serializer with optional anchors for Rc/Arc/Weak,
2//! order preservation (uses the iterator order of your types), simple
3//! style controls (block strings & flow containers), and special
4//! float handling for NaN/±Inf. No intermediate YAML DOM is built.
5//!
6//! Usage example:
7//!
8//! use serde::Serialize;
9//! use std::rc::Rc;
10//! use serde_saphyr::{to_string, RcAnchor, LitStr, FlowSeq};
11//!
12//! #[derive(Serialize)]
13//! struct Cfg {
14//!     name: String,
15//!     ports: FlowSeq<Vec<u16>>,   // render `[8080, 8081]`
16//!     note: LitStr<'static>,      // render as `|` block
17//!     data: RcAnchor<Vec<i32>>,   // first sight => &a1
18//!     alias: RcAnchor<Vec<i32>>,  // later sight => *a1
19//! }
20//!
21//! fn main() {
22//!     let shared = Rc::new(vec![1,2,3]);
23//!     let cfg = Cfg {
24//!         name: "demo".into(),
25//!         ports: FlowSeq(vec![8080, 8081]),
26//!         note: LitStr("line 1\nline 2"),
27//!         data: RcAnchor(shared.clone()),
28//!         alias: RcAnchor(shared),
29//!     };
30//!     println!("{}", to_string(&cfg).unwrap());
31//! }
32
33use serde::de::{Deserialize, Deserializer};
34use serde::ser::{
35    self, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
36    SerializeTuple, SerializeTupleStruct, SerializeTupleVariant, Serializer,
37};
38use std::collections::HashMap;
39use std::fmt::{self, Write};
40use std::rc::{Rc, Weak as RcWeak};
41use std::sync::{Arc, Weak as ArcWeak};
42
43use crate::serializer_options::SerializerOptions;
44use crate::{ArcAnchor, ArcWeakAnchor, RcAnchor, RcWeakAnchor};
45use base64::{engine::general_purpose::STANDARD as B64, Engine as _};
46use nohash_hasher::BuildNoHashHasher;
47
48// ------------------------------------------------------------
49// Public API
50// ------------------------------------------------------------
51
52pub use crate::ser_error::Error;
53use crate::ser_quoting::{is_plain_safe, is_plain_value_safe};
54
55/// Result alias.
56pub type Result<T> = std::result::Result<T, Error>;
57
58/// Force a sequence to be emitted in flow style: `[a, b, c]`.
59#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct FlowSeq<T>(pub T);
61/// Force a mapping to be emitted in flow style: `{k1: v1, k2: v2}`.
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct FlowMap<T>(pub T);
64
65/// Attach an inline YAML comment to a value when serializing.
66///
67/// This wrapper lets you annotate a scalar with an inline YAML comment that is
68/// emitted after the value when using block style. The typical form is:
69/// `value # comment`.
70///
71/// Behavior
72/// - Block style (default): the comment appears after the scalar on the same line.
73/// - Flow style (inside `[ ... ]` or `{ ... }`): comments are suppressed to keep
74///   the flow representation compact and unambiguous.
75/// - Complex values (sequences/maps/structs): the comment is ignored; only the
76///   inner value is serialized to preserve indentation and layout.
77/// - Newlines in comments are sanitized to spaces so the comment remains on a
78///   single line (e.g., "a\nb" becomes "a b").
79/// - Deserialization of `Commented<T>` ignores comments: it behaves like `T` and
80///   produces an empty comment string.
81///
82/// Examples
83///
84/// Basic scalar with a comment in block style:
85/// ```rust
86/// use serde::Serialize;
87///
88/// // Re-exported from the crate root
89/// use serde_saphyr::Commented;
90///
91/// let out = serde_saphyr::to_string(&Commented(42, "answer".to_string())).unwrap();
92/// assert_eq!(out, "42 # answer\n");
93/// ```
94///
95/// As a mapping value, still inline:
96/// ```rust
97/// use serde::Serialize;
98/// use serde_saphyr::Commented;
99///
100/// #[derive(Serialize)]
101/// struct S { n: Commented<i32> }
102///
103/// let s = S { n: Commented(5, "send five starships first".into()) };
104/// let out = serde_saphyr::to_string(&s).unwrap();
105/// assert_eq!(out, "n: 5 # send five starships first\n");
106/// ```
107///
108/// *Important*: Comments are suppressed in flow contexts (no `#` appears), and
109/// ignored for complex inner values. Value with `Commented` wrapper will be
110/// deserializaed correctly as well, but deserialization of comment is
111/// currently not supported.
112/// ```
113#[derive(Clone, Debug, PartialEq, Eq)]
114pub struct Commented<T>(pub T, pub String);
115
116/// Force a YAML block literal string using the `|` style.
117///
118/// Emits the inner `&str` as a block scalar that preserves newlines exactly
119/// as written. Each line is indented one level deeper than the surrounding
120/// indentation where the value appears.
121///
122/// Behavior
123/// - Uses YAML's literal block style: a leading `|` followed by newline.
124/// - Newlines are preserved verbatim by YAML consumers.
125/// - Indentation is handled automatically by the serializer.
126/// - Works in mapping values, sequence items, and at the top level.
127///
128/// Examples
129///
130/// Top-level literal block string:
131/// ```rust
132/// let out = serde_saphyr::to_string(&serde_saphyr::LitStr("line 1\nline 2")).unwrap();
133/// assert_eq!(out, "|\n  line 1\n  line 2\n");
134/// ```
135///
136/// As a mapping value:
137/// ```rust
138/// use serde::Serialize;
139/// #[derive(Serialize)]
140/// struct S { note: serde_saphyr::LitStr<'static> }
141/// let s = S { note: serde_saphyr::LitStr("a\nb") };
142/// let out = serde_saphyr::to_string(&s).unwrap();
143/// assert_eq!(out, "note: |\n  a\n  b\n");
144/// ```
145#[derive(Clone, Copy)]
146pub struct LitStr<'a>(pub &'a str);
147
148/// Force a YAML folded block string using the `>` style.
149///
150/// Emits the inner `&str` as a block scalar that suggests folding line breaks
151/// to spaces for display by YAML consumers (empty lines are kept as paragraph
152/// breaks). The serializer writes each line on its own; the folding behavior is
153/// applied by consumers of the YAML, not during serialization.
154///
155/// Behavior
156/// - Uses YAML's folded block style: a leading `>` followed by newline.
157/// - Intended for human-readable paragraphs where soft-wrapping is desirable.
158/// - Indentation is handled automatically by the serializer.
159/// - Works in mapping values, sequence items, and at the top level.
160///
161/// Examples
162///
163/// Top-level folded block string:
164/// ```rust
165/// let out = serde_saphyr::to_string(&serde_saphyr::FoldStr("line 1\nline 2")).unwrap();
166/// assert_eq!(out, ">\n  line 1\n  line 2\n");
167/// ```
168///
169/// As a mapping value:
170/// ```rust
171/// use serde::Serialize;
172/// #[derive(Serialize)]
173/// struct S { note: serde_saphyr::FoldStr<'static> }
174/// let s = S { note: serde_saphyr::FoldStr("a\nb") };
175/// let out = serde_saphyr::to_string(&s).unwrap();
176/// assert_eq!(out, "note: >\n  a\n  b\n");
177/// ```
178#[derive(Clone, Copy)]
179pub struct FoldStr<'a>(pub &'a str);
180
181// ------------------------------------------------------------
182// Internal wrappers -> shape the stream Serde produces so our
183// serializer can intercept them in a single pass.
184// ------------------------------------------------------------
185
186// Strong: "__yaml_anchor" tuple-struct => [ptr, value]
187#[allow(dead_code)]
188struct RcStrongPayload<'a, T>(&'a Rc<T>);
189#[allow(dead_code)]
190struct ArcStrongPayload<'a, T>(&'a Arc<T>);
191
192// Weak: "__yaml_weak_anchor" tuple-struct => [ptr, present, value]
193#[allow(dead_code)]
194struct RcWeakPayload<'a, T>(&'a RcWeak<T>);
195#[allow(dead_code)]
196struct ArcWeakPayload<'a, T>(&'a ArcWeak<T>);
197
198// Flow hints and block-string hints: we use newtype-struct names.
199const NAME_TUPLE_ANCHOR: &str = "__yaml_anchor";
200const NAME_TUPLE_WEAK: &str = "__yaml_weak_anchor";
201const NAME_FLOW_SEQ: &str = "__yaml_flow_seq";
202const NAME_FLOW_MAP: &str = "__yaml_flow_map";
203const NAME_LIT_STR: &str = "__yaml_lit_str";
204const NAME_FOLD_STR: &str = "__yaml_fold_str";
205const NAME_TUPLE_COMMENTED: &str = "__yaml_commented";
206
207// Top-level newtype wrappers for strong/weak simply wrap the real payloads.
208impl<T: Serialize> Serialize for RcAnchor<T> {
209    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
210        // delegate to tuple-struct the serializer knows how to intercept
211        let mut ts = s.serialize_tuple_struct(NAME_TUPLE_ANCHOR, 2)?;
212        let ptr = Rc::as_ptr(&self.0) as *const T as usize;
213        ts.serialize_field(&ptr)?;
214        ts.serialize_field(&*self.0)?;
215        ts.end()
216    }
217}
218impl<T: Serialize> Serialize for ArcAnchor<T> {
219    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
220        let mut ts = s.serialize_tuple_struct(NAME_TUPLE_ANCHOR, 2)?;
221        let ptr = Arc::as_ptr(&self.0) as *const T as usize;
222        ts.serialize_field(&ptr)?;
223        ts.serialize_field(&*self.0)?;
224        ts.end()
225    }
226}
227impl<T: Serialize> Serialize for RcWeakAnchor<T> {
228    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
229        let up = self.0.upgrade();
230        let mut ts = s.serialize_tuple_struct(NAME_TUPLE_WEAK, 3)?;
231        let ptr = self.0.as_ptr() as *const T as usize;
232        ts.serialize_field(&ptr)?;
233        ts.serialize_field(&up.is_some())?;
234        if let Some(rc) = up {
235            ts.serialize_field(&*rc)?;
236        } else {
237            ts.serialize_field(&())?; // ignored by our serializer
238        }
239        ts.end()
240    }
241}
242impl<T: Serialize> Serialize for ArcWeakAnchor<T> {
243    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
244        let up = self.0.upgrade();
245        let mut ts = s.serialize_tuple_struct(NAME_TUPLE_WEAK, 3)?;
246        let ptr = self.0.as_ptr() as *const T as usize;
247        ts.serialize_field(&ptr)?;
248        ts.serialize_field(&up.is_some())?;
249        if let Some(arc) = up {
250            ts.serialize_field(&*arc)?;
251        } else {
252            ts.serialize_field(&())?;
253        }
254        ts.end()
255    }
256}
257
258// Hints for flow / block strings.
259impl<T: Serialize> Serialize for FlowSeq<T> {
260    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
261        s.serialize_newtype_struct(NAME_FLOW_SEQ, &self.0)
262    }
263}
264impl<T: Serialize> Serialize for FlowMap<T> {
265    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
266        s.serialize_newtype_struct(NAME_FLOW_MAP, &self.0)
267    }
268}
269
270impl<T: Serialize> Serialize for Commented<T> {
271    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
272        // Represent as a special tuple-struct with two fields: (comment, value)
273        // so the serializer can stage the comment before serializing the value.
274        let mut ts = s.serialize_tuple_struct(NAME_TUPLE_COMMENTED, 2)?;
275        ts.serialize_field(&self.1)?; // comment first
276        ts.serialize_field(&self.0)?; // then value
277        ts.end()
278    }
279}
280
281// Deserialization for flow wrappers: delegate to inner T during deserialization.
282impl<'de, T: Deserialize<'de>> Deserialize<'de> for FlowSeq<T> {
283    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
284        T::deserialize(deserializer).map(FlowSeq)
285    }
286}
287impl<'de, T: Deserialize<'de>> Deserialize<'de> for FlowMap<T> {
288    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
289        T::deserialize(deserializer).map(FlowMap)
290    }
291}
292impl<'de, T: Deserialize<'de>> Deserialize<'de> for Commented<T> {
293    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
294        T::deserialize(deserializer).map(|v| Commented(v, String::new()))
295    }
296}
297
298impl<'a> Serialize for LitStr<'a> {
299    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
300        s.serialize_newtype_struct(NAME_LIT_STR, &self.0)
301    }
302}
303impl<'a> Serialize for FoldStr<'a> {
304    fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
305        s.serialize_newtype_struct(NAME_FOLD_STR, &self.0)
306    }
307}
308
309// ------------------------------------------------------------
310// Core serializer
311// ------------------------------------------------------------
312
313#[derive(Clone, Copy, PartialEq, Eq)]
314enum PendingFlow {
315    AnySeq,
316    AnyMap,
317}
318#[derive(Clone, Copy, PartialEq, Eq)]
319enum StrStyle {
320    Literal, // |
321    Folded,  // >
322}
323
324// Numeric anchor id used internally.
325type AnchorId = u32;
326
327/// Core YAML serializer used by `to_string`, `to_fmt_writer`, and `to_io_writer` (and their `_with_options` variants).
328///
329/// This type implements `serde::Serializer` and writes YAML to a `fmt::Write`.
330/// It manages indentation, flow/block styles, and YAML anchors/aliases.
331pub struct YamlSer<'a, W: Write> {
332    /// Destination writer where YAML text is emitted.
333    out: &'a mut W,
334    /// Spaces per indentation level for block-style collections.
335    indent_step: usize,
336    /// Current nesting depth (used for indentation).
337    depth: usize,
338    /// Whether the cursor is at the start of a line.
339    at_line_start: bool,
340
341    // Anchors:
342    /// Map from pointer identity to anchor id.
343    anchors: HashMap<usize, AnchorId, BuildNoHashHasher<usize>>,
344    /// Next numeric id to use when generating anchor names (1-based).
345    next_anchor_id: AnchorId,
346    /// If set, the next scalar/complex node to be emitted will be prefixed with this `&anchor`.
347    pending_anchor_id: Option<AnchorId>,
348    /// Optional custom anchor-name generator supplied by the caller.
349    anchor_gen: Option<fn(usize) -> String>,
350    /// Cache of custom anchor names when generator is present (index = id-1).
351    custom_anchor_names: Option<Vec<String>>,
352
353    // Style flags:
354    /// Pending flow-style hint captured from wrapper types.
355    pending_flow: Option<PendingFlow>,
356    /// Number of nested flow containers we are currently inside (>0 means in-flow).
357    in_flow: usize,
358    /// Pending block-string style hint (literal `|` or folded `>`).
359    pending_str_style: Option<StrStyle>,
360    /// Pending inline comment to be appended after the next scalar (block style only).
361    pending_inline_comment: Option<String>,
362    /// When the previous token was a list item dash ("- ") and the next node is a mapping,
363    /// emit the first key inline on the same line ("- key: value").
364    pending_inline_map: bool,
365    /// After writing a mapping key and ':', defer writing the following space until we know
366    /// whether the value is a scalar (space) or a complex node (newline with no space).
367    pending_space_after_colon: bool,
368    /// If the previous sequence element after a dash turned out to be a mapping (inline first key),
369    /// indent subsequent dashes by one level to satisfy tests expecting "\n  -".
370    inline_map_after_dash: bool,
371    /// If a sequence element starts with a dash on this depth, capture that depth so
372    /// struct-variant mappings emitted immediately after can indent their fields correctly.
373    after_dash_depth: Option<usize>,
374    /// Current block map indentation depth (for aligning sequences under a map key).
375    current_map_depth: Option<usize>,
376}
377
378impl<'a, W: Write> YamlSer<'a, W> {
379    /// Construct a `YamlSer` that writes to `out`.
380    /// Called by `to_writer`/`to_string` entry points.
381    pub fn new(out: &'a mut W) -> Self {
382        Self {
383            out,
384            indent_step: 2,
385            depth: 0,
386            at_line_start: true,
387            anchors: HashMap::with_hasher(BuildNoHashHasher::default()),
388            next_anchor_id: 1,
389            pending_anchor_id: None,
390            anchor_gen: None,
391            custom_anchor_names: None,
392            pending_flow: None,
393            in_flow: 0,
394            pending_str_style: None,
395            pending_inline_comment: None,
396            pending_inline_map: false,
397            pending_space_after_colon: false,
398            inline_map_after_dash: false,
399            after_dash_depth: None,
400            current_map_depth: None,
401        }
402    }
403    /// Construct a `YamlSer` with a specific indentation step.
404    /// Typically used internally by tests or convenience wrappers.
405    pub fn with_indent(out: &'a mut W, indent_step: usize) -> Self {
406        let mut s = Self::new(out);
407        s.indent_step = indent_step;
408        s
409    }
410    /// Construct a `YamlSer` from user-supplied [`SerializerOptions`].
411    /// Used by `to_writer_with_options`.
412    pub fn with_options(out: &'a mut W, options: &mut SerializerOptions) -> Self {
413        let mut s = Self::new(out);
414        s.indent_step = options.indent_step;
415        s.anchor_gen = options.anchor_generator.take();
416        s
417    }
418
419    // -------- helpers --------
420
421    /// Called at the end of emitting a scalar in block style: appends a pending inline
422    /// comment (if any) and then emits a newline. In flow style, comments are suppressed.
423    #[inline]
424    fn write_end_of_scalar(&mut self) -> Result<()> {
425        if self.in_flow == 0 {
426            if let Some(c) = self.pending_inline_comment.take() {
427                self.out.write_str(" # ")?;
428                self.out.write_str(&c)?;
429            }
430            self.newline()?;
431        }
432        Ok(())
433    }
434
435    /// Allocate (or get existing) anchor id for a pointer identity.
436    /// Returns `(id, is_new)`.
437    #[inline]
438    fn alloc_anchor_for(&mut self, ptr: usize) -> (AnchorId, bool) {
439        match self.anchors.entry(ptr) {
440            std::collections::hash_map::Entry::Occupied(e) => (*e.get(), false),
441            std::collections::hash_map::Entry::Vacant(v) => {
442                let id = self.next_anchor_id;
443                self.next_anchor_id = self.next_anchor_id.saturating_add(1);
444                if let Some(generator) = self.anchor_gen {
445                    let name = generator(id as usize);
446                    self.custom_anchor_names
447                        .get_or_insert_with(Vec::new)
448                        .push(name);
449                }
450                v.insert(id);
451                (id, true)
452            }
453        }
454    }
455
456    /// Resolve an anchor name for `id` and write it.
457    #[inline]
458    fn write_anchor_name(&mut self, id: AnchorId) -> Result<()> {
459        if let Some(names) = &self.custom_anchor_names {
460            // ids are 1-based; vec is 0-based
461            let idx = id as usize - 1;
462            if let Some(name) = names.get(idx) {
463                self.out.write_str(name)?;
464            } else {
465                // Fallback if generator vector is out of sync
466                write!(self.out, "a{}", id)?;
467            }
468        } else {
469            write!(self.out, "a{}", id)?;
470        }
471        Ok(())
472    }
473
474    /// If a mapping key has just been written (':' emitted) and we determined the value is a scalar,
475    /// insert a single space before the scalar and clear the pending flag.
476    #[inline]
477    fn write_space_if_pending(&mut self) -> Result<()> {
478        if self.pending_space_after_colon {
479            self.out.write_char(' ')?;
480            self.pending_space_after_colon = false;
481        }
482        Ok(())
483    }
484
485    /// Ensure indentation is written if we are at the start of a line.
486    /// Internal: called by most emitters before writing tokens.
487    #[inline]
488    fn write_indent(&mut self, depth: usize) -> Result<()> {
489        if self.at_line_start {
490            for _k in 0..self.indent_step * depth {
491                self.out.write_char(' ')?;
492            }
493            self.at_line_start = false;
494        }
495        Ok(())
496    }
497
498    /// Emit a newline and mark the next write position as line start.
499    /// Internal utility used after finishing a top-level token.
500    #[inline]
501    fn newline(&mut self) -> Result<()> {
502        self.out.write_char('\n')?;
503        self.at_line_start = true;
504        Ok(())
505    }
506
507    /// Write a scalar either as plain or as double-quoted with minimal escapes.
508    /// Called by most `serialize_*` primitive methods.
509    fn write_plain_or_quoted(&mut self, s: &str) -> Result<()> {
510        if is_plain_safe(s) {
511            self.out.write_str(s)?;
512            Ok(())
513        } else {
514            self.write_quoted(s)
515        }
516    }
517
518    /// Write a double-quoted string with necessary escapes.
519    fn write_quoted(&mut self, s: &str) -> Result<()> {
520        self.out.write_char('"')?;
521        for ch in s.chars() {
522            match ch {
523                '\\' => self.out.write_str("\\\\")?,
524                '"' => self.out.write_str("\\\"")?,
525                // YAML named escapes for common control characters
526                '\0' => self.out.write_str("\\0")?,
527                '\u{7}' => self.out.write_str("\\a")?,
528                '\u{8}' => self.out.write_str("\\b")?,
529                '\t' => self.out.write_str("\\t")?,
530                '\n' => self.out.write_str("\\n")?,
531                '\u{b}' => self.out.write_str("\\v")?,
532                '\u{c}' => self.out.write_str("\\f")?,
533                '\r' => self.out.write_str("\\r")?,
534                '\u{1b}' => self.out.write_str("\\e")?,
535                // Unicode BOM should use the standard \u escape rather than Rust's \u{...}
536                '\u{FEFF}' => self.out.write_str("\\uFEFF")?,
537                // YAML named escapes for Unicode separators
538                '\u{0085}' => self.out.write_str("\\N")?,
539                '\u{2028}' => self.out.write_str("\\L")?,
540                '\u{2029}' => self.out.write_str("\\P")?,
541                c if (c as u32) <= 0xFF
542                    && (c.is_control() || (0x7F..=0x9F).contains(&(c as u32))) =>
543                {
544                    write!(self.out, "\\x{:02X}", c as u32)?
545                }
546                c if (c as u32) <= 0xFFFF
547                    && (c.is_control() || (0x7F..=0x9F).contains(&(c as u32))) =>
548                {
549                    write!(self.out, "\\u{:04X}", c as u32)?
550                }
551                c => self.out.write_char(c)?,
552            }
553        }
554        self.out.write_char('"')?;
555        Ok(())
556    }
557
558    /// Like `write_plain_or_quoted`, but intended for VALUE position where ':' is allowed.
559    #[inline]
560    fn write_plain_or_quoted_value(&mut self, s: &str) -> Result<()> {
561        if is_plain_value_safe(s) {
562            self.out.write_str(s)?;
563            Ok(())
564        } else {
565            // Force quoted style for unsafe value tokens (commas/brackets, bool/num-like, etc.).
566            self.write_quoted(s)
567        }
568    }
569
570    /// If an anchor is pending for the next scalar, emit `&name ` prefix.
571    /// Used for in-flow scalars.
572    #[inline]
573    fn write_scalar_prefix_if_anchor(&mut self) -> Result<()> {
574        if let Some(id) = self.pending_anchor_id.take() {
575            if self.at_line_start {
576                self.write_indent(self.depth)?;
577            }
578            self.out.write_char('&')?;
579            self.write_anchor_name(id)?;
580            self.out.write_char(' ')?;
581        }
582        Ok(())
583    }
584
585    /// If an anchor is pending for the next complex node (seq/map),
586    /// emit it on its own line before the node.
587    #[inline]
588    fn write_anchor_for_complex_node(&mut self) -> Result<()> {
589        if let Some(id) = self.pending_anchor_id.take() {
590            if self.at_line_start {
591                self.write_indent(self.depth)?;
592            }
593            self.write_space_if_pending()?;
594            self.out.write_char('&')?;
595            self.write_anchor_name(id)?;
596            self.newline()?;
597        }
598        Ok(())
599    }
600
601    /// Emit an alias `*name`. Adds a newline in block style.
602    /// Used when a previously defined anchor is referenced again.
603    #[inline]
604    fn write_alias_id(&mut self, id: AnchorId) -> Result<()> {
605        if self.at_line_start {
606            self.write_indent(self.depth)?;
607        }
608        self.write_space_if_pending()?;
609        self.out.write_char('*')?;
610        self.write_anchor_name(id)?;
611        if self.in_flow == 0 {
612            self.newline()?;
613        }
614        Ok(())
615    }
616
617    /// Determine whether the next sequence should be emitted in flow style.
618    /// Consumes any pending flow hint.
619    #[inline]
620    fn take_flow_for_seq(&mut self) -> bool {
621        if self.in_flow > 0 {
622            true
623        } else {
624            matches!(self.pending_flow.take(), Some(PendingFlow::AnySeq))
625        }
626    }
627    /// Determine whether the next mapping should be emitted in flow style.
628    /// Consumes any pending flow hint.
629    #[inline]
630    fn take_flow_for_map(&mut self) -> bool {
631        if self.in_flow > 0 {
632            true
633        } else {
634            matches!(self.pending_flow.take(), Some(PendingFlow::AnyMap))
635        }
636    }
637
638    /// Temporarily mark that we are inside a flow container while running `f`.
639    /// Ensures proper comma insertion and line handling for nested flow nodes.
640    #[inline]
641    fn with_in_flow<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<T> {
642        self.in_flow += 1;
643        let r = f(self);
644        self.in_flow -= 1;
645        r
646    }
647}
648
649// ------------------------------------------------------------
650// Impl Serializer for YamlSer
651// ------------------------------------------------------------
652
653impl<'a, 'b, W: Write> Serializer for &'a mut YamlSer<'b, W> {
654    type Ok = ();
655    type Error = Error;
656
657    type SerializeSeq = SeqSer<'a, 'b, W>;
658    type SerializeTuple = SeqSer<'a, 'b, W>;
659    type SerializeTupleStruct = TupleSer<'a, 'b, W>;
660    type SerializeTupleVariant = TupleVariantSer<'a, 'b, W>;
661    type SerializeMap = MapSer<'a, 'b, W>;
662    type SerializeStruct = MapSer<'a, 'b, W>;
663    type SerializeStructVariant = StructVariantSer<'a, 'b, W>;
664
665    // -------- Scalars --------
666
667    fn serialize_bool(self, v: bool) -> Result<()> {
668        self.write_space_if_pending()?;
669        self.write_scalar_prefix_if_anchor()?;
670        if self.at_line_start {
671            self.write_indent(self.depth)?;
672        }
673        self.out.write_str(if v { "true" } else { "false" })?;
674        self.write_end_of_scalar()?;
675        Ok(())
676    }
677
678    fn serialize_i8(self, v: i8) -> Result<()> {
679        self.serialize_i64(v as i64)
680    }
681    fn serialize_i16(self, v: i16) -> Result<()> {
682        self.serialize_i64(v as i64)
683    }
684    fn serialize_i32(self, v: i32) -> Result<()> {
685        self.serialize_i64(v as i64)
686    }
687    fn serialize_i64(self, v: i64) -> Result<()> {
688        self.write_space_if_pending()?;
689        self.write_scalar_prefix_if_anchor()?;
690        if self.at_line_start {
691            self.write_indent(self.depth)?;
692        }
693        write!(self.out, "{}", v)?;
694        if self.in_flow == 0 {
695            self.newline()?;
696        }
697        Ok(())
698    }
699
700    fn serialize_i128(self, v: i128) -> Result<()> {
701        self.write_space_if_pending()?;
702        self.write_scalar_prefix_if_anchor()?;
703        if self.at_line_start {
704            self.write_indent(self.depth)?;
705        }
706        write!(self.out, "{}", v)?;
707        if self.in_flow == 0 {
708            self.newline()?;
709        }
710        Ok(())
711    }
712
713    fn serialize_u8(self, v: u8) -> Result<()> {
714        self.serialize_u64(v as u64)
715    }
716    fn serialize_u16(self, v: u16) -> Result<()> {
717        self.serialize_u64(v as u64)
718    }
719    fn serialize_u32(self, v: u32) -> Result<()> {
720        self.serialize_u64(v as u64)
721    }
722    fn serialize_u64(self, v: u64) -> Result<()> {
723        self.write_space_if_pending()?;
724        self.write_scalar_prefix_if_anchor()?;
725        if self.at_line_start {
726            self.write_indent(self.depth)?;
727        }
728        write!(self.out, "{}", v)?;
729        if self.in_flow == 0 {
730            self.newline()?;
731        }
732        Ok(())
733    }
734
735    fn serialize_u128(self, v: u128) -> Result<()> {
736        self.write_space_if_pending()?;
737        self.write_scalar_prefix_if_anchor()?;
738        if self.at_line_start {
739            self.write_indent(self.depth)?;
740        }
741        write!(self.out, "{}", v)?;
742        if self.in_flow == 0 {
743            self.newline()?;
744        }
745        Ok(())
746    }
747
748    fn serialize_f32(self, v: f32) -> Result<()> {
749        self.serialize_f64(v as f64)
750    }
751    fn serialize_f64(self, v: f64) -> Result<()> {
752        self.write_space_if_pending()?;
753        self.write_scalar_prefix_if_anchor()?;
754        if self.at_line_start {
755            self.write_indent(self.depth)?;
756        }
757        if v.is_nan() {
758            self.out.write_str(".nan")?;
759        } else if v.is_infinite() {
760            if v.is_sign_positive() {
761                self.out.write_str(".inf")?;
762            } else {
763                self.out.write_str("-.inf")?;
764            }
765        } else {
766            let mut buf = ryu::Buffer::new();
767            let s = buf.format(v);
768            if !s.contains('.') && !s.contains('e') && !s.contains('E') {
769                self.out.write_str(s)?;
770                self.out.write_str(".0")?;
771            } else {
772                self.out.write_str(s)?;
773            }
774        }
775        if self.in_flow == 0 {
776            self.newline()?;
777        }
778        Ok(())
779    }
780
781    fn serialize_char(self, v: char) -> Result<()> {
782        self.write_space_if_pending()?;
783        let mut buf = [0u8; 4];
784        self.serialize_str(v.encode_utf8(&mut buf))
785    }
786
787    fn serialize_str(self, v: &str) -> Result<()> {
788        if let Some(style) = self.pending_str_style.take() {
789            // Emit block string. If we are a mapping value, YAML requires a space after ':'.
790            // Insert it now if pending.
791            self.write_space_if_pending()?;
792            if self.at_line_start {
793                self.write_indent(self.depth)?;
794            }
795            match style {
796                StrStyle::Literal => self.out.write_str("|")?,
797                StrStyle::Folded => self.out.write_str(">")?,
798            }
799            self.newline()?;
800            for line in v.split('\n') {
801                self.write_indent(self.depth + 1)?;
802                self.out.write_str(line)?;
803                self.newline()?;
804            }
805            return Ok(());
806        }
807        self.write_space_if_pending()?;
808        self.write_scalar_prefix_if_anchor()?;
809        if self.at_line_start {
810            self.write_indent(self.depth)?;
811        }
812        // Special-case: prefer single-quoted style for select 1-char punctuation to
813        // match expected YAML output in tests ('.', '#', '-').
814        if v.len() == 1 {
815            if let Some(ch) = v.chars().next() {
816                if ch == '.' || ch == '#' || ch == '-' {
817                    self.out.write_char('\'')?;
818                    self.out.write_char(ch)?;
819                    self.out.write_char('\'')?;
820                    if self.in_flow == 0 {
821                        self.newline()?;
822                    }
823                    return Ok(());
824                }
825            }
826        }
827        self.write_plain_or_quoted_value(v)?;
828        if self.in_flow == 0 {
829            self.newline()?;
830        }
831        Ok(())
832    }
833
834    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
835        // Two behaviors are required by tests:
836        // - Top-level &[u8] should serialize as a block sequence of integers.
837        // - Fields using #[serde(with = "serde_bytes")] should serialize as a tagged !!binary
838        //   base64 scalar inline after "key: ". The latter ends up calling serialize_bytes in
839        //   value position (mid-line), whereas plain Vec<u8> without serde_bytes goes through
840        //   serialize_seq instead. Distinguish by whether we are at the start of a line.
841        if self.at_line_start {
842            // Top-level or start-of-line: emit as sequence of numbers
843            let mut seq = self.serialize_seq(Some(v.len()))?;
844            for b in v {
845                serde::ser::SerializeSeq::serialize_element(&mut seq, b)?;
846            }
847            return serde::ser::SerializeSeq::end(seq);
848        }
849
850        // Inline value position: emit !!binary with base64.
851        self.write_space_if_pending()?;
852        self.write_scalar_prefix_if_anchor()?;
853        // No indent needed mid-line; mirror serialize_str behavior.
854        self.out.write_str("!!binary ")?;
855        let mut s = String::new();
856        B64.encode_string(v, &mut s);
857        self.out.write_str(&s)?;
858        if self.in_flow == 0 {
859            self.newline()?;
860        }
861        Ok(())
862    }
863
864    fn serialize_none(self) -> Result<()> {
865        self.write_space_if_pending()?;
866        if self.at_line_start {
867            self.write_indent(self.depth)?;
868        }
869        self.out.write_str("null")?;
870        if self.in_flow == 0 {
871            self.newline()?;
872        }
873        Ok(())
874    }
875
876    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<()> {
877        value.serialize(self)
878    }
879
880    fn serialize_unit(self) -> Result<()> {
881        self.write_space_if_pending()?;
882        if self.at_line_start {
883            self.write_indent(self.depth)?;
884        }
885        self.out.write_str("null")?;
886        if self.in_flow == 0 {
887            self.newline()?;
888        }
889        Ok(())
890    }
891
892    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
893        self.serialize_unit()
894    }
895
896    fn serialize_unit_variant(
897        self,
898        _name: &'static str,
899        _variant_index: u32,
900        variant: &'static str,
901    ) -> Result<()> {
902        // If we are in a mapping value position, insert the deferred space after ':'
903        self.write_space_if_pending()?;
904        self.serialize_str(variant)
905    }
906
907    fn serialize_newtype_struct<T: ?Sized + Serialize>(
908        self,
909        name: &'static str,
910        value: &T,
911    ) -> Result<()> {
912        // Flow hints & block-string hints:
913        match name {
914            NAME_FLOW_SEQ => {
915                self.pending_flow = Some(PendingFlow::AnySeq);
916                return value.serialize(self);
917            }
918            NAME_FLOW_MAP => {
919                self.pending_flow = Some(PendingFlow::AnyMap);
920                return value.serialize(self);
921            }
922            NAME_LIT_STR => {
923                self.pending_str_style = Some(StrStyle::Literal);
924                return value.serialize(self);
925            }
926            NAME_FOLD_STR => {
927                self.pending_str_style = Some(StrStyle::Folded);
928                return value.serialize(self);
929            }
930            _ => {}
931        }
932        // default: ignore the name, serialize the inner as-is
933        value.serialize(self)
934    }
935
936    fn serialize_newtype_variant<T: ?Sized + Serialize>(
937        self,
938        _name: &'static str,
939        _variant_index: u32,
940        variant: &'static str,
941        value: &T,
942    ) -> Result<()> {
943        // If we are the value of a mapping key, YAML forbids "key: Variant: value" inline.
944        // Emit the variant mapping on the next line indented one level. Also, do not insert
945        // a space after the colon when the value may itself be a mapping; instead, defer
946        // space insertion to the value serializer via pending_space_after_colon.
947        if self.pending_space_after_colon {
948            // consume the pending space request and start a new line
949            self.pending_space_after_colon = false;
950            self.newline()?;
951            // When used as a mapping value, indent relative to the parent mapping's base,
952            // not the serializer's current depth (which may still be the outer level).
953            let base = self.current_map_depth.unwrap_or(self.depth);
954            self.write_indent(base + 1)?;
955            self.write_plain_or_quoted(variant)?;
956            // Write ':' without trailing space, then mark that a space may be needed
957            // if the following value is a scalar.
958            self.out.write_str(":")?;
959            self.pending_space_after_colon = true;
960            self.at_line_start = false;
961            // Ensure that if the value is another variant or a mapping/sequence,
962            // it indents under this variant label rather than the parent map key.
963            let prev_map_depth = self.current_map_depth.replace(base + 1);
964            let res = value.serialize(&mut *self);
965            self.current_map_depth = prev_map_depth;
966            return res;
967        }
968        // Otherwise (top-level or sequence context).
969        if self.at_line_start {
970            self.write_indent(self.depth)?;
971        }
972        self.write_plain_or_quoted(variant)?;
973        // Write ':' without a space and defer spacing/newline to the value serializer.
974        self.out.write_str(":")?;
975        self.pending_space_after_colon = true;
976        self.at_line_start = false;
977        value.serialize(&mut *self)
978    }
979
980    // -------- Collections --------
981
982    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
983        let flow = self.take_flow_for_seq();
984        if flow {
985            self.write_scalar_prefix_if_anchor()?;
986            // Ensure a space after a preceding colon when this sequence is a mapping value.
987            self.write_space_if_pending()?;
988            if self.at_line_start {
989                self.write_indent(self.depth)?;
990            }
991            self.out.write_str("[")?;
992            self.at_line_start = false;
993            let depth_next = self.depth; // inline
994            Ok(SeqSer {
995                ser: self,
996                depth: depth_next,
997                flow: true,
998                first: true,
999            })
1000        } else {
1001            // Block sequence. Decide indentation based on whether this is after a map key or after a list dash.
1002            let was_inline_value = !self.at_line_start;
1003            // For block sequences, never inline the first inner dash after a parent dash.
1004            // Style expectation in tests prefers:
1005            // -\n  - 1
1006            // rather than "- - 1".
1007            let inline_first = (!self.at_line_start)
1008                && self.after_dash_depth.is_some()
1009                && !self.pending_space_after_colon;
1010            // Remember if we are a mapping value (space after colon was pending) to handle newline correctly.
1011            let had_pending_space = self.pending_space_after_colon;
1012            self.write_anchor_for_complex_node()?;
1013            if inline_first {
1014                // Keep staged inline (pending_inline_map) so the child can inline its first dash.
1015                // Ensure we stay mid-line so the child can emit its first dash inline.
1016                self.at_line_start = false;
1017            } else if was_inline_value {
1018                // Mid-line start. If we are here due to a map value (after ':'), move to next line.
1019                // If we are here due to a list dash, keep inline.
1020                self.pending_space_after_colon = false;
1021                if had_pending_space && !self.at_line_start {
1022                    self.newline()?;
1023                }
1024            }
1025            // Indentation policy mirrors serialize_map:
1026            // - After a list dash inline_first: base is dash depth; indent one level deeper.
1027            // - As a value after a map key: base is current_map_depth (if set), indent one level deeper.
1028            // - Otherwise (top-level or already at line start): base is current depth.
1029            let base = if inline_first {
1030                self.after_dash_depth.unwrap_or(self.depth)
1031            } else if was_inline_value && self.current_map_depth.is_some() {
1032                // Guarded by is_some(); use unwrap_or to avoid panicking unwrap
1033                self.current_map_depth.unwrap_or(self.depth)
1034            } else {
1035                self.depth
1036            };
1037            // For sequences used as a mapping value, the dash should align under the parent key
1038            // (no extra indentation). Keep depth at `base` so the first dash starts at the base.
1039            let depth_next = if inline_first {
1040                base + 1
1041            } else if was_inline_value {
1042                base + 1
1043            } else {
1044                base
1045            };
1046            Ok(SeqSer {
1047                ser: self,
1048                depth: depth_next,
1049                flow: false,
1050                first: true,
1051            })
1052        }
1053    }
1054
1055    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
1056        self.serialize_seq(Some(len))
1057    }
1058
1059    fn serialize_tuple_struct(
1060        self,
1061        name: &'static str,
1062        _len: usize,
1063    ) -> Result<Self::SerializeTupleStruct> {
1064        if name == NAME_TUPLE_ANCHOR {
1065            Ok(TupleSer::anchor_strong(self))
1066        } else if name == NAME_TUPLE_WEAK {
1067            Ok(TupleSer::anchor_weak(self))
1068        } else if name == NAME_TUPLE_COMMENTED {
1069            Ok(TupleSer::commented(self))
1070        } else {
1071            // Treat as normal block sequence
1072            Ok(TupleSer::normal(self))
1073        }
1074    }
1075
1076    fn serialize_tuple_variant(
1077        self,
1078        _name: &'static str,
1079        _variant_index: u32,
1080        variant: &'static str,
1081        _len: usize,
1082    ) -> Result<Self::SerializeTupleVariant> {
1083        if self.at_line_start {
1084            self.write_indent(self.depth)?;
1085        }
1086        self.write_plain_or_quoted(variant)?;
1087        self.out.write_str(":\n")?;
1088        self.at_line_start = true;
1089        let depth_next = self.depth + 1;
1090        Ok(TupleVariantSer {
1091            ser: self,
1092            depth: depth_next,
1093        })
1094    }
1095
1096    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
1097        let flow = self.take_flow_for_map();
1098        if flow {
1099            self.write_scalar_prefix_if_anchor()?;
1100            // Ensure a space after a preceding colon when this mapping is a value.
1101            self.write_space_if_pending()?;
1102            if self.at_line_start {
1103                self.write_indent(self.depth)?;
1104            }
1105            self.out.write_str("{")?;
1106            self.at_line_start = false;
1107            let depth_next = self.depth;
1108            Ok(MapSer {
1109                ser: self,
1110                depth: depth_next,
1111                flow: true,
1112                first: true,
1113                last_key_complex: false,
1114            })
1115        } else {
1116            let inline_first = self.pending_inline_map;
1117            let was_inline_value = !self.at_line_start;
1118            self.write_anchor_for_complex_node()?;
1119            if inline_first {
1120                // Suppress newline after a list dash for inline map first key.
1121                self.pending_inline_map = false;
1122                // Mark that this sequence element is a mapping printed inline after a dash.
1123                self.inline_map_after_dash = true;
1124            } else if was_inline_value {
1125                // Map used as a value after "key: ". If an anchor was emitted, we are already at
1126                // the start of a new line due to write_anchor_for_complex_node() -> newline().
1127                // Only add a newline if we are not already at line start (i.e., no anchor emitted).
1128                self.pending_space_after_colon = false;
1129                if !self.at_line_start {
1130                    self.newline()?;
1131                }
1132            }
1133            // Indentation rules:
1134            // - Top-level (at line start, not after dash): use current depth.
1135            // - After dash inline first key or as a value: indent one level deeper for subsequent lines.
1136            // Use the current mapping's depth as base only when we are in a VALUE position.
1137            // For complex KEYS (non-scalar), keep using the current serializer depth so that
1138            // subsequent key lines indent relative to the "? " line, not the parent map's base.
1139            let base = if inline_first {
1140                self.after_dash_depth.unwrap_or(self.depth)
1141            } else if was_inline_value && self.current_map_depth.is_some() {
1142                self.current_map_depth.unwrap_or(self.depth)
1143            } else {
1144                self.depth
1145            };
1146            let depth_next = if inline_first || was_inline_value {
1147                base + 1
1148            } else {
1149                base
1150            };
1151            Ok(MapSer {
1152                ser: self,
1153                depth: depth_next,
1154                flow: false,
1155                first: true,
1156                last_key_complex: false,
1157            })
1158        }
1159    }
1160
1161    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
1162        self.serialize_map(None)
1163    }
1164
1165    fn serialize_struct_variant(
1166        self,
1167        _name: &'static str,
1168        _variant_index: u32,
1169        variant: &'static str,
1170        _len: usize,
1171    ) -> Result<Self::SerializeStructVariant> {
1172        // If we are the value of a mapping key, YAML forbids keeping a nested mapping
1173        // on the same line (e.g., "key: Variant:"). Move the variant mapping to the next line
1174        // indented under the parent mapping's base depth.
1175        let _was_inline_value = !self.at_line_start;
1176        if self.pending_space_after_colon {
1177            // Value position after a map key: start the variant mapping on the next line.
1178            self.pending_space_after_colon = false;
1179            self.newline()?;
1180            // Indent the variant name one level under the parent mapping.
1181            let base = self.current_map_depth.unwrap_or(self.depth) + 1;
1182            self.write_indent(base)?;
1183            self.write_plain_or_quoted(variant)?;
1184            self.out.write_str(":\n")?;
1185            self.at_line_start = true;
1186            // Fields indent one more level under the variant label.
1187            let depth_next = base + 1;
1188            return Ok(StructVariantSer {
1189                ser: self,
1190                depth: depth_next,
1191            });
1192        }
1193        // Otherwise (top-level or sequence context), emit the variant name at current depth.
1194        if self.at_line_start {
1195            self.write_indent(self.depth)?;
1196        }
1197        self.write_plain_or_quoted(variant)?;
1198        self.out.write_str(":\n")?;
1199        self.at_line_start = true;
1200        // Default indentation for fields under a plain variant line.
1201        let mut depth_next = self.depth + 1;
1202        // If this variant follows a list dash, indent two levels under the dash (one for the element, one for the mapping).
1203        if let Some(d) = self.after_dash_depth.take() {
1204            depth_next = d + 2;
1205            self.pending_inline_map = false;
1206        }
1207        Ok(StructVariantSer {
1208            ser: self,
1209            depth: depth_next,
1210        })
1211    }
1212}
1213
1214// ------------------------------------------------------------
1215// Seq / Tuple serializers
1216// ------------------------------------------------------------
1217
1218/// Serializer for sequences and tuples.
1219///
1220/// Created by `YamlSer::serialize_seq`/`serialize_tuple`. Holds a mutable
1221/// reference to the parent serializer and formatting state for the sequence.
1222pub struct SeqSer<'a, 'b, W: Write> {
1223    /// Parent YAML serializer.
1224    ser: &'a mut YamlSer<'b, W>,
1225    /// Target indentation depth for block-style items.
1226    depth: usize,
1227    /// Whether the sequence is being written in flow style (`[a, b]`).
1228    flow: bool,
1229    /// Whether the next element is the first (comma handling in flow style).
1230    first: bool,
1231}
1232
1233impl<'a, 'b, W: Write> SerializeTuple for SeqSer<'a, 'b, W> {
1234    type Ok = ();
1235    type Error = Error;
1236
1237    fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<()> {
1238        SerializeSeq::serialize_element(self, v)
1239    }
1240    fn end(self) -> Result<()> {
1241        SerializeSeq::end(self)
1242    }
1243}
1244
1245// Re-implement SerializeSeq for SeqSer with correct end.
1246impl<'a, 'b, W: Write> SerializeSeq for SeqSer<'a, 'b, W> {
1247    type Ok = ();
1248    type Error = Error;
1249
1250    fn serialize_element<T: ?Sized + Serialize>(&mut self, v: &T) -> Result<()> {
1251        if self.flow {
1252            if !self.first {
1253                self.ser.out.write_str(", ")?;
1254            }
1255            self.ser.with_in_flow(|s| v.serialize(s))?;
1256        } else {
1257            // If previous element was an inline map after a dash, just clear the flag; do not change depth.
1258            if !self.first && self.ser.inline_map_after_dash {
1259                self.ser.inline_map_after_dash = false;
1260            }
1261            if self.first && (!self.ser.at_line_start || self.ser.pending_inline_map) {
1262                // Inline the first element of this nested sequence right after the outer dash
1263                // (either we are already mid-line, or the parent staged inline via pending_inline_map).
1264                // Do not write indentation here.
1265            } else {
1266                self.ser.write_indent(self.depth)?;
1267            }
1268            self.ser.out.write_str("- ")?;
1269            self.ser.at_line_start = false;
1270            if self.first && self.ser.inline_map_after_dash {
1271                // We consumed the inline-after-dash behavior for this child sequence.
1272                self.ser.inline_map_after_dash = false;
1273            }
1274            // Capture the dash's indentation depth for potential struct-variant that follows.
1275            self.ser.after_dash_depth = Some(self.depth);
1276            // Hint to emit first key/element of a following mapping/sequence inline on the same line.
1277            self.ser.pending_inline_map = true;
1278            v.serialize(&mut *self.ser)?;
1279        }
1280        self.first = false;
1281        Ok(())
1282    }
1283
1284    fn end(self) -> Result<()> {
1285        if self.flow {
1286            let me = self;
1287            me.ser.out.write_str("]")?;
1288            if me.ser.in_flow == 0 {
1289                me.ser.newline()?;
1290            }
1291        }
1292        Ok(())
1293    }
1294}
1295
1296// Tuple-struct serializer (normal or anchor payload)
1297/// Serializer for tuple-structs.
1298///
1299/// Used for three shapes:
1300/// - Normal tuple-structs (treated like sequences in block style),
1301/// - Internal strong-anchor payloads (`__yaml_anchor`),
1302/// - Internal weak-anchor payloads (`__yaml_weak_anchor`).
1303pub struct TupleSer<'a, 'b, W: Write> {
1304    /// Parent YAML serializer.
1305    ser: &'a mut YamlSer<'b, W>,
1306    /// Variant describing how to interpret fields.
1307    kind: TupleKind,
1308    /// Current field index being serialized.
1309    idx: usize,
1310    /// For normal tuples: target indentation depth.
1311    /// For weak/strong: temporary storage (ptr id or state).
1312    depth_for_normal: usize,
1313
1314    // ---- Extra fields for refactoring/perf/correctness ----
1315    /// For strong anchors: if Some(id) then we must emit an alias instead of a definition at field #2.
1316    strong_alias_id: Option<AnchorId>,
1317    /// For weak anchors: whether the `present` flag was true.
1318    weak_present: bool,
1319    /// Skip serializing the 3rd field (value) in weak case if present==false.
1320    skip_third: bool,
1321    /// For weak anchors: hold alias id if value should be emitted as alias in field #3.
1322    weak_alias_id: Option<AnchorId>,
1323    /// For commented wrapper: captured comment text from field #0.
1324    comment_text: Option<String>,
1325}
1326enum TupleKind {
1327    Normal,       // treat as block seq
1328    AnchorStrong, // [ptr, value]
1329    AnchorWeak,   // [ptr, present, value]
1330    Commented,    // [comment, value]
1331}
1332impl<'a, 'b, W: Write> TupleSer<'a, 'b, W> {
1333    /// Create a tuple serializer for normal tuple-structs.
1334    fn normal(ser: &'a mut YamlSer<'b, W>) -> Self {
1335        let depth_next = ser.depth + 1;
1336        Self {
1337            ser,
1338            kind: TupleKind::Normal,
1339            idx: 0,
1340            depth_for_normal: depth_next,
1341            strong_alias_id: None,
1342            weak_present: false,
1343            skip_third: false,
1344            weak_alias_id: None,
1345            comment_text: None,
1346        }
1347    }
1348    /// Create a tuple serializer for internal strong-anchor payloads.
1349    fn anchor_strong(ser: &'a mut YamlSer<'b, W>) -> Self {
1350        Self {
1351            ser,
1352            kind: TupleKind::AnchorStrong,
1353            idx: 0,
1354            depth_for_normal: 0,
1355            strong_alias_id: None,
1356            weak_present: false,
1357            skip_third: false,
1358            weak_alias_id: None,
1359            comment_text: None,
1360        }
1361    }
1362    /// Create a tuple serializer for internal weak-anchor payloads.
1363    fn anchor_weak(ser: &'a mut YamlSer<'b, W>) -> Self {
1364        Self {
1365            ser,
1366            kind: TupleKind::AnchorWeak,
1367            idx: 0,
1368            depth_for_normal: 0,
1369            strong_alias_id: None,
1370            weak_present: false,
1371            skip_third: false,
1372            weak_alias_id: None,
1373            comment_text: None,
1374        }
1375    }
1376    /// Create a tuple serializer for internal commented wrapper.
1377    fn commented(ser: &'a mut YamlSer<'b, W>) -> Self {
1378        Self {
1379            ser,
1380            kind: TupleKind::Commented,
1381            idx: 0,
1382            depth_for_normal: 0,
1383            strong_alias_id: None,
1384            weak_present: false,
1385            skip_third: false,
1386            weak_alias_id: None,
1387            comment_text: None,
1388        }
1389    }
1390}
1391
1392impl<'a, 'b, W: Write> SerializeTupleStruct for TupleSer<'a, 'b, W> {
1393    type Ok = ();
1394    type Error = Error;
1395
1396    fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1397        match self.kind {
1398            TupleKind::Normal => {
1399                if self.idx == 0 {
1400                    self.ser.write_anchor_for_complex_node()?;
1401                    if !self.ser.at_line_start {
1402                        self.ser.newline()?;
1403                    }
1404                }
1405                self.ser.write_indent(self.ser.depth + 1)?;
1406                self.ser.out.write_str("- ")?;
1407                self.ser.at_line_start = false;
1408                value.serialize(&mut *self.ser)?;
1409            }
1410            TupleKind::AnchorStrong => {
1411                match self.idx {
1412                    0 => {
1413                        // capture ptr, decide define vs alias
1414                        let mut cap = UsizeCapture::default();
1415                        value.serialize(&mut cap)?;
1416                        let ptr = cap.finish()?;
1417                        let (id, fresh) = self.ser.alloc_anchor_for(ptr);
1418                        if fresh {
1419                            self.ser.pending_anchor_id = Some(id); // define before value
1420                            self.strong_alias_id = None;
1421                        } else {
1422                            self.strong_alias_id = Some(id); // alias instead of value
1423                        }
1424                    }
1425                    1 => {
1426                        if let Some(id) = self.strong_alias_id.take() {
1427                            // Already defined earlier -> emit alias
1428                            self.ser.write_alias_id(id)?;
1429                        } else {
1430                            // First sight -> serialize value; pending_anchor_id (if any) will be emitted
1431                            value.serialize(&mut *self.ser)?;
1432                        }
1433                    }
1434                    _ => return Err(Error::unexpected("unexpected field in __yaml_anchor")),
1435                }
1436            }
1437            TupleKind::AnchorWeak => {
1438                match self.idx {
1439                    0 => {
1440                        let mut cap = UsizeCapture::default();
1441                        value.serialize(&mut cap)?;
1442                        let ptr = cap.finish()?;
1443                        self.depth_for_normal = ptr; // store ptr for fields #2/#3
1444                    }
1445                    1 => {
1446                        let mut bc = BoolCapture::default();
1447                        value.serialize(&mut bc)?;
1448                        self.weak_present = bc.finish()?;
1449                        if !self.weak_present {
1450                            // present == false: emit null and skip field #3
1451                            if self.ser.at_line_start {
1452                                self.ser.write_indent(self.ser.depth)?;
1453                            }
1454                            self.ser.out.write_str("null")?;
1455                            if self.ser.in_flow == 0 {
1456                                self.ser.newline()?;
1457                            }
1458                            self.skip_third = true;
1459                        } else {
1460                            let ptr = self.depth_for_normal;
1461                            let (id, fresh) = self.ser.alloc_anchor_for(ptr);
1462                            if fresh {
1463                                self.ser.pending_anchor_id = Some(id); // define before value
1464                                self.weak_alias_id = None;
1465                            } else {
1466                                self.weak_alias_id = Some(id); // alias in field #3
1467                            }
1468                        }
1469                    }
1470                    2 => {
1471                        if self.skip_third {
1472                            // nothing to do
1473                        } else if let Some(id) = self.weak_alias_id.take() {
1474                            self.ser.write_alias_id(id)?;
1475                        } else {
1476                            // definition path: pending_anchor_id (if any) will be placed automatically
1477                            value.serialize(&mut *self.ser)?;
1478                        }
1479                    }
1480                    _ => return Err(Error::unexpected("unexpected field in __yaml_weak_anchor")),
1481                }
1482            }
1483            TupleKind::Commented => {
1484                match self.idx {
1485                    0 => {
1486                        // Capture comment string
1487                        let mut sc = StrCapture::default();
1488                        value.serialize(&mut sc)?;
1489                        self.comment_text = Some(sc.finish()?);
1490                    }
1491                    1 => {
1492                        let comment = self.comment_text.take().unwrap_or_default();
1493                        let is_scalar = scalar_key_to_string(value).is_ok();
1494                        if is_scalar && self.ser.in_flow == 0 {
1495                            // Serialize the scalar without trailing newline and then append the comment.
1496                            self.ser.with_in_flow(|s| {
1497                                value.serialize(&mut *s)?;
1498                                if !comment.is_empty() {
1499                                    s.out.write_str(" # ")?;
1500                                    // Replace newlines in comment with spaces to keep it on one line
1501                                    let sanitized = comment.replace('\n', " ");
1502                                    s.out.write_str(&sanitized)?;
1503                                }
1504                                Ok(())
1505                            })?;
1506                            // End the line after leaving the flow context
1507                            self.ser.newline()?;
1508                        } else {
1509                            // Complex value or inside flow: just serialize the value, ignore the comment
1510                            value.serialize(&mut *self.ser)?;
1511                        }
1512                    }
1513                    _ => return Err(Error::unexpected("unexpected field in __yaml_commented")),
1514                }
1515            }
1516        }
1517        self.idx += 1;
1518        Ok(())
1519    }
1520
1521    fn end(self) -> Result<()> {
1522        Ok(())
1523    }
1524}
1525
1526// Tuple variant (enum Variant: ( ... ))
1527/// Serializer for tuple variants (enum Variant: ( ... )).
1528///
1529/// Created by `YamlSer::serialize_tuple_variant` to emit the variant name
1530/// followed by a block sequence of fields.
1531pub struct TupleVariantSer<'a, 'b, W: Write> {
1532    /// Parent YAML serializer.
1533    ser: &'a mut YamlSer<'b, W>,
1534    /// Target indentation depth for the fields.
1535    depth: usize,
1536}
1537impl<'a, 'b, W: Write> SerializeTupleVariant for TupleVariantSer<'a, 'b, W> {
1538    type Ok = ();
1539    type Error = Error;
1540
1541    fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1542        self.ser.write_indent(self.depth)?;
1543        self.ser.out.write_str("- ")?;
1544        self.ser.at_line_start = false;
1545        value.serialize(&mut *self.ser)
1546    }
1547    fn end(self) -> Result<()> {
1548        Ok(())
1549    }
1550}
1551
1552// ------------------------------------------------------------
1553// Map / Struct serializers
1554// ------------------------------------------------------------
1555
1556/// Serializer for maps and structs.
1557///
1558/// Created by `YamlSer::serialize_map`/`serialize_struct`. Manages indentation
1559/// and flow/block style for key-value pairs.
1560pub struct MapSer<'a, 'b, W: Write> {
1561    /// Parent YAML serializer.
1562    ser: &'a mut YamlSer<'b, W>,
1563    /// Target indentation depth for block-style entries.
1564    depth: usize,
1565    /// Whether the mapping is in flow style (`{k: v}`).
1566    flow: bool,
1567    /// Whether the next entry is the first (comma handling in flow style).
1568    first: bool,
1569    /// Whether the most recently serialized key was a complex (non-scalar) node.
1570    last_key_complex: bool,
1571}
1572
1573impl<'a, 'b, W: Write> SerializeMap for MapSer<'a, 'b, W> {
1574    type Ok = ();
1575    type Error = Error;
1576
1577    fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<()> {
1578        if self.flow {
1579            if !self.first {
1580                self.ser.out.write_str(", ")?;
1581            }
1582            let text = scalar_key_to_string(key)?;
1583            self.ser.out.write_str(&text)?;
1584            self.ser.out.write_str(": ")?;
1585            self.ser.at_line_start = false;
1586            self.last_key_complex = false;
1587        } else {
1588            match scalar_key_to_string(key) {
1589                Ok(text) => {
1590                    if !self.ser.at_line_start {
1591                        self.ser.write_space_if_pending()?;
1592                    }
1593                    self.ser.write_indent(self.depth)?;
1594                    self.ser.out.write_str(&text)?;
1595                    // Defer the decision to put a space vs. newline until we see the value type.
1596                    self.ser.out.write_str(":")?;
1597                    self.ser.pending_space_after_colon = true;
1598                    self.ser.at_line_start = false;
1599                    self.last_key_complex = false;
1600                }
1601                Err(Error::Unexpected { msg }) if msg == "non-scalar key" => {
1602                    if !self.ser.at_line_start {
1603                        self.ser.write_space_if_pending()?;
1604                    }
1605                    self.ser.write_anchor_for_complex_node()?;
1606                    self.ser.write_indent(self.depth)?;
1607                    self.ser.out.write_str("? ")?;
1608                    self.ser.at_line_start = false;
1609
1610                    let saved_depth = self.ser.depth;
1611                    let saved_current_map_depth = self.ser.current_map_depth;
1612                    let saved_pending_inline_map = self.ser.pending_inline_map;
1613                    let saved_inline_map_after_dash = self.ser.inline_map_after_dash;
1614                    let saved_after_dash_depth = self.ser.after_dash_depth;
1615
1616                    self.ser.pending_inline_map = true;
1617                    self.ser.depth = self.depth;
1618                    // Provide a base depth for nested maps within this complex key so that
1619                    // continuation lines indent one level deeper than the parent mapping.
1620                    self.ser.current_map_depth = Some(self.depth);
1621                    self.ser.after_dash_depth = None;
1622                    key.serialize(&mut *self.ser)?;
1623
1624                    self.ser.depth = saved_depth;
1625                    self.ser.current_map_depth = saved_current_map_depth;
1626                    self.ser.pending_inline_map = saved_pending_inline_map;
1627                    self.ser.inline_map_after_dash = saved_inline_map_after_dash;
1628                    self.ser.after_dash_depth = saved_after_dash_depth;
1629                    self.last_key_complex = true;
1630                }
1631                Err(e) => return Err(e),
1632            }
1633        }
1634        Ok(())
1635    }
1636
1637    fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
1638        if self.flow {
1639            self.ser.with_in_flow(|s| value.serialize(s))?;
1640        } else {
1641            let saved_pending_inline_map = self.ser.pending_inline_map;
1642            let saved_depth = self.ser.depth;
1643            if self.last_key_complex {
1644                self.ser.write_indent(self.depth)?;
1645                self.ser.out.write_str(":")?;
1646                self.ser.pending_space_after_colon = true;
1647                self.ser.pending_inline_map = true;
1648                self.ser.at_line_start = false;
1649                self.ser.depth = self.depth;
1650            }
1651            let prev_map_depth = self.ser.current_map_depth.replace(self.depth);
1652            let result = value.serialize(&mut *self.ser);
1653            self.ser.current_map_depth = prev_map_depth;
1654            // Always restore the parent's pending_inline_map to avoid leaking inline hints
1655            // across sibling values (e.g., after finishing a sequence value like `groups`).
1656            self.ser.pending_inline_map = saved_pending_inline_map;
1657            if self.last_key_complex {
1658                self.ser.depth = saved_depth;
1659                self.last_key_complex = false;
1660            }
1661            result?;
1662        }
1663        self.first = false;
1664        Ok(())
1665    }
1666
1667    fn end(self) -> Result<()> {
1668        if self.flow {
1669            self.ser.out.write_str("}")?;
1670            if self.ser.in_flow == 0 {
1671                self.ser.newline()?;
1672            }
1673        } else if self.first {
1674            self.ser.newline()?;
1675        }
1676        Ok(())
1677    }
1678}
1679impl<'a, 'b, W: Write> SerializeStruct for MapSer<'a, 'b, W> {
1680    type Ok = ();
1681    type Error = Error;
1682
1683    fn serialize_field<T: ?Sized + Serialize>(
1684        &mut self,
1685        key: &'static str,
1686        value: &T,
1687    ) -> Result<()> {
1688        SerializeMap::serialize_key(self, &key)?;
1689        SerializeMap::serialize_value(self, value)
1690    }
1691    fn end(self) -> Result<()> {
1692        SerializeMap::end(self)
1693    }
1694}
1695
1696/// Serializer for struct variants (enum Variant: { ... }).
1697///
1698/// Created by `YamlSer::serialize_struct_variant` to emit the variant name
1699/// followed by a block mapping of fields.
1700pub struct StructVariantSer<'a, 'b, W: Write> {
1701    /// Parent YAML serializer.
1702    ser: &'a mut YamlSer<'b, W>,
1703    /// Target indentation depth for the fields.
1704    depth: usize,
1705}
1706impl<'a, 'b, W: Write> SerializeStructVariant for StructVariantSer<'a, 'b, W> {
1707    type Ok = ();
1708    type Error = Error;
1709
1710    fn serialize_field<T: ?Sized + Serialize>(
1711        &mut self,
1712        key: &'static str,
1713        value: &T,
1714    ) -> Result<()> {
1715        let text = scalar_key_to_string(&key)?;
1716        self.ser.write_indent(self.depth)?;
1717        self.ser.out.write_str(&text)?;
1718        // Defer spacing/newline decision to the value serializer similarly to map entries.
1719        self.ser.out.write_str(":")?;
1720        self.ser.pending_space_after_colon = true;
1721        self.ser.at_line_start = false;
1722        // Ensure nested mappings/collections used as this field's value indent relative to this struct variant.
1723        let prev_map_depth = self.ser.current_map_depth.replace(self.depth);
1724        let result = value.serialize(&mut *self.ser);
1725        self.ser.current_map_depth = prev_map_depth;
1726        result
1727    }
1728    fn end(self) -> Result<()> {
1729        Ok(())
1730    }
1731}
1732
1733// ------------------------------------------------------------
1734// Helpers used for extracting ptr/bool inside tuple payloads
1735// ------------------------------------------------------------
1736
1737/// Minimal serializer that captures a numeric `usize` from a serialized field.
1738///
1739/// Used internally to read the raw pointer value encoded as the first field
1740/// of our internal anchor tuple payloads.
1741#[derive(Default)]
1742struct UsizeCapture {
1743    v: Option<usize>,
1744}
1745impl<'a> Serializer for &'a mut UsizeCapture {
1746    type Ok = ();
1747    type Error = Error;
1748
1749    type SerializeSeq = ser::Impossible<(), Error>;
1750    type SerializeTuple = ser::Impossible<(), Error>;
1751    type SerializeTupleStruct = ser::Impossible<(), Error>;
1752    type SerializeTupleVariant = ser::Impossible<(), Error>;
1753    type SerializeMap = ser::Impossible<(), Error>;
1754    type SerializeStruct = ser::Impossible<(), Error>;
1755    type SerializeStructVariant = ser::Impossible<(), Error>;
1756
1757    fn serialize_i8(self, v: i8) -> Result<()> {
1758        self.v = Some(v as usize);
1759        Ok(())
1760    }
1761    fn serialize_i16(self, v: i16) -> Result<()> {
1762        self.v = Some(v as usize);
1763        Ok(())
1764    }
1765    fn serialize_i32(self, v: i32) -> Result<()> {
1766        self.v = Some(v as usize);
1767        Ok(())
1768    }
1769    fn serialize_i64(self, v: i64) -> Result<()> {
1770        self.v = Some(v as usize);
1771        Ok(())
1772    }
1773    fn serialize_u8(self, v: u8) -> Result<()> {
1774        self.v = Some(v as usize);
1775        Ok(())
1776    }
1777    fn serialize_u16(self, v: u16) -> Result<()> {
1778        self.v = Some(v as usize);
1779        Ok(())
1780    }
1781    fn serialize_u32(self, v: u32) -> Result<()> {
1782        self.v = Some(v as usize);
1783        Ok(())
1784    }
1785    fn serialize_u64(self, v: u64) -> Result<()> {
1786        self.v = Some(v as usize);
1787        Ok(())
1788    }
1789    fn serialize_f32(self, v: f32) -> Result<()> {
1790        self.v = Some(v as usize);
1791        Ok(())
1792    }
1793    fn serialize_f64(self, v: f64) -> Result<()> {
1794        self.v = Some(v as usize);
1795        Ok(())
1796    }
1797    fn serialize_bool(self, v: bool) -> Result<()> {
1798        self.v = Some(v as usize);
1799        Ok(())
1800    }
1801    fn serialize_char(self, _v: char) -> Result<()> {
1802        Err(Error::unexpected("ptr expects number"))
1803    }
1804    fn serialize_str(self, _v: &str) -> Result<()> {
1805        Err(Error::unexpected("ptr expects number"))
1806    }
1807    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
1808        Err(Error::unexpected("ptr expects number"))
1809    }
1810    fn serialize_none(self) -> Result<()> {
1811        Err(Error::unexpected("ptr cannot be none"))
1812    }
1813    fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<()> {
1814        Err(Error::unexpected("ptr not option"))
1815    }
1816    fn serialize_unit(self) -> Result<()> {
1817        Err(Error::unexpected("ptr cannot be unit"))
1818    }
1819    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
1820        unexpected_e()
1821    }
1822    fn serialize_unit_variant(self, _name: &'static str, _i: u32, _v: &'static str) -> Result<()> {
1823        unexpected_e()
1824    }
1825    fn serialize_newtype_struct<T: ?Sized + Serialize>(
1826        self,
1827        _name: &'static str,
1828        _value: &T,
1829    ) -> Result<()> {
1830        unexpected_e()
1831    }
1832    fn serialize_newtype_variant<T: ?Sized + Serialize>(
1833        self,
1834        _name: &'static str,
1835        _i: u32,
1836        _v: &'static str,
1837        _value: &T,
1838    ) -> Result<()> {
1839        unexpected_e()
1840    }
1841    fn serialize_seq(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
1842        unexpected()
1843    }
1844    fn serialize_tuple(self, _len: usize) -> Result<ser::Impossible<(), Error>> {
1845        unexpected()
1846    }
1847    fn serialize_tuple_struct(
1848        self,
1849        _name: &'static str,
1850        _len: usize,
1851    ) -> Result<ser::Impossible<(), Error>> {
1852        unexpected()
1853    }
1854    fn serialize_tuple_variant(
1855        self,
1856        _name: &'static str,
1857        _i: u32,
1858        _v: &'static str,
1859        _len: usize,
1860    ) -> Result<ser::Impossible<(), Error>> {
1861        unexpected()
1862    }
1863    fn serialize_map(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
1864        unexpected()
1865    }
1866    fn serialize_struct(
1867        self,
1868        _name: &'static str,
1869        _len: usize,
1870    ) -> Result<ser::Impossible<(), Error>> {
1871        unexpected()
1872    }
1873    fn serialize_struct_variant(
1874        self,
1875        _name: &'static str,
1876        _i: u32,
1877        _v: &'static str,
1878        _len: usize,
1879    ) -> Result<ser::Impossible<(), Error>> {
1880        unexpected()
1881    }
1882    fn collect_str<T: ?Sized + fmt::Display>(self, _value: &T) -> Result<()> {
1883        unexpected_e()
1884    }
1885    fn is_human_readable(&self) -> bool {
1886        true
1887    }
1888}
1889impl UsizeCapture {
1890    fn finish(self) -> Result<usize> {
1891        self.v
1892            .ok_or_else(|| Error::unexpected("missing numeric ptr"))
1893    }
1894}
1895
1896/// Minimal serializer that captures a boolean from a serialized field.
1897///
1898/// Used internally to read the `present` flag from weak-anchor payloads.
1899#[derive(Default)]
1900struct BoolCapture {
1901    v: Option<bool>,
1902}
1903impl<'a> Serializer for &'a mut BoolCapture {
1904    type Ok = ();
1905    type Error = Error;
1906
1907    type SerializeSeq = ser::Impossible<(), Error>;
1908    type SerializeTuple = ser::Impossible<(), Error>;
1909    type SerializeTupleStruct = ser::Impossible<(), Error>;
1910    type SerializeTupleVariant = ser::Impossible<(), Error>;
1911    type SerializeMap = ser::Impossible<(), Error>;
1912    type SerializeStruct = ser::Impossible<(), Error>;
1913    type SerializeStructVariant = ser::Impossible<(), Error>;
1914
1915    fn serialize_bool(self, v: bool) -> Result<()> {
1916        self.v = Some(v);
1917        Ok(())
1918    }
1919    fn serialize_i8(self, _v: i8) -> Result<()> {
1920        Err(Error::unexpected("bool expected"))
1921    }
1922    fn serialize_i16(self, _v: i16) -> Result<()> {
1923        Err(Error::unexpected("bool expected"))
1924    }
1925    fn serialize_i32(self, _v: i32) -> Result<()> {
1926        Err(Error::unexpected("bool expected"))
1927    }
1928    fn serialize_i64(self, _v: i64) -> Result<()> {
1929        Err(Error::unexpected("bool expected"))
1930    }
1931    fn serialize_u8(self, _v: u8) -> Result<()> {
1932        Err(Error::unexpected("bool expected"))
1933    }
1934    fn serialize_u16(self, _v: u16) -> Result<()> {
1935        Err(Error::unexpected("bool expected"))
1936    }
1937    fn serialize_u32(self, _v: u32) -> Result<()> {
1938        Err(Error::unexpected("bool expected"))
1939    }
1940    fn serialize_u64(self, _v: u64) -> Result<()> {
1941        Err(Error::unexpected("bool expected"))
1942    }
1943    fn serialize_f32(self, _v: f32) -> Result<()> {
1944        Err(Error::unexpected("bool expected"))
1945    }
1946    fn serialize_f64(self, _v: f64) -> Result<()> {
1947        Err(Error::unexpected("bool expected"))
1948    }
1949    fn serialize_char(self, _c: char) -> Result<()> {
1950        Err(Error::unexpected("bool expected"))
1951    }
1952    fn serialize_str(self, _v: &str) -> Result<()> {
1953        Err(Error::unexpected("bool expected"))
1954    }
1955    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
1956        Err(Error::unexpected("bool expected"))
1957    }
1958    fn serialize_none(self) -> Result<()> {
1959        Err(Error::unexpected("bool expected"))
1960    }
1961    fn serialize_some<T: ?Sized + Serialize>(self, _v: &T) -> Result<()> {
1962        Err(Error::unexpected("bool expected"))
1963    }
1964    fn serialize_unit(self) -> Result<()> {
1965        Err(Error::unexpected("bool expected"))
1966    }
1967    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
1968        unexpected_e()
1969    }
1970    fn serialize_unit_variant(self, _name: &'static str, _i: u32, _v: &'static str) -> Result<()> {
1971        unexpected_e()
1972    }
1973    fn serialize_newtype_struct<T: ?Sized + Serialize>(
1974        self,
1975        _name: &'static str,
1976        _value: &T,
1977    ) -> Result<()> {
1978        unexpected_e()
1979    }
1980    fn serialize_newtype_variant<T: ?Sized + Serialize>(
1981        self,
1982        _name: &'static str,
1983        _i: u32,
1984        _v: &'static str,
1985        _value: &T,
1986    ) -> Result<()> {
1987        unexpected_e()
1988    }
1989    fn serialize_seq(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
1990        unexpected()
1991    }
1992    fn serialize_tuple(self, _len: usize) -> Result<ser::Impossible<(), Error>> {
1993        unexpected()
1994    }
1995    fn serialize_tuple_struct(
1996        self,
1997        _name: &'static str,
1998        _len: usize,
1999    ) -> Result<ser::Impossible<(), Error>> {
2000        unexpected()
2001    }
2002    fn serialize_tuple_variant(
2003        self,
2004        _name: &'static str,
2005        _i: u32,
2006        _v: &'static str,
2007        _len: usize,
2008    ) -> Result<ser::Impossible<(), Error>> {
2009        unexpected()
2010    }
2011    fn serialize_map(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
2012        unexpected()
2013    }
2014    fn serialize_struct(
2015        self,
2016        _name: &'static str,
2017        _len: usize,
2018    ) -> Result<ser::Impossible<(), Error>> {
2019        unexpected()
2020    }
2021    fn serialize_struct_variant(
2022        self,
2023        _name: &'static str,
2024        _i: u32,
2025        _v: &'static str,
2026        _len: usize,
2027    ) -> Result<ser::Impossible<(), Error>> {
2028        unexpected()
2029    }
2030    fn collect_str<T: ?Sized + fmt::Display>(self, _value: &T) -> Result<()> {
2031        unexpected_e()
2032    }
2033    fn is_human_readable(&self) -> bool {
2034        true
2035    }
2036}
2037impl BoolCapture {
2038    fn finish(self) -> Result<bool> {
2039        self.v.ok_or_else(|| Error::unexpected("missing bool"))
2040    }
2041}
2042
2043/// Minimal serializer that captures a string from a serialized field.
2044///
2045/// Used internally to read the comment text for the Commented wrapper.
2046#[derive(Default)]
2047struct StrCapture {
2048    s: Option<String>,
2049}
2050impl<'a> Serializer for &'a mut StrCapture {
2051    type Ok = ();
2052    type Error = Error;
2053
2054    type SerializeSeq = ser::Impossible<(), Error>;
2055    type SerializeTuple = ser::Impossible<(), Error>;
2056    type SerializeTupleStruct = ser::Impossible<(), Error>;
2057    type SerializeTupleVariant = ser::Impossible<(), Error>;
2058    type SerializeMap = ser::Impossible<(), Error>;
2059    type SerializeStruct = ser::Impossible<(), Error>;
2060    type SerializeStructVariant = ser::Impossible<(), Error>;
2061
2062    fn serialize_str(self, v: &str) -> Result<()> {
2063        self.s = Some(v.to_string());
2064        Ok(())
2065    }
2066
2067    fn serialize_bool(self, _v: bool) -> Result<()> {
2068        unexpected_e()
2069    }
2070    fn serialize_i8(self, _v: i8) -> Result<()> {
2071        unexpected_e()
2072    }
2073    fn serialize_i16(self, _v: i16) -> Result<()> {
2074        unexpected_e()
2075    }
2076    fn serialize_i32(self, _v: i32) -> Result<()> {
2077        unexpected_e()
2078    }
2079    fn serialize_i64(self, _v: i64) -> Result<()> {
2080        unexpected_e()
2081    }
2082    fn serialize_i128(self, _v: i128) -> Result<()> {
2083        unexpected_e()
2084    }
2085    fn serialize_u8(self, _v: u8) -> Result<()> {
2086        unexpected_e()
2087    }
2088    fn serialize_u16(self, _v: u16) -> Result<()> {
2089        unexpected_e()
2090    }
2091    fn serialize_u32(self, _v: u32) -> Result<()> {
2092        unexpected_e()
2093    }
2094    fn serialize_u64(self, _v: u64) -> Result<()> {
2095        unexpected_e()
2096    }
2097    fn serialize_u128(self, _v: u128) -> Result<()> {
2098        unexpected_e()
2099    }
2100    fn serialize_f32(self, _v: f32) -> Result<()> {
2101        unexpected_e()
2102    }
2103    fn serialize_f64(self, _v: f64) -> Result<()> {
2104        unexpected_e()
2105    }
2106    fn serialize_char(self, _c: char) -> Result<()> {
2107        unexpected_e()
2108    }
2109    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
2110        unexpected_e()
2111    }
2112    fn serialize_none(self) -> Result<()> {
2113        unexpected_e()
2114    }
2115    fn serialize_some<T: ?Sized + Serialize>(self, _value: &T) -> Result<()> {
2116        unexpected_e()
2117    }
2118    fn serialize_unit(self) -> Result<()> {
2119        unexpected_e()
2120    }
2121    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
2122        unexpected_e()
2123    }
2124    fn serialize_unit_variant(self, _name: &'static str, _i: u32, _v: &'static str) -> Result<()> {
2125        unexpected_e()
2126    }
2127    fn serialize_newtype_struct<T: ?Sized + Serialize>(
2128        self,
2129        _name: &'static str,
2130        _value: &T,
2131    ) -> Result<()> {
2132        unexpected_e()
2133    }
2134    fn serialize_newtype_variant<T: ?Sized + Serialize>(
2135        self,
2136        _name: &'static str,
2137        _i: u32,
2138        _v: &'static str,
2139        _value: &T,
2140    ) -> Result<()> {
2141        unexpected_e()
2142    }
2143    fn serialize_seq(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
2144        unexpected()
2145    }
2146    fn serialize_tuple(self, _len: usize) -> Result<ser::Impossible<(), Error>> {
2147        unexpected()
2148    }
2149    fn serialize_tuple_struct(
2150        self,
2151        _name: &'static str,
2152        _len: usize,
2153    ) -> Result<ser::Impossible<(), Error>> {
2154        unexpected()
2155    }
2156    fn serialize_tuple_variant(
2157        self,
2158        _name: &'static str,
2159        _i: u32,
2160        _v: &'static str,
2161        _len: usize,
2162    ) -> Result<ser::Impossible<(), Error>> {
2163        unexpected()
2164    }
2165    fn serialize_map(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
2166        unexpected()
2167    }
2168    fn serialize_struct(
2169        self,
2170        _name: &'static str,
2171        _len: usize,
2172    ) -> Result<ser::Impossible<(), Error>> {
2173        unexpected()
2174    }
2175    fn serialize_struct_variant(
2176        self,
2177        _name: &'static str,
2178        _i: u32,
2179        _v: &'static str,
2180        _len: usize,
2181    ) -> Result<ser::Impossible<(), Error>> {
2182        unexpected()
2183    }
2184    fn collect_str<T: ?Sized + fmt::Display>(self, _value: &T) -> Result<()> {
2185        unexpected_e()
2186    }
2187    fn is_human_readable(&self) -> bool {
2188        true
2189    }
2190}
2191impl StrCapture {
2192    fn finish(self) -> Result<String> {
2193        self.s.ok_or_else(|| Error::unexpected("missing string"))
2194    }
2195}
2196
2197// ------------------------------------------------------------
2198// Key scalar helper
2199// ------------------------------------------------------------
2200
2201/// Serialize a key using a restricted scalar-only serializer into a `String`.
2202///
2203/// Called by map/struct serializers to ensure YAML keys are scalars.
2204fn scalar_key_to_string<K: Serialize + ?Sized>(key: &K) -> Result<String> {
2205    let mut s = String::new();
2206    {
2207        let mut ks = KeyScalarSink { s: &mut s };
2208        key.serialize(&mut ks)?;
2209    }
2210    Ok(s)
2211}
2212
2213struct KeyScalarSink<'a> {
2214    s: &'a mut String,
2215}
2216
2217impl<'a> Serializer for &'a mut KeyScalarSink<'a> {
2218    type Ok = ();
2219    type Error = Error;
2220
2221    type SerializeSeq = ser::Impossible<(), Error>;
2222    type SerializeTuple = ser::Impossible<(), Error>;
2223    type SerializeTupleStruct = ser::Impossible<(), Error>;
2224    type SerializeTupleVariant = ser::Impossible<(), Error>;
2225    type SerializeMap = ser::Impossible<(), Error>;
2226    type SerializeStruct = ser::Impossible<(), Error>;
2227    type SerializeStructVariant = ser::Impossible<(), Error>;
2228
2229    fn serialize_bool(self, v: bool) -> Result<()> {
2230        self.s.push_str(if v { "true" } else { "false" });
2231        Ok(())
2232    }
2233    fn serialize_i64(self, v: i64) -> Result<()> {
2234        let _ = write!(self.s, "{}", v);
2235        Ok(())
2236    }
2237    fn serialize_i32(self, v: i32) -> Result<()> {
2238        self.serialize_i64(v as i64)
2239    }
2240    fn serialize_i16(self, v: i16) -> Result<()> {
2241        self.serialize_i64(v as i64)
2242    }
2243    fn serialize_i8(self, v: i8) -> Result<()> {
2244        self.serialize_i64(v as i64)
2245    }
2246    fn serialize_i128(self, v: i128) -> Result<()> {
2247        let _ = write!(self.s, "{}", v);
2248        Ok(())
2249    }
2250    fn serialize_u64(self, v: u64) -> Result<()> {
2251        let _ = write!(self.s, "{}", v);
2252        Ok(())
2253    }
2254    fn serialize_u32(self, v: u32) -> Result<()> {
2255        self.serialize_u64(v as u64)
2256    }
2257    fn serialize_u16(self, v: u16) -> Result<()> {
2258        self.serialize_u64(v as u64)
2259    }
2260    fn serialize_u8(self, v: u8) -> Result<()> {
2261        self.serialize_u64(v as u64)
2262    }
2263    fn serialize_u128(self, v: u128) -> Result<()> {
2264        let _ = write!(self.s, "{}", v);
2265        Ok(())
2266    }
2267    fn serialize_f32(self, v: f32) -> Result<()> {
2268        let v = v as f64;
2269        if v.is_nan() {
2270            self.s.push_str(".nan");
2271        } else if v.is_infinite() {
2272            if v.is_sign_positive() {
2273                self.s.push_str(".inf");
2274            } else {
2275                self.s.push_str("-.inf");
2276            }
2277        } else {
2278            let mut buf = ryu::Buffer::new();
2279            let s = buf.format(v);
2280            if !s.contains('.') && !s.contains('e') && !s.contains('E') {
2281                self.s.push_str(s);
2282                self.s.push_str(".0");
2283            } else {
2284                self.s.push_str(s);
2285            }
2286        }
2287        Ok(())
2288    }
2289    fn serialize_f64(self, v: f64) -> Result<()> {
2290        if v.is_nan() {
2291            self.s.push_str(".nan");
2292        } else if v.is_infinite() {
2293            if v.is_sign_positive() {
2294                self.s.push_str(".inf");
2295            } else {
2296                self.s.push_str("-.inf");
2297            }
2298        } else {
2299            let mut buf = ryu::Buffer::new();
2300            let s = buf.format(v);
2301            if !s.contains('.') && !s.contains('e') && !s.contains('E') {
2302                self.s.push_str(s);
2303                self.s.push_str(".0");
2304            } else {
2305                self.s.push_str(s);
2306            }
2307        }
2308        Ok(())
2309    }
2310    fn serialize_char(self, v: char) -> Result<()> {
2311        let mut buf = [0u8; 4];
2312        self.serialize_str(v.encode_utf8(&mut buf))
2313    }
2314    fn serialize_str(self, v: &str) -> Result<()> {
2315        if is_plain_safe(v) {
2316            self.s.push_str(v);
2317        } else {
2318            self.s.push('"');
2319            for ch in v.chars() {
2320                match ch {
2321                    '\\' => self.s.push_str("\\\\"),
2322                    '"' => self.s.push_str("\\\""),
2323                    '\n' => self.s.push_str("\\n"),
2324                    '\r' => self.s.push_str("\\r"),
2325                    '\t' => self.s.push_str("\\t"),
2326                    c if c.is_control() => {
2327                        use std::fmt::Write as _;
2328                        // Writing into a String cannot fail; ignore the Result to avoid unwrap.
2329                        let _ = write!(self.s, "\\u{:04X}", c as u32);
2330                    }
2331                    c => self.s.push(c),
2332                }
2333            }
2334            self.s.push('"');
2335        }
2336        Ok(())
2337    }
2338    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
2339        non_scalar_key_e()
2340    }
2341    fn serialize_none(self) -> Result<()> {
2342        self.s.push_str("null");
2343        Ok(())
2344    }
2345    fn serialize_some<T: ?Sized + Serialize>(self, v: &T) -> Result<()> {
2346        v.serialize(self)
2347    }
2348    fn serialize_unit(self) -> Result<()> {
2349        self.s.push_str("null");
2350        Ok(())
2351    }
2352    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
2353        self.serialize_unit()
2354    }
2355    fn serialize_unit_variant(
2356        self,
2357        _name: &'static str,
2358        _idx: u32,
2359        variant: &'static str,
2360    ) -> Result<()> {
2361        self.serialize_str(variant)
2362    }
2363    fn serialize_newtype_struct<T: ?Sized + Serialize>(
2364        self,
2365        _name: &'static str,
2366        _value: &T,
2367    ) -> Result<()> {
2368        non_scalar_key_e()
2369    }
2370    fn serialize_newtype_variant<T: ?Sized + Serialize>(
2371        self,
2372        _: &'static str,
2373        _: u32,
2374        _: &'static str,
2375        _: &T,
2376    ) -> Result<()> {
2377        non_scalar_key_e()
2378    }
2379    fn serialize_seq(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
2380        non_scalar_key()
2381    }
2382    fn serialize_tuple(self, _len: usize) -> Result<ser::Impossible<(), Error>> {
2383        non_scalar_key()
2384    }
2385    fn serialize_tuple_struct(
2386        self,
2387        _: &'static str,
2388        _: usize,
2389    ) -> Result<ser::Impossible<(), Error>> {
2390        non_scalar_key()
2391    }
2392    fn serialize_tuple_variant(
2393        self,
2394        _: &'static str,
2395        _: u32,
2396        _: &'static str,
2397        _: usize,
2398    ) -> Result<ser::Impossible<(), Error>> {
2399        non_scalar_key()
2400    }
2401    fn serialize_map(self, _len: Option<usize>) -> Result<ser::Impossible<(), Error>> {
2402        non_scalar_key()
2403    }
2404    fn serialize_struct(
2405        self,
2406        _name: &'static str,
2407        _len: usize,
2408    ) -> Result<ser::Impossible<(), Error>> {
2409        non_scalar_key()
2410    }
2411    fn serialize_struct_variant(
2412        self,
2413        _: &'static str,
2414        _: u32,
2415        _: &'static str,
2416        _: usize,
2417    ) -> Result<ser::Impossible<(), Error>> {
2418        non_scalar_key()
2419    }
2420    fn collect_str<T: ?Sized + fmt::Display>(self, v: &T) -> Result<()> {
2421        self.serialize_str(&v.to_string())
2422    }
2423    fn is_human_readable(&self) -> bool {
2424        true
2425    }
2426}
2427
2428fn unexpected() -> Result<ser::Impossible<(), Error>> {
2429    Err(Error::unexpected("unexpected"))
2430}
2431
2432fn unexpected_e() -> Result<()> {
2433    Err(Error::unexpected("unexpected"))
2434}
2435
2436fn non_scalar_key() -> Result<ser::Impossible<(), Error>> {
2437    Err(Error::unexpected("non-scalar key"))
2438}
2439
2440fn non_scalar_key_e() -> Result<()> {
2441    Err(Error::unexpected("non-scalar key"))
2442}