1 | pub use serde::de::{Deserialize, IntoDeserializer}; |
2 | |
3 | use 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 ] |
30 | macro_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)] |
73 | macro_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. |
411 | pub 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. |
417 | pub 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 | |
428 | fn 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 | |