Skip to main content

serpent_serializer/
options.rs

1//! Serialization options.
2//!
3//! [`Options`] mirrors the serpent option table. The three entry points build
4//! their own defaults: [`Options::dump`], [`Options::line`], and
5//! [`Options::block`]. [`Options::serialize`] takes the options as given with no
6//! defaults, matching the raw serpent entry point.
7
8use crate::value::{Ident, Key, Value};
9use std::collections::HashSet;
10
11/// A custom key sort. Receives the key list to reorder in place and the source
12/// table's key/value pairs, so the comparator can rank by key or by value.
13///
14/// serpent calls the comparator as `alphanumsort(keys, table, padding)`. This
15/// signature mirrors the first two arguments. Reorder `keys` in place. Look up a
16/// key's value in `entries` when the order depends on values.
17pub type SortFn = Box<dyn Fn(&mut Vec<Key>, &[(Key, Value)])>;
18
19/// A custom table formatter. Receives `(tag, head, body, tail, level)` and
20/// returns the table text. Mirrors serpent's `custom` option.
21pub type CustomFn = Box<dyn Fn(&str, &str, &str, &str, usize) -> String>;
22
23/// Options controlling serialization.
24///
25/// Field names and defaults follow serpent. Booleans use Lua truthiness unless
26/// a field notes an exact comparison. Set fields directly, or start from
27/// [`Options::dump`], [`Options::line`], or [`Options::block`].
28#[derive(Default)]
29pub struct Options {
30    /// Variable name. When set, output is wrapped in a `do ... return name end`
31    /// block with a self-reference section. `dump` sets `_`.
32    pub name: Option<String>,
33    /// Indentation unit. When set, output is multi-line. `block` sets two spaces.
34    pub indent: Option<String>,
35    /// Remove spaces around separators. `dump` sets true.
36    pub compact: bool,
37    /// Force sparse array encoding, skipping nil holes. `dump` sets true.
38    pub sparse: bool,
39    /// Raise an error on non-serializable values instead of emitting a fallback.
40    pub fatal: bool,
41    /// Maximum number of array-part elements to emit.
42    pub maxnum: Option<usize>,
43    /// Maximum table nesting depth to expand. Deeper tables emit `{}`.
44    pub maxlevel: Option<usize>,
45    /// Maximum cumulative length of emitted element strings.
46    pub maxlength: Option<i64>,
47    /// Replace functions with an empty-body stub instead of bytecode.
48    pub nocode: bool,
49    /// Disable the special `1/0`, `-1/0`, `0/0` forms for inf and nan.
50    pub nohuge: bool,
51    /// Append `--[[...]]` comments up to this depth. The gate is `level < n`, so
52    /// a table at level `l` gets a comment when `l < n`. `Some(0)` disables
53    /// comments, matching serpent's numeric depth 0. `Some(usize::MAX)` comments
54    /// every level, standing in for serpent's `math.huge`. `line` and `block`
55    /// set `Some(usize::MAX)`.
56    pub comment: Option<usize>,
57    /// Sort non-array keys. `line` and `block` set the default sort on.
58    pub sortkeys: bool,
59    /// Custom key sort. Overrides the default `alphanumsort` when set.
60    pub sortfn: Option<SortFn>,
61    /// Force a `.` decimal separator. A no-op in this implementation because
62    /// Rust float formatting is locale-independent.
63    pub fixradix: bool,
64    /// Use `__tostring` on tables. Only an explicit `Some(false)` disables it;
65    /// `None` and `Some(true)` enable it, matching serpent's `~= false` gate.
66    pub metatostring: Option<bool>,
67    /// `printf`-style number format. Defaults to `%.17g`.
68    pub numformat: Option<String>,
69    /// Values to skip, matched by identity or scalar value.
70    pub valignore: Option<HashSet<Ident>>,
71    /// Scalar values to skip.
72    pub valignore_scalar: Option<Vec<Value>>,
73    /// Allowlist of keys to serialize. Keys not in the list are dropped. Keyed
74    /// by `Key`, so numeric and boolean keys work, not only strings.
75    pub keyallow: Option<Vec<Key>>,
76    /// Denylist of keys to skip. Keyed by `Key`, so numeric and boolean keys
77    /// work, not only strings.
78    pub keyignore: Option<Vec<Key>>,
79    /// Value type names to skip, such as `function` or `table`.
80    pub valtypeignore: Option<HashSet<String>>,
81    /// Custom table formatter.
82    pub custom: Option<CustomFn>,
83}
84
85impl Options {
86    /// Options for full serialization: `name = "_"`, `compact`, `sparse`.
87    #[must_use]
88    pub fn dump() -> Self {
89        Options {
90            name: Some("_".to_string()),
91            compact: true,
92            sparse: true,
93            ..Options::default()
94        }
95    }
96
97    /// Options for single-line pretty printing: `sortkeys` and `comment` on.
98    #[must_use]
99    pub fn line() -> Self {
100        Options {
101            sortkeys: true,
102            comment: Some(usize::MAX),
103            ..Options::default()
104        }
105    }
106
107    /// Options for multi-line pretty printing: two-space `indent`, `sortkeys`,
108    /// and `comment` on.
109    #[must_use]
110    pub fn block() -> Self {
111        Options {
112            indent: Some("  ".to_string()),
113            sortkeys: true,
114            comment: Some(usize::MAX),
115            ..Options::default()
116        }
117    }
118
119    /// Options for the raw `serialize` entry point: all defaults, nothing preset.
120    #[must_use]
121    pub fn serialize() -> Self {
122        Options::default()
123    }
124}