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}