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