1 | pub use serde::de::{Deserialize, IntoDeserializer}; |
2 | |
3 | use 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 ] |
28 | macro_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)] |
74 | macro_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. |
412 | pub 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. |
418 | pub 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 | |
429 | fn 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 | |