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