1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
//! Serde serialization (clean-room work item C4b; spec §10.8).
//!
//! Any `Serialize` value can be written as UCL text: [`to_string`] and [`to_writer`] in the
//! config format, [`to_json_string`], [`to_json_string_compact`] and [`to_yaml_string`] in the
//! other formats of spec §10. [`to_value`] gives the [`UclValue`] tree instead of text, and
//! [`crate::from_value`] turns a tree back into a Rust value. Errors are [`UclError`]; values that
//! have no form are [`SerdeError::Unrepresentable`].
//!
//! ```
//! use serde::{Deserialize, Serialize};
//! use std::time::Duration;
//!
//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
//! struct Server {
//! host: String,
//! ports: Vec<u16>,
//! ratio: f64,
//! #[serde(with = "serde_ucl::time")]
//! timeout: Duration,
//! }
//!
//! let server = Server {
//! host: "example.org".into(),
//! ports: vec![80, 443],
//! ratio: 0.1,
//! timeout: Duration::from_millis(1500),
//! };
//! let text = serde_ucl::to_string(&server).unwrap();
//! assert_eq!(
//! text,
//! "host = \"example.org\";\nports [\n 80,\n 443,\n]\nratio = 0.1;\ntimeout = 1.5s;\n"
//! );
//! let value = serde_ucl::parse::parse(text.as_bytes()).unwrap();
//! assert_eq!(serde_ucl::from_value::<Server>(value).unwrap(), server);
//! ```
//!
//! # Round trip
//!
//! The text has the layouts of libucl's output (spec §10.4–§10.6), but every value is written in
//! a form that libucl and [`crate::parse`] read back as exactly the value written (spec §10.8),
//! floats included, so deserializing the text gives back the same Rust value. The one exception
//! is a time in JSON, which is written as its number of seconds and reads back as a float (see
//! *JSON* below). The reader must use
//! the default flags and the `append` strategy (spec §8, §12): `key-lowercase` lowercases keys,
//! `no-time` reads times as strings, and `no-implicit-arrays` or another strategy changes
//! repeated keys. In JSON, compact JSON and YAML it must also not register variables that the
//! strings refer to (see *Variables* below).
//!
//! | Value | Written as |
//! | --- | --- |
//! | integer | decimal |
//! | float | the fewest digits that identify the double, with a `.` or an exponent: `0.1`, `1.0`, `-0.0`, `1e16`, `2.2250738585072014e-308`. NaN is `nan` (its sign and payload are not kept), +∞ `inf`, −∞ `-1e308k`; JSON has none of the three |
//! | time | the digits of a float followed by `s`: `1.5s`, `0.001s`; +∞ and −∞ are `1e308ks` and `-1e308ks`; a subnormal time, which only `ms` gives, is a normal float followed by `ms`: `1e-307ms`, `2.2250738585072014e-308ms` (spec §5.4, §10.8). In JSON, the digits of its seconds alone: `1.5`, `0.001` |
//! | string | double-quoted, with the escapes of spec §6.1 for `"`, `\`, control bytes and DEL; in the config format, a string that contains `$` is single-quoted, with `'` written `\'` |
//! | key | bare where spec §3.1 allows it (config and YAML), otherwise double-quoted with those escapes; always double-quoted in JSON |
//! | entry with several values ([`UclValue`] only) | one entry per value, all with the same key, in every format (libucl's JSON and YAML write an array instead, §10.7) |
//! | bool, null, empty object, empty array | `true`, `false`, `null`, `{}`, `[]` |
//!
//! Variables. A double-quoted string expands references to variables registered when it is read
//! (spec §7), and there is no escape that prevents it (§7.6). libucl and [`crate::parse`] define
//! `FILENAME` and `CURDIR` for every document by default (§7.8), and an application may register
//! more.
//!
//! - The config format writes every string that contains `$` in single quotes, which never
//! expand (§6.2), so its output reads back exactly whatever variables the reader has.
//! - JSON, compact JSON and YAML write every string double-quoted, as JSON requires. A string
//! that refers to `FILENAME` or `CURDIR` (`$FILENAME`, `$CURDIR`, `${FILENAME}`, `${CURDIR}`,
//! also with more text after an unbraced name) would expand with the default settings, so it
//! is an error there; the check is conservative and also rejects a reference that `$$` keeps
//! as written (§7.5). A reference to a variable that the application registers when reading
//! expands too: the output reads back exactly only with a reader that registers none of the
//! variables its strings refer to.
//!
//! JSON. [`to_json_string`] and [`to_json_string_compact`] always write valid JSON (RFC 8259),
//! unlike libucl's own JSON output, which writes `nan` and `inf` (WORKLIST.md C4, decision 2):
//!
//! - a time is written as its number of seconds, a JSON number, and reads back as a float. A
//! Rust value whose deserializer takes a number of seconds still round-trips: a `Duration`
//! through [`crate::time`] does, while a time in a [`UclValue`] comes back as a float;
//! - a NaN or infinite float or time has no JSON number and is an error, as is a subnormal time,
//! whose number of seconds no literal reads back as (spec §5.3). The config and YAML formats
//! write all three.
//!
//! An entry with several values gives repeated member names, which JSON's grammar allows (RFC
//! 8259 advises unique names; readers such as `serde_json` keep the last value).
//!
//! # Errors
//!
//! [`SerdeError::Unrepresentable`] for a value that has no form that reads back as itself:
//!
//! - an integer outside the 64-bit signed range, which [`to_value`] rejects too (spec §5.3);
//! - a subnormal float: every literal below the normal range is an error (§5.3);
//! - a subnormal time closer to zero than `2.2250738585069563e-311`, the smallest that `ms` gives
//! from a normal float (§10.8), and in JSON every subnormal time;
//! - a NaN time, which no text gives (§5.4);
//! - in JSON and compact JSON, a NaN or infinite float or time;
//! - the empty key, which parsing rejects (§3.2);
//! - a root that is not a map, a struct or a sequence: a UCL document is an object or an array
//! (§1.1);
//! - more than 1024 containers nested inside one another, the root included (§11.2);
//! - in the config format, a string that contains `$` and a backslash before `'`, a line break
//! or its end: double quotes would expand it and single quotes cannot hold it (§6.2, §10.8);
//! - in JSON, compact JSON and YAML, a string that refers to `FILENAME` or `CURDIR` (see
//! *Variables*);
//! - a map key that is not a string, a `char`, an integer, a `bool` or a unit variant.
//!
//! [`crate::time::serialize`] reports a `Duration` that a 64-bit float of seconds cannot hold
//! exactly as [`SerdeError::Custom`].
//!
//! # Depth
//!
//! A [`UclValue`] or [`UclObject`], also as a field of another type, is copied as it is, with
//! the same stack at any depth: [`to_value`] of one gives an equal value, priorities and marks
//! included, and the text functions write any such value up to 1024 containers deep (spec
//! §11.2), which every value the parser returns is unless its `.inherit` depth limit is raised
//! ([`Parser::set_inherit_depth_limit`](crate::parse::Parser::set_inherit_depth_limit)). Deeper
//! text could not be parsed again. Any other type is serialized by recursion through its `Serialize` impl, one
//! level per map or sequence, and there serialization enters at most
//! [`MAX_SERDE_NESTING`](crate::MAX_SERDE_NESTING) maps and sequences inside one another, the
//! outermost included; deeper, it fails with [`SerdeError::TooDeep`]. The object of an enum
//! variant counts as a map, and the array or object inside a tuple or struct variant counts too.
//!
//! # Serde's own limits
//!
//! `Some(None)` and `Some(())` are written `null` and read back as `None`, as in every
//! self-describing format. Enums are externally tagged: a unit variant is its name, the other
//! variants an object whose one key is the name.
pub
use crate;
use crate;
use cratehandoff;
use crate;
use ;
use ValueSerializer;
use io;
/// Serializes `value` into a [`UclValue`] tree, in the mapping of the table below. The tree can
/// be of any kind; only the text functions require an object or an array at the root.
///
/// | serde | UCL |
/// | --- | --- |
/// | `bool`, `char`, `str` | boolean, one-character string, string |
/// | integers | integer; outside the `i64` range an error |
/// | `f32`, `f64` | float (`f32` widened exactly) |
/// | unit, unit struct, `None` | `null` |
/// | `Some(v)`, newtype struct | `v` |
/// | bytes | array of integers 0–255 |
/// | sequence, tuple, tuple struct | array |
/// | map, struct | object, with entries and fields in order |
/// | unit variant | the variant's name |
/// | newtype, tuple and struct variant | object with one key, the variant's name |
/// | `Duration` with [`crate::time`] | time |
Sized + Serialize>
Sized + Serialize>
/// Serializes `value` as UCL text in the config format (spec §10.5), which reads back exactly
/// with any registered variables. See the [module documentation](self) for the forms and the
/// errors.
Sized + Serialize>
/// Serializes `value` as pretty JSON (spec §10.4 layout), one member per line. The output is
/// valid JSON (RFC 8259): times are numbers of seconds, and NaN and infinite floats and times are
/// errors. See the [module documentation](self).
Sized + Serialize>
/// Serializes `value` as JSON without whitespace (spec §10.4 layout), valid JSON as
/// [`to_json_string`] writes it.
Sized + Serialize>
/// Serializes `value` in libucl's YAML format (spec §10.6 layout).
Sized + Serialize>
/// Writes `value` to `writer` in the config format, as [`to_string`] does. Nothing is written
/// when serialization fails.
Sized + Serialize>
/// The content of the newtype struct [`marker::VALUE`] that `Serialize for UclValue` and
/// `Serialize for UclObject` write. Asked by the crate's serializer, it hands a copy of the
/// value over (see [`crate::handoff`]); for any other serializer, it writes the value's
/// structure.
/// A value as serde's data model has it, for serializers other than the crate's.
;
/// An object as a map from each key to its value; the values of a key that has several are the
/// private newtype struct [`marker::MULTI`] around the sequence of them.
;
/// The values of a multi-value entry, as the private newtype struct [`marker::MULTI`].
;
;