Skip to main content

serde_saphyr/ser/
options.rs

1//! Serializer options for YAML emission.
2//!
3//! Controls indentation and optional anchor name generation for the serializer.
4//!
5//! Example: use 4-space indentation and a custom anchor naming scheme.
6//!
7//! ```rust
8//! use serde::Serialize;
9//!
10//! #[derive(Serialize)]
11//! struct Item { a: i32, b: bool }
12//!
13//! let mut buf = String::new();
14//! let opts = serde_saphyr::ser_options! {
15//!     indent_step: 4,
16//!     anchor_generator: Some(|id| format!("id{}/", id)),
17//! };
18//! serde_saphyr::to_fmt_writer_with_options(&mut buf, &Item { a: 1, b: true }, opts).unwrap();
19//! assert!(buf.contains("a: 1"));
20//! ```
21
22use crate::ser_error::Error;
23
24/// Placement style for comments emitted by [`crate::Commented`].
25#[non_exhaustive]
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub enum CommentPosition {
28    /// Emit the comment inline on the right side from the item it describes (default)
29    Inline,
30    /// Emit the comment above the item it describes
31    Above,
32}
33
34/// Serializer options for YAML emission.
35///
36/// This struct controls various aspects of YAML serialization, such as indentation,
37/// anchor generation, and scalar styles.
38///
39/// Construct `SerializerOptions` using the [`ser_options!`](crate::ser_options!)
40/// macro to ensure compatibility with future updates.
41///
42/// ```rust
43/// use serde::Serialize;
44/// use serde_saphyr::{ser_options, to_string_with_options};
45///
46/// #[derive(Serialize)]
47/// struct Config {
48///     name: String,
49///     values: Vec<i32>,
50/// }
51///
52/// let config = Config {
53///     name: "test".to_string(),
54///     values: vec![1, 2, 3],
55/// };
56///
57/// // Use 4-space indentation and quote all strings
58/// let options = ser_options! {
59///     indent_step: 4,
60///     quote_all: true,
61/// };
62///
63/// let yaml = to_string_with_options(&config, options).unwrap();
64/// ```
65#[derive(Clone, Copy)]
66pub struct SerializerOptions {
67    /// If true, empty maps are emitted as braces {} and empty lists as []  (this is the default).
68    /// Such form is equally valid YAML, allows to tell empty from null and may be easier for a
69    /// human to grasp.
70    #[deprecated(
71        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
72    )]
73    pub empty_as_braces: bool,
74    /// Number of spaces to indent per nesting level when emitting block-style collections (2 by default).
75    /// 0 value is invalid and will result and error when trying to deserialize, because
76    /// no indentation would produce invalid YAML otherwise.
77    #[deprecated(
78        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
79    )]
80    pub indent_step: usize,
81    /// When enabled, emit list items with a more compact indentation style. On by default.
82    /// ```yaml
83    ///       containers:
84    ///       - env:
85    ///         - name: METHOD
86    ///           value: WATCH
87    /// ```
88    ///
89    /// Compared to a more expanded indentation style:
90    ///
91    /// ```yaml
92    ///       containers:
93    ///         - env:
94    ///             - name: METHOD
95    ///               value: WATCH
96    /// ```
97    #[deprecated(
98        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
99    )]
100    pub compact_list_indent: bool,
101    /// Optional custom anchor-name generator.
102    ///
103    /// Receives a monotonically increasing `usize` id (starting at 1) and returns the
104    /// anchor name to emit. If `None`, the built-in generator yields names like `a1`, `a2`, ...
105    #[deprecated(
106        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
107    )]
108    pub anchor_generator: Option<fn(usize) -> String>,
109    /// Threshold for block-string wrappers ([crate::LitStr]/[crate::FoldStr] and owned variants
110    /// [crate::LitString]/[crate::FoldString]).
111    ///
112    /// If the string contains a newline, block style is always used. Otherwise, when the
113    /// string is single-line and its length is strictly less than this threshold, the
114    /// serializer emits a normal YAML scalar (no block style). Longer strings use block
115    /// styles `|` or `>` depending on the wrapper. See the type docs for
116    /// [crate::LitStr], [crate::FoldStr], [crate::LitString] and [crate::FoldString] for
117    /// examples.
118    #[deprecated(
119        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
120    )]
121    pub min_fold_chars: usize,
122    /// Maximum width (in characters) for lines in folded block scalars (`>`).
123    ///
124    /// Lines are wrapped **only** at whitespace so that each emitted line is at most
125    /// this many characters long (excluding indentation). If no whitespace is present
126    /// within the limit (e.g., a single long token), the line is emitted unwrapped
127    /// to preserve round-trip correctness: YAML folded scalars typically fold inserted
128    /// newlines back as spaces when parsing. 32 default.
129    #[deprecated(
130        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
131    )]
132    pub folded_wrap_chars: usize,
133    /// When enabled, serialize simple enums that become a single scalar (unit variants)
134    /// using YAML tags, e.g. `!!Enum Variant` instead of a plain scalar `Variant`.
135    /// Deserializer does not need this setting as both cases will be understood. Off by default.
136    #[deprecated(
137        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
138    )]
139    pub tagged_enums: bool,
140
141    /// When enabled, strings containing more than folded_wrap_chars (80 by default) are written
142    /// in wrapped multistring folded form (>), and strings containing new lines are written in
143    /// literal form (|), selecting format depending on the number of empty lines at the end.
144    /// On by default.
145    #[deprecated(
146        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
147    )]
148    pub prefer_block_scalars: bool,
149
150    /// When enabled, quote all string scalars. Uses single quotes by default,
151    /// but switches to double quotes when the string contains escape sequences
152    /// (control characters like `\n`, `\t`, `\r`, backslash) or single quotes.
153    /// Disables block scalar styles (`|` and `>`) for quoted strings when active.
154    /// Off by default.
155    #[deprecated(
156        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
157    )]
158    pub quote_all: bool,
159
160    /// Controls where [`crate::Commented`] comments are emitted in block style.
161    ///
162    /// [`CommentPosition::Inline`] preserves the existing `value # comment` behavior for
163    /// scalars and aliases. [`CommentPosition::Above`] emits the comment on its own line
164    /// immediately before the wrapped value. Comments remain suppressed in flow-style
165    /// collections in both modes.
166    #[deprecated(
167        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
168    )]
169    pub comment_position: CommentPosition,
170
171    /// When enabled, emit `%YAML 1.2` at the beginning of the document and
172    /// use YAML 1.2 rules for certain compatibility heuristics.
173    ///
174    /// In particular, YAML 1.1 boolean spellings like `yes`/`no`/`on`/`off`/`y`/`n`
175    /// will **not** be treated as booleans for the purpose of auto-quoting. In cases
176    /// like multiple x, y coordinates quoting y may be very annoying.
177    /// Default: false.
178    #[deprecated(
179        note = "Direct construction of `SerializerOptions` will be disabled from 1.0.0, use macro `ser_options!`"
180    )]
181    pub yaml_12: bool,
182}
183
184// Below this length, block-string wrappers serialize as regular scalars
185// instead of YAML block styles. This keeps short values compact.
186pub(crate) const MIN_FOLD_CHARS: usize = 32;
187/// Maximum width (in characters) for lines inside folded block scalars.
188/// Lines will be wrapped at whitespace so that each emitted line is at most
189/// this many characters long (excluding indentation). If no whitespace is
190/// available within the limit, the line is not wrapped.
191pub(crate) const FOLDED_WRAP_CHARS: usize = 80;
192
193impl SerializerOptions {
194    #[allow(deprecated)]
195    pub(crate) fn consistent(&self) -> Result<(), Error> {
196        if self.indent_step == 0 {
197            return Err(Error::InvalidOptions(
198                "Invalid indent step must be positive".to_string(),
199            ));
200        }
201        Ok(())
202    }
203}
204
205impl Default for SerializerOptions {
206    #[allow(deprecated)]
207    fn default() -> Self {
208        // Defaults mirror internal constants used by the serializer.
209        Self {
210            indent_step: 2,
211            compact_list_indent: true,
212            anchor_generator: None,
213            min_fold_chars: MIN_FOLD_CHARS,
214            folded_wrap_chars: FOLDED_WRAP_CHARS,
215            tagged_enums: false,
216            empty_as_braces: true,
217            prefer_block_scalars: true,
218            quote_all: false,
219            comment_position: CommentPosition::Inline,
220            yaml_12: false,
221        }
222    }
223}