1pub use serde::de::{Deserialize, IntoDeserializer};
2
3use crate::value::{Array, Table, Value};
4
5/// Construct a [`Table`] from TOML syntax.
6///
7/// ```rust
8/// let cargo_toml = toml::toml! {
9/// [package]
10/// name = "toml"
11/// version = "0.4.5"
12/// authors = ["Alex Crichton <alex@alexcrichton.com>"]
13///
14/// [badges]
15/// travis-ci = { repository = "alexcrichton/toml-rs" }
16///
17/// [dependencies]
18/// serde = "1.0"
19///
20/// [dev-dependencies]
21/// serde_derive = "1.0"
22/// serde_json = "1.0"
23/// };
24///
25/// println!("{:#?}", cargo_toml);
26/// ```
27#[macro_export]
28macro_rules! toml {
29 ($($toml:tt)+) => {{
30 let table = $crate::value::Table::new();
31 let mut root = $crate::Value::Table(table);
32 $crate::toml_internal!(@toplevel root [] $($toml)+);
33 match root {
34 $crate::Value::Table(table) => table,
35 _ => unreachable!(),
36 }
37 }};
38}
39
40// TT-muncher to parse TOML syntax into a toml::Value.
41//
42// @toplevel -- Parse tokens outside of an inline table or inline array. In
43// this state, `[table headers]` and `[[array headers]]` are
44// allowed and `key = value` pairs are not separated by commas.
45//
46// @topleveldatetime -- Helper to parse a Datetime from string and insert it
47// into a table, continuing in the @toplevel state.
48//
49// @path -- Turn a path segment into a string. Segments that look like idents
50// are stringified, while quoted segments like `"cfg(windows)"`
51// are not.
52//
53// @value -- Parse the value part of a `key = value` pair, which may be a
54// primitive or inline table or inline array.
55//
56// @table -- Parse the contents of an inline table, returning them as a
57// toml::Value::Table.
58//
59// @tabledatetime -- Helper to parse a Datetime from string and insert it
60// into a table, continuing in the @table state.
61//
62// @array -- Parse the contents of an inline array, returning them as a
63// toml::Value::Array.
64//
65// @arraydatetime -- Helper to parse a Datetime from string and push it into
66// an array, continuing in the @array state.
67//
68// @trailingcomma -- Helper to append a comma to a sequence of tokens if the
69// sequence is non-empty and does not already end in a trailing
70// comma.
71//
72#[macro_export]
73#[doc(hidden)]
74macro_rules! toml_internal {
75 // Base case, no elements remaining.
76 (@toplevel $root:ident [$($path:tt)*]) => {};
77
78 // Parse negative number `key = -value`.
79 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = - $v:tt $($rest:tt)*) => {
80 $crate::toml_internal!(@toplevel $root [$($path)*] $($($k)-+).+ = (-$v) $($rest)*);
81 };
82
83 // Parse positive number `key = +value`.
84 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = + $v:tt $($rest:tt)*) => {
85 $crate::toml_internal!(@toplevel $root [$($path)*] $($($k)-+).+ = ($v) $($rest)*);
86 };
87
88 // Parse offset datetime `key = 1979-05-27T00:32:00.999999-07:00`.
89 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => {
90 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
91 };
92 // Space instead of T.
93 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => {
94 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
95 };
96
97 // Parse offset datetime `key = 1979-05-27T00:32:00-07:00`.
98 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => {
99 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*);
100 };
101 // Space instead of T.
102 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => {
103 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec - $tzh : $tzm) $($rest)*);
104 };
105
106 // Parse local datetime `key = 1979-05-27T00:32:00.999999`.
107 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => {
108 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*);
109 };
110 // Space instead of T.
111 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => {
112 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac) $($rest)*);
113 };
114
115 // Parse offset datetime `key = 1979-05-27T07:32:00Z` and local datetime `key = 1979-05-27T07:32:00`.
116 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt $($rest:tt)*) => {
117 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec) $($rest)*);
118 };
119 // Space instead of T.
120 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt $($rest:tt)*) => {
121 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec) $($rest)*);
122 };
123
124 // Parse local date `key = 1979-05-27`.
125 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $($rest:tt)*) => {
126 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($yr - $mo - $day) $($rest)*);
127 };
128
129 // Parse local time `key = 00:32:00.999999`.
130 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => {
131 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($hr : $min : $sec . $frac) $($rest)*);
132 };
133
134 // Parse local time `key = 07:32:00`.
135 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt $($rest:tt)*) => {
136 $crate::toml_internal!(@topleveldatetime $root [$($path)*] $($($k)-+).+ = ($hr : $min : $sec) $($rest)*);
137 };
138
139 // Parse any other `key = value` including string, inline array, inline
140 // table, number, and boolean.
141 (@toplevel $root:ident [$($path:tt)*] $($($k:tt)-+).+ = $v:tt $($rest:tt)*) => {{
142 $crate::macros::insert_toml(
143 &mut $root,
144 &[$($path)* $(&concat!($("-", $crate::toml_internal!(@path $k),)+)[1..], )+],
145 $crate::toml_internal!(@value $v));
146 $crate::toml_internal!(@toplevel $root [$($path)*] $($rest)*);
147 }};
148
149 // Parse array header `[[bin]]`.
150 (@toplevel $root:ident $oldpath:tt [[$($($path:tt)-+).+]] $($rest:tt)*) => {
151 $crate::macros::push_toml(
152 &mut $root,
153 &[$(&concat!($("-", $crate::toml_internal!(@path $path),)+)[1..],)+]);
154 $crate::toml_internal!(@toplevel $root [$(&concat!($("-", $crate::toml_internal!(@path $path),)+)[1..],)+] $($rest)*);
155 };
156
157 // Parse table header `[patch.crates-io]`.
158 (@toplevel $root:ident $oldpath:tt [$($($path:tt)-+).+] $($rest:tt)*) => {
159 $crate::macros::insert_toml(
160 &mut $root,
161 &[$(&concat!($("-", $crate::toml_internal!(@path $path),)+)[1..],)+],
162 $crate::Value::Table($crate::value::Table::new()));
163 $crate::toml_internal!(@toplevel $root [$(&concat!($("-", $crate::toml_internal!(@path $path),)+)[1..],)+] $($rest)*);
164 };
165
166 // Parse datetime from string and insert into table.
167 (@topleveldatetime $root:ident [$($path:tt)*] $($($k:tt)-+).+ = ($($datetime:tt)+) $($rest:tt)*) => {
168 $crate::macros::insert_toml(
169 &mut $root,
170 &[$($path)* $(&concat!($("-", $crate::toml_internal!(@path $k),)+)[1..], )+],
171 $crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
172 $crate::toml_internal!(@toplevel $root [$($path)*] $($rest)*);
173 };
174
175 // Turn a path segment into a string.
176 (@path $ident:ident) => {
177 stringify!($ident)
178 };
179
180 // For a path segment that is not an ident, expect that it is already a
181 // quoted string, like in `[target."cfg(windows)".dependencies]`.
182 (@path $quoted:tt) => {
183 $quoted
184 };
185
186 // Construct a Value from an inline table.
187 (@value { $($inline:tt)* }) => {{
188 let mut table = $crate::Value::Table($crate::value::Table::new());
189 $crate::toml_internal!(@trailingcomma (@table table) $($inline)*);
190 table
191 }};
192
193 // Construct a Value from an inline array.
194 (@value [ $($inline:tt)* ]) => {{
195 let mut array = $crate::value::Array::new();
196 $crate::toml_internal!(@trailingcomma (@array array) $($inline)*);
197 $crate::Value::Array(array)
198 }};
199
200 (@value (-nan)) => {
201 $crate::Value::Float(-::std::f64::NAN)
202 };
203
204 (@value (nan)) => {
205 $crate::Value::Float(::std::f64::NAN)
206 };
207
208 (@value nan) => {
209 $crate::Value::Float(::std::f64::NAN)
210 };
211
212 (@value (-inf)) => {
213 $crate::Value::Float(::std::f64::NEG_INFINITY)
214 };
215
216 (@value (inf)) => {
217 $crate::Value::Float(::std::f64::INFINITY)
218 };
219
220 (@value inf) => {
221 $crate::Value::Float(::std::f64::INFINITY)
222 };
223
224 // Construct a Value from any other type, probably string or boolean or number.
225 (@value $v:tt) => {{
226 // TODO: Implement this with something like serde_json::to_value instead.
227 let de = $crate::macros::IntoDeserializer::<$crate::de::Error>::into_deserializer($v);
228 <$crate::Value as $crate::macros::Deserialize>::deserialize(de).unwrap()
229 }};
230
231 // Base case of inline table.
232 (@table $root:ident) => {};
233
234 // Parse negative number `key = -value`.
235 (@table $root:ident $($($k:tt)-+).+ = - $v:tt , $($rest:tt)*) => {
236 $crate::toml_internal!(@table $root $($($k)-+).+ = (-$v) , $($rest)*);
237 };
238
239 // Parse positive number `key = +value`.
240 (@table $root:ident $($($k:tt)-+).+ = + $v:tt , $($rest:tt)*) => {
241 $crate::toml_internal!(@table $root $($($k)-+).+ = ($v) , $($rest)*);
242 };
243
244 // Parse offset datetime `key = 1979-05-27T00:32:00.999999-07:00`.
245 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
246 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
247 };
248 // Space instead of T.
249 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
250 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
251 };
252
253 // Parse offset datetime `key = 1979-05-27T00:32:00-07:00`.
254 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
255 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*);
256 };
257 // Space instead of T.
258 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
259 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec - $tzh : $tzm) $($rest)*);
260 };
261
262 // Parse local datetime `key = 1979-05-27T00:32:00.999999`.
263 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
264 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*);
265 };
266 // Space instead of T.
267 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
268 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec . $frac) $($rest)*);
269 };
270
271 // Parse offset datetime `key = 1979-05-27T07:32:00Z` and local datetime `key = 1979-05-27T07:32:00`.
272 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
273 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $dhr : $min : $sec) $($rest)*);
274 };
275 // Space instead of T.
276 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
277 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day T $hr : $min : $sec) $($rest)*);
278 };
279
280 // Parse local date `key = 1979-05-27`.
281 (@table $root:ident $($($k:tt)-+).+ = $yr:tt - $mo:tt - $day:tt , $($rest:tt)*) => {
282 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($yr - $mo - $day) $($rest)*);
283 };
284
285 // Parse local time `key = 00:32:00.999999`.
286 (@table $root:ident $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
287 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($hr : $min : $sec . $frac) $($rest)*);
288 };
289
290 // Parse local time `key = 07:32:00`.
291 (@table $root:ident $($($k:tt)-+).+ = $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
292 $crate::toml_internal!(@tabledatetime $root $($($k)-+).+ = ($hr : $min : $sec) $($rest)*);
293 };
294
295 // Parse any other type, probably string or boolean or number.
296 (@table $root:ident $($($k:tt)-+).+ = $v:tt , $($rest:tt)*) => {
297 $crate::macros::insert_toml(
298 &mut $root,
299 &[$(&concat!($("-", $crate::toml_internal!(@path $k),)+)[1..], )+],
300 $crate::toml_internal!(@value $v));
301 $crate::toml_internal!(@table $root $($rest)*);
302 };
303
304 // Parse a Datetime from string and continue in @table state.
305 (@tabledatetime $root:ident $($($k:tt)-+).+ = ($($datetime:tt)*) $($rest:tt)*) => {
306 $crate::macros::insert_toml(
307 &mut $root,
308 &[$(&concat!($("-", $crate::toml_internal!(@path $k),)+)[1..], )+],
309 $crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
310 $crate::toml_internal!(@table $root $($rest)*);
311 };
312
313 // Base case of inline array.
314 (@array $root:ident) => {};
315
316 // Parse negative number `-value`.
317 (@array $root:ident - $v:tt , $($rest:tt)*) => {
318 $crate::toml_internal!(@array $root (-$v) , $($rest)*);
319 };
320
321 // Parse positive number `+value`.
322 (@array $root:ident + $v:tt , $($rest:tt)*) => {
323 $crate::toml_internal!(@array $root ($v) , $($rest)*);
324 };
325
326 // Parse offset datetime `1979-05-27T00:32:00.999999-07:00`.
327 (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
328 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
329 };
330 // Space instead of T.
331 (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
332 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
333 };
334
335 // Parse offset datetime `1979-05-27T00:32:00-07:00`.
336 (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
337 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*);
338 };
339 // Space instead of T.
340 (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
341 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec - $tzh : $tzm) $($rest)*);
342 };
343
344 // Parse local datetime `1979-05-27T00:32:00.999999`.
345 (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
346 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*);
347 };
348 // Space instead of T.
349 (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
350 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec . $frac) $($rest)*);
351 };
352
353 // Parse offset datetime `1979-05-27T07:32:00Z` and local datetime `1979-05-27T07:32:00`.
354 (@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
355 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec) $($rest)*);
356 };
357 // Space instead of T.
358 (@array $root:ident $yr:tt - $mo:tt - $day:tt $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
359 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $day T $hr : $min : $sec) $($rest)*);
360 };
361
362 // Parse local date `1979-05-27`.
363 (@array $root:ident $yr:tt - $mo:tt - $day:tt , $($rest:tt)*) => {
364 $crate::toml_internal!(@arraydatetime $root ($yr - $mo - $day) $($rest)*);
365 };
366
367 // Parse local time `00:32:00.999999`.
368 (@array $root:ident $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
369 $crate::toml_internal!(@arraydatetime $root ($hr : $min : $sec . $frac) $($rest)*);
370 };
371
372 // Parse local time `07:32:00`.
373 (@array $root:ident $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
374 $crate::toml_internal!(@arraydatetime $root ($hr : $min : $sec) $($rest)*);
375 };
376
377 // Parse any other type, probably string or boolean or number.
378 (@array $root:ident $v:tt , $($rest:tt)*) => {
379 $root.push($crate::toml_internal!(@value $v));
380 $crate::toml_internal!(@array $root $($rest)*);
381 };
382
383 // Parse a Datetime from string and continue in @array state.
384 (@arraydatetime $root:ident ($($datetime:tt)*) $($rest:tt)*) => {
385 $root.push($crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
386 $crate::toml_internal!(@array $root $($rest)*);
387 };
388
389 // No trailing comma required if the tokens are empty.
390 (@trailingcomma ($($args:tt)*)) => {
391 $crate::toml_internal!($($args)*);
392 };
393
394 // Tokens end with a trailing comma, do not append another one.
395 (@trailingcomma ($($args:tt)*) ,) => {
396 $crate::toml_internal!($($args)* ,);
397 };
398
399 // Tokens end with something other than comma, append a trailing comma.
400 (@trailingcomma ($($args:tt)*) $last:tt) => {
401 $crate::toml_internal!($($args)* $last ,);
402 };
403
404 // Not yet at the last token.
405 (@trailingcomma ($($args:tt)*) $first:tt $($rest:tt)+) => {
406 $crate::toml_internal!(@trailingcomma ($($args)* $first) $($rest)+);
407 };
408}
409
410// Called when parsing a `key = value` pair.
411// Inserts an entry into the table at the given path.
412pub fn insert_toml(root: &mut Value, path: &[&str], value: Value) {
413 *traverse(root, path) = value;
414}
415
416// Called when parsing an `[[array header]]`.
417// Pushes an empty table onto the array at the given path.
418pub fn push_toml(root: &mut Value, path: &[&str]) {
419 let target: &mut Value = traverse(root, path);
420 if !target.is_array() {
421 *target = Value::Array(Array::new());
422 }
423 target&mut Vec
424 .as_array_mut()
425 .unwrap()
426 .push(Value::Table(Table::new()));
427}
428
429fn traverse<'a>(root: &'a mut Value, path: &[&str]) -> &'a mut Value {
430 let mut cur = root;
431 for &key in path {
432 // Lexical lifetimes :D
433 let cur1 = cur;
434
435 // From the TOML spec:
436 //
437 // > Each double-bracketed sub-table will belong to the most recently
438 // > defined table element above it.
439 let cur2 = if cur1.is_array() {
440 cur1.as_array_mut().unwrap().last_mut().unwrap()
441 } else {
442 cur1
443 };
444
445 // We are about to index into this value, so it better be a table.
446 if !cur2.is_table() {
447 *cur2 = Value::Table(Table::new());
448 }
449
450 if !cur2.as_table().unwrap().contains_key(key) {
451 // Insert an empty table for the next loop iteration to point to.
452 let empty = Value::Table(Table::new());
453 cur2.as_table_mut().unwrap().insert(key.to_owned(), empty);
454 }
455
456 // Step into the current table.
457 cur = cur2.as_table_mut().unwrap().get_mut(key).unwrap();
458 }
459 cur
460}
461