| 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 | |