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
//! A self-contained [TOML 1.1.0](https://toml.io/en/v1.1.0) parser and
//! serializer.
//!
//! `tomlproc` implements the whole of TOML 1.1.0 -- every string flavour, all
//! four date-time types, dotted keys, inline tables and arrays of tables --
//! with no dependencies outside the standard library.
//!
//! # Parsing
//!
//! [`parse`] turns a document into a [`Table`], an insertion-ordered map of
//! [`Value`]s:
//!
//! ```
//! # #[cfg(feature = "alloc")] fn main() {
//! let doc = tomlproc::parse(r#"
//! title = "TOML Example"
//!
//! [owner]
//! name = "Tom Preston-Werner"
//! dob = 1979-05-27T07:32:00-08:00
//!
//! [[server]]
//! ip = "10.0.0.1"
//! ports = [8000, 8001]
//! "#).unwrap();
//!
//! assert_eq!(doc["title"].as_str(), Some("TOML Example"));
//! assert_eq!(doc["owner"]["dob"].as_datetime().unwrap().date.unwrap().year, 1979);
//! assert_eq!(doc["server"][0]["ports"][1].as_integer(), Some(8001));
//! # }
//! # #[cfg(not(feature = "alloc"))] fn main() {}
//! ```
//!
//! Errors carry the line and column at which the problem was found:
//!
//! ```
//! # #[cfg(feature = "alloc")] fn main() {
//! let error = tomlproc::parse("a = 1\nb = [1, 2").unwrap_err();
//! assert_eq!(error.line(), 2);
//! assert_eq!(error.to_string(), "TOML parse error at line 2, column 5: unterminated array");
//! # }
//! # #[cfg(not(feature = "alloc"))] fn main() {}
//! ```
//!
//! # Building and writing
//!
//! Tables can be built by hand and written back out with [`to_string`]:
//!
//! ```
//! # #[cfg(feature = "alloc")] fn main() {
//! let mut package = tomlproc::Table::new();
//! package.insert("name", "tomlproc");
//! package.insert("edition", "2024");
//!
//! let mut doc = tomlproc::Table::new();
//! doc.insert("package", package);
//!
//! assert_eq!(tomlproc::to_string(&doc), "[package]\nname = \"tomlproc\"\nedition = \"2024\"\n");
//! # }
//! # #[cfg(not(feature = "alloc"))] fn main() {}
//! ```
//!
//! Parsing and serializing round-trip: key order, and the shape of tables and
//! arrays of tables, are preserved. Formatting is not -- comments, blank lines
//! and the choice between a header and an inline table belong to the document,
//! not to the value model.
//!
//! # Features
//!
//! | Feature | Default | What it adds |
//! | --- | --- | --- |
//! | `std` | yes | Implies `alloc`, and indexes tables by hash |
//! | `alloc` | via `std` | The value model, the parser and the serializer |
//! | `serde` | no | [`tomlproc::serde`](crate::serde); implies `alloc` |
//!
//! The crate is `#![no_std]`. With `alloc` but not `std` everything here works
//! unchanged, on ordered maps instead of hash maps; the public API is the
//! same, and so is what the parser accepts. Turn `alloc` off too and what is
//! left is [`Datetime`] and the types it is made of, which parse and format
//! with no allocator at all -- the value model cannot follow, since a
//! [`Table`] owns its keys and values.
//!
//! ```toml
//! # embedded, with a heap
//! tomlproc = { version = "0.1", default-features = false, features = ["alloc"] }
//! ```
//!
//! # Beyond the value model
//!
//! [`parse_spans`] also reports where each value was written, so a value that
//! turns out to be wrong later can be pointed back at its line and column.
//!
//! The optional `serde` feature adds [`tomlproc::serde`](crate::serde), which
//! maps documents onto your own types. It is off by default, and it is the
//! only thing that gives the crate a dependency.
//!
//! # Conformance
//!
//! Everything TOML 1.1.0 added over 1.0.0 is accepted: newlines and trailing
//! commas inside inline tables, the `\e` and `\xHH` string escapes, and times
//! written without seconds. Since 1.1 only adds to 1.0, every 1.0 document
//! still parses. What is *written* stays within 1.0, so a document this crate
//! produces can be read by an older parser: seconds are always written, inline
//! tables stay on one line, and control characters are escaped as `\u00XX`.
//!
//! The parser is strict, and rejects what the specification calls invalid:
//! duplicate keys, extending an inline table, redefining a table, mismatched
//! quotes, out-of-range integers and dates, bad underscore or leading-zero
//! placement in numbers, control characters in strings and comments, and a key
//! of any kind landing on a table that is already defined. A bare carriage
//! return is an error; `\r\n` in a multi-line string is normalized to `\n`, as
//! the specification permits.
// On docs.rs, mark what each feature adds.
extern crate alloc;
extern crate std;
pub use crate;
pub use crateError;
pub use crate;
pub use crate;
pub use crate;
pub use crateValue;
/// Implementation details the `array!` macro needs to name. Not public API.
/// Parses a TOML document.
///
/// ```
/// let doc = tomlproc::parse("key = \"value\"").unwrap();
/// assert_eq!(doc["key"].as_str(), Some("value"));
/// ```
/// Parses a TOML document, also reporting where each value was written.
///
/// The [`Spans`] are keyed by dotted path, the same way
/// [`Error::key_path`] spells one, so a value that later turns out to be
/// wrong can be pointed back at its place in the source. Recording them costs
/// a little time and memory, which is why [`parse`] does not.
///
/// ```
/// let source = "[server]\nport = 8080\n";
/// let (doc, spans) = tomlproc::parse_spans(source).unwrap();
///
/// assert_eq!(doc["server"]["port"].as_integer(), Some(8080));
///
/// let span = spans.get("server.port").unwrap();
/// assert_eq!((span.line, span.column), (2, 1));
/// assert_eq!(&source[span.value.clone()], "8080");
/// assert_eq!(&source[span.range.clone()], "port = 8080");
/// ```
/// Parses a TOML document from bytes, which must be UTF-8.
///
/// ```
/// let doc = tomlproc::parse_bytes(b"key = 'value'").unwrap();
/// assert_eq!(doc["key"].as_str(), Some("value"));
///
/// let error = tomlproc::parse_bytes(b"key = 'v\xff'").unwrap_err();
/// assert_eq!(error.to_string(), "TOML parse error at line 1, column 9: input is not valid UTF-8");
/// ```