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
//! Reading a document: the seam between text and this crate's tree.
//!
//! A reader answers one question — *what does this text say, in this
//! format?* — and answers it with a [`Value`]. Everything above it works
//! on that tree and never on a parser, which is what lets the parser be a
//! choice.
//!
//! ```text
//! "[db]\nport = 5432\n" + Format::Toml ──▶ {db: {port: 5432}}
//! ```
//!
//! Three ship, and the reason to choose between them is not taste:
//!
//! | reader | feature | parses | notes |
//! |---|---|---|---|
//! | [`native()`] — **the default** | — | JSON, TOML, YAML, INI, `.properties` | the only `.properties` parser anywhere |
//! | [`config_rs()`] | — | JSON, TOML, YAML, INI, RON, JSON5 | YAML through the maintained `yaml-rust2` |
//! | [`figment()`] | `figment` | JSON, TOML, YAML | |
//!
//! The column is what each one **parses**, not what a load that chose it
//! can read: a format the chosen reader has no parser for is handed to one
//! that has — so choosing `config_rs()` for its YAML does not cost you the
//! `.properties` file beside it.
//!
//! **Unlike the [engines](crate::engine), readers are not interchangeable
//! down to the corner.** A fold is one rule with an implementation on
//! each side; a parser is a *dialect*, and two YAML libraries disagree about
//! things no specification settles. What the tests hold is the part a
//! deployment depends on — the shapes documents actually take — and the
//! places they diverge are named in the book rather than papered over.
//!
//! Which one runs is the same choice the engine is: `Builder::reader`,
//! [`LoadSpec::with_reader`](crate::LoadSpec::with_reader), or
//! [`set_reader`] once for the process.
use fmt;
use crate;
use crateFormat;
use crateValue;
/// Text in, this crate's tree out.
///
/// Implement it to read a format this crate does not ship, or to read one
/// it does with a parser of your own.
///
/// # Errors
///
/// A reader's error must **never carry document content**. The line that
/// failed to parse is, on a bad day, the line holding the password — so a
/// message says where it stopped and why, and never what it found there.
/// This crate's own parsers.
///
/// The only reader that reads `.properties`, and the one whose INI dialect
/// the book documents.
/// The [`config`](https://docs.rs/config) crate's parsers.
///
/// **Not the default** — [`native()`] is, and the module's own
/// documentation says why. This is the engine's opposite: there the
/// backend's fold is what runs unless a load says otherwise, because a
/// fold can be proved interchangeable and a parser is a dialect.
///
/// Reads two formats nothing else here does — RON and JSON5 — and reads
/// YAML through `yaml-rust2`, which is maintained where this crate's own
/// `serde_yaml` is archived.
/// The [`figment`](https://docs.rs/figment) crate's parsers.
/// Every reader this build ships, this crate's own first.
///
/// **The one list.** The agreement tests walk it, so a reader added here
/// is compared against the others on every corpus without a test being
/// edited.
/// The reader a load uses when nothing chose one: this crate's own.
///
/// **Not the backend, unlike the [engine](crate::engine).** The asymmetry
/// is deliberate and it is about what can be proved. A fold is one rule
/// with an implementation on each side, and the tests hold both to it leaf
/// by leaf, so which one runs is not a question about meaning. A parser is
/// a *dialect*: this crate's INI is the one the book specifies, and
/// `.properties` has no parser anywhere else — every reader reads one, and
/// it is this one. Handing those to a different
/// library by default would change what a document means for everyone who
/// upgraded, quietly.
///
/// The backend's parsers are one call away, and worth having — see
/// [`config_rs`].
pub
static INSTALLED: OnceLock = new;
/// The installed reader, or the default.
pub
/// Installs `reader` for every load in this process that does not name one.
///
/// Call it before the first `init()`.
///
/// # Errors
///
/// If one is already installed. The rejected reader is returned, so a
/// caller can tell "already set" from "failed".
/// Whether a reader has been installed.
/// The reader that will parse `format`: the chosen one, or the first that
/// can.
///
/// A reader that does not read a format hands it on rather than refusing
/// it, which is what makes a format like RON — parsed by the backend and
/// by nothing here — work without a caller having to install a reader by
/// hand. Deterministic, in [`all`]'s order, and **additive**: the fallback
/// can only fire where the chosen reader would have failed outright, so a
/// load that worked keeps working through exactly the same parser.
pub
/// Nobody in this build reads `format`.
///
/// Names the readers that *could*, because the answer is almost always a
/// feature: this crate's own for `.properties`, the backend's for RON.
pub
// ---------------------------------------------------------------------------
// This crate's own
// ---------------------------------------------------------------------------
;
// ---------------------------------------------------------------------------
// config-rs
// ---------------------------------------------------------------------------
use crateReader as ConfigRs;
// ---------------------------------------------------------------------------
// figment
// ---------------------------------------------------------------------------
use crateReader as Figment;