commit
b44ea161d3
|
@ -9,6 +9,7 @@ before_script:
|
||||||
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
- pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH
|
||||||
script:
|
script:
|
||||||
- cargo test
|
- cargo test
|
||||||
|
- cargo test --manifest-path test-suite/Cargo.toml
|
||||||
- rustdoc --test README.md -L target
|
- rustdoc --test README.md -L target
|
||||||
- test "$TRAVIS_RUST_VERSION" != "1.15.0" && cargo doc --no-deps || echo "skipping cargo doc"
|
- test "$TRAVIS_RUST_VERSION" != "1.15.0" && cargo doc --no-deps || echo "skipping cargo doc"
|
||||||
after_success:
|
after_success:
|
||||||
|
|
|
@ -166,3 +166,6 @@ pub mod de;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use de::{from_slice, from_str, Deserializer};
|
pub use de::{from_slice, from_str, Deserializer};
|
||||||
mod tokens;
|
mod tokens;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod macros;
|
||||||
|
|
373
src/macros.rs
Normal file
373
src/macros.rs
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
pub use serde::de::{Deserialize, IntoDeserializer};
|
||||||
|
|
||||||
|
use value::{Value, Table, Array};
|
||||||
|
|
||||||
|
/// Construct a [`toml::Value`] from TOML syntax.
|
||||||
|
///
|
||||||
|
/// [`toml::Value`]: value/enum.Value.html
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #[macro_use]
|
||||||
|
/// extern crate toml;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let cargo_toml = toml! {
|
||||||
|
/// [package]
|
||||||
|
/// name = "toml"
|
||||||
|
/// version = "0.4.5"
|
||||||
|
/// authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
///
|
||||||
|
/// [badges]
|
||||||
|
/// travis-ci = { repository = "alexcrichton/toml-rs" }
|
||||||
|
///
|
||||||
|
/// [dependencies]
|
||||||
|
/// serde = "1.0"
|
||||||
|
///
|
||||||
|
/// [dev-dependencies]
|
||||||
|
/// serde_derive = "1.0"
|
||||||
|
/// serde_json = "1.0"
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// println!("{:#?}", cargo_toml);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! toml {
|
||||||
|
($($toml:tt)+) => {{
|
||||||
|
let table = $crate::value::Table::new();
|
||||||
|
let mut root = $crate::Value::Table(table);
|
||||||
|
toml_internal!(@toplevel root [] $($toml)+);
|
||||||
|
root
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TT-muncher to parse TOML syntax into a toml::Value.
|
||||||
|
//
|
||||||
|
// @toplevel -- Parse tokens outside of an inline table or inline array. In
|
||||||
|
// this state, `[table headers]` and `[[array headers]]` are
|
||||||
|
// allowed and `key = value` pairs are not separated by commas.
|
||||||
|
//
|
||||||
|
// @topleveldatetime -- Helper to parse a Datetime from string and insert it
|
||||||
|
// into a table, continuing in the @toplevel state.
|
||||||
|
//
|
||||||
|
// @path -- Turn a path segment into a string. Segments that look like idents
|
||||||
|
// are stringified, while quoted segments like `"cfg(windows)"`
|
||||||
|
// are not.
|
||||||
|
//
|
||||||
|
// @value -- Parse the value part of a `key = value` pair, which may be a
|
||||||
|
// primitive or inline table or inline array.
|
||||||
|
//
|
||||||
|
// @table -- Parse the contents of an inline table, returning them as a
|
||||||
|
// toml::Value::Table.
|
||||||
|
//
|
||||||
|
// @tabledatetime -- Helper to parse a Datetime from string and insert it
|
||||||
|
// into a table, continuing in the @table state.
|
||||||
|
//
|
||||||
|
// @array -- Parse the contents of an inline array, returning them as a
|
||||||
|
// toml::Value::Array.
|
||||||
|
//
|
||||||
|
// @arraydatetime -- Helper to parse a Datetime from string and push it into
|
||||||
|
// an array, continuing in the @array state.
|
||||||
|
//
|
||||||
|
// @trailingcomma -- Helper to append a comma to a sequence of tokens if the
|
||||||
|
// sequence is non-empty and does not already end in a trailing
|
||||||
|
// comma.
|
||||||
|
//
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! toml_internal {
|
||||||
|
// Base case, no elements remaining.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*]) => {};
|
||||||
|
|
||||||
|
// Parse negative number `key = -value`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = - $v:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@toplevel $root [$($path)*] $($k)-+ = (-$v) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `key = 1979-05-27T00:32:00.999999-07:00`.
|
||||||
|
(@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)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `key = 1979-05-27T00:32:00-07:00`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local datetime `key = 1979-05-27T00:32:00.999999`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `key = 1979-05-27T07:32:00Z` and local datetime `key = 1979-05-27T07:32:00`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($yr - $mo - $dhr : $min : $sec) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local date `key = 1979-05-27`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $yr:tt - $mo:tt - $day:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($yr - $mo - $day) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local time `key = 00:32:00.999999`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $hr:tt : $min:tt : $sec:tt . $frac:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($hr : $min : $sec . $frac) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local time `key = 07:32:00`.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $hr:tt : $min:tt : $sec:tt $($rest:tt)*) => {
|
||||||
|
toml_internal!(@topleveldatetime $root [$($path)*] $($k)-+ = ($hr : $min : $sec) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse any other `key = value` including string, inline array, inline
|
||||||
|
// table, number, and boolean.
|
||||||
|
(@toplevel $root:ident [$($path:tt)*] $($k:tt)-+ = $v:tt $($rest:tt)*) => {
|
||||||
|
$crate::macros::insert_toml(
|
||||||
|
&mut $root,
|
||||||
|
&[$($path)* &concat!($("-", toml_internal!(@path $k),)+)[1..]],
|
||||||
|
toml_internal!(@value $v));
|
||||||
|
toml_internal!(@toplevel $root [$($path)*] $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse array header `[[bin]]`.
|
||||||
|
(@toplevel $root:ident $oldpath:tt [[$($($path:tt)-+).+]] $($rest:tt)*) => {
|
||||||
|
$crate::macros::push_toml(
|
||||||
|
&mut $root,
|
||||||
|
&[$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+]);
|
||||||
|
toml_internal!(@toplevel $root [$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+] $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse table header `[patch.crates-io]`.
|
||||||
|
(@toplevel $root:ident $oldpath:tt [$($($path:tt)-+).+] $($rest:tt)*) => {
|
||||||
|
$crate::macros::insert_toml(
|
||||||
|
&mut $root,
|
||||||
|
&[$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+],
|
||||||
|
$crate::Value::Table($crate::value::Table::new()));
|
||||||
|
toml_internal!(@toplevel $root [$(&concat!($("-", toml_internal!(@path $path),)+)[1..],)+] $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse datetime from string and insert into table.
|
||||||
|
(@topleveldatetime $root:ident [$($path:tt)*] $($k:tt)-+ = ($($datetime:tt)+) $($rest:tt)*) => {
|
||||||
|
$crate::macros::insert_toml(
|
||||||
|
&mut $root,
|
||||||
|
&[$($path)* &concat!($("-", toml_internal!(@path $k),)+)[1..]],
|
||||||
|
$crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
|
||||||
|
toml_internal!(@toplevel $root [$($path)*] $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Turn a path segment into a string.
|
||||||
|
(@path $ident:ident) => {
|
||||||
|
stringify!($ident)
|
||||||
|
};
|
||||||
|
|
||||||
|
// For a path segment that is not an ident, expect that it is already a
|
||||||
|
// quoted string, like in `[target."cfg(windows)".dependencies]`.
|
||||||
|
(@path $quoted:tt) => {
|
||||||
|
$quoted
|
||||||
|
};
|
||||||
|
|
||||||
|
// Construct a Value from an inline table.
|
||||||
|
(@value { $($inline:tt)* }) => {{
|
||||||
|
let mut table = $crate::value::Table::new();
|
||||||
|
toml_internal!(@trailingcomma (@table table) $($inline)*);
|
||||||
|
$crate::Value::Table(table)
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Construct a Value from an inline array.
|
||||||
|
(@value [ $($inline:tt)* ]) => {{
|
||||||
|
let mut array = $crate::value::Array::new();
|
||||||
|
toml_internal!(@trailingcomma (@array array) $($inline)*);
|
||||||
|
$crate::Value::Array(array)
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Construct a Value from any other type, probably string or boolean or number.
|
||||||
|
(@value $v:tt) => {{
|
||||||
|
// TODO: Implement this with something like serde_json::to_value instead.
|
||||||
|
let de = $crate::macros::IntoDeserializer::<$crate::de::Error>::into_deserializer($v);
|
||||||
|
<$crate::Value as $crate::macros::Deserialize>::deserialize(de).unwrap()
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Base case of inline table.
|
||||||
|
(@table $root:ident) => {};
|
||||||
|
|
||||||
|
// Parse negative number `key = -value`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = - $v:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@table $root $($k)-+ = (-$v) , $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `key = 1979-05-27T00:32:00.999999-07:00`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `key = 1979-05-27T00:32:00-07:00`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local datetime `key = 1979-05-27T00:32:00.999999`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `key = 1979-05-27T07:32:00Z` and local datetime `key = 1979-05-27T07:32:00`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($yr - $mo - $dhr : $min : $sec) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local date `key = 1979-05-27`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $yr:tt - $mo:tt - $day:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($yr - $mo - $day) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local time `key = 00:32:00.999999`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($hr : $min : $sec . $frac) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local time `key = 07:32:00`.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@tabledatetime $root $($k)-+ = ($hr : $min : $sec) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse any other type, probably string or boolean or number.
|
||||||
|
(@table $root:ident $($k:tt)-+ = $v:tt , $($rest:tt)*) => {
|
||||||
|
$root.insert(
|
||||||
|
concat!($("-", toml_internal!(@path $k),)+)[1..].to_owned(),
|
||||||
|
toml_internal!(@value $v));
|
||||||
|
toml_internal!(@table $root $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse a Datetime from string and continue in @table state.
|
||||||
|
(@tabledatetime $root:ident $($k:tt)-+ = ($($datetime:tt)*) $($rest:tt)*) => {
|
||||||
|
$root.insert(
|
||||||
|
concat!($("-", toml_internal!(@path $k),)+)[1..].to_owned(),
|
||||||
|
$crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
|
||||||
|
toml_internal!(@table $root $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base case of inline array.
|
||||||
|
(@array $root:ident) => {};
|
||||||
|
|
||||||
|
// Parse negative number `-value`.
|
||||||
|
(@array $root:ident - $v:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@array $root (-$v) , $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `1979-05-27T00:32:00.999999-07:00`.
|
||||||
|
(@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec . $frac - $tzh : $tzm) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `1979-05-27T00:32:00-07:00`.
|
||||||
|
(@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt - $tzh:tt : $tzm:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec - $tzh : $tzm) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local datetime `1979-05-27T00:32:00.999999`.
|
||||||
|
(@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec . $frac) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse offset datetime `1979-05-27T07:32:00Z` and local datetime `1979-05-27T07:32:00`.
|
||||||
|
(@array $root:ident $yr:tt - $mo:tt - $dhr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($yr - $mo - $dhr : $min : $sec) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local date `1979-05-27`.
|
||||||
|
(@array $root:ident $yr:tt - $mo:tt - $day:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($yr - $mo - $day) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local time `00:32:00.999999`.
|
||||||
|
(@array $root:ident $hr:tt : $min:tt : $sec:tt . $frac:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($hr : $min : $sec . $frac) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse local time `07:32:00`.
|
||||||
|
(@array $root:ident $hr:tt : $min:tt : $sec:tt , $($rest:tt)*) => {
|
||||||
|
toml_internal!(@arraydatetime $root ($hr : $min : $sec) $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse any other type, probably string or boolean or number.
|
||||||
|
(@array $root:ident $v:tt , $($rest:tt)*) => {
|
||||||
|
$root.push(toml_internal!(@value $v));
|
||||||
|
toml_internal!(@array $root $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse a Datetime from string and continue in @array state.
|
||||||
|
(@arraydatetime $root:ident ($($datetime:tt)*) $($rest:tt)*) => {
|
||||||
|
$root.push($crate::Value::Datetime(concat!($(stringify!($datetime)),+).parse().unwrap()));
|
||||||
|
toml_internal!(@array $root $($rest)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// No trailing comma required if the tokens are empty.
|
||||||
|
(@trailingcomma ($($args:tt)*)) => {
|
||||||
|
toml_internal!($($args)*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tokens end with a trailing comma, do not append another one.
|
||||||
|
(@trailingcomma ($($args:tt)*) ,) => {
|
||||||
|
toml_internal!($($args)* ,);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tokens end with something other than comma, append a trailing comma.
|
||||||
|
(@trailingcomma ($($args:tt)*) $last:tt) => {
|
||||||
|
toml_internal!($($args)* $last ,);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Not yet at the last token.
|
||||||
|
(@trailingcomma ($($args:tt)*) $first:tt $($rest:tt)+) => {
|
||||||
|
toml_internal!(@trailingcomma ($($args)* $first) $($rest)+);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when parsing a `key = value` pair.
|
||||||
|
// Inserts an entry into the table at the given path.
|
||||||
|
pub fn insert_toml(root: &mut Value, path: &[&str], value: Value) {
|
||||||
|
*traverse(root, path) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when parsing an `[[array header]]`.
|
||||||
|
// Pushes an empty table onto the array at the given path.
|
||||||
|
pub fn push_toml(root: &mut Value, path: &[&str]) {
|
||||||
|
let target = traverse(root, path);
|
||||||
|
if !target.is_array() {
|
||||||
|
*target = Value::Array(Array::new());
|
||||||
|
}
|
||||||
|
target.as_array_mut().unwrap().push(Value::Table(Table::new()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn traverse<'a>(root: &'a mut Value, path: &[&str]) -> &'a mut Value {
|
||||||
|
let mut cur = root;
|
||||||
|
for &key in path {
|
||||||
|
// Lexical lifetimes :D
|
||||||
|
let cur1 = cur;
|
||||||
|
let cur2;
|
||||||
|
|
||||||
|
// From the TOML spec:
|
||||||
|
//
|
||||||
|
// > Each double-bracketed sub-table will belong to the most recently
|
||||||
|
// > defined table element above it.
|
||||||
|
if cur1.is_array() {
|
||||||
|
cur2 = cur1.as_array_mut().unwrap().last_mut().unwrap();
|
||||||
|
} else {
|
||||||
|
cur2 = cur1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// We are about to index into this value, so it better be a table.
|
||||||
|
if !cur2.is_table() {
|
||||||
|
*cur2 = Value::Table(Table::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cur2.as_table().unwrap().contains_key(key) {
|
||||||
|
// Insert an empty table for the next loop iteration to point to.
|
||||||
|
let empty = Value::Table(Table::new());
|
||||||
|
cur2.as_table_mut().unwrap().insert(key.to_owned(), empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step into the current table.
|
||||||
|
cur = cur2.as_table_mut().unwrap().get_mut(key).unwrap();
|
||||||
|
}
|
||||||
|
cur
|
||||||
|
}
|
15
test-suite/Cargo.toml
Normal file
15
test-suite/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "toml_test_suite"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
build = "build.rs"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
rustc_version = "0.2"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
toml = { path = ".." }
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0"
|
8
test-suite/build.rs
Normal file
8
test-suite/build.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
extern crate rustc_version;
|
||||||
|
use rustc_version::{version, Version};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if version().unwrap() >= Version::parse("1.20.0").unwrap() {
|
||||||
|
println!(r#"cargo:rustc-cfg=feature="test-quoted-keys-in-macro""#);
|
||||||
|
}
|
||||||
|
}
|
286
test-suite/tests/macros.rs
Normal file
286
test-suite/tests/macros.rs
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
#![recursion_limit = "128"]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate toml;
|
||||||
|
|
||||||
|
macro_rules! table {
|
||||||
|
($($key:expr => $value:expr,)*) => {{
|
||||||
|
let mut table = toml::value::Table::new();
|
||||||
|
$(
|
||||||
|
table.insert($key.to_string(), $value.into());
|
||||||
|
)*
|
||||||
|
toml::Value::Table(table)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! array {
|
||||||
|
($($element:expr,)*) => {{
|
||||||
|
let mut array = toml::value::Array::new();
|
||||||
|
$(
|
||||||
|
array.push($element.into());
|
||||||
|
)*
|
||||||
|
toml::Value::Array(array)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! datetime {
|
||||||
|
($s:tt) => {
|
||||||
|
$s.parse::<toml::value::Datetime>().unwrap()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cargo_toml() {
|
||||||
|
// Simple sanity check of:
|
||||||
|
//
|
||||||
|
// - Ordinary tables
|
||||||
|
// - Inline tables
|
||||||
|
// - Inline arrays
|
||||||
|
// - String values
|
||||||
|
// - Table keys containing hyphen
|
||||||
|
// - Table headers containing hyphen
|
||||||
|
let actual = toml! {
|
||||||
|
[package]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.4.5"
|
||||||
|
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
travis-ci = { repository = "alexcrichton/toml-rs" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "1.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = table! {
|
||||||
|
"package" => table! {
|
||||||
|
"name" => "toml".to_owned(),
|
||||||
|
"version" => "0.4.5".to_owned(),
|
||||||
|
"authors" => array! {
|
||||||
|
"Alex Crichton <alex@alexcrichton.com>".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"badges" => table! {
|
||||||
|
"travis-ci" => table! {
|
||||||
|
"repository" => "alexcrichton/toml-rs".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"dependencies" => table! {
|
||||||
|
"serde" => "1.0".to_owned(),
|
||||||
|
},
|
||||||
|
"dev-dependencies" => table! {
|
||||||
|
"serde_derive" => "1.0".to_owned(),
|
||||||
|
"serde_json" => "1.0".to_owned(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_array() {
|
||||||
|
// Copied from the TOML spec.
|
||||||
|
let actual = toml! {
|
||||||
|
[[fruit]]
|
||||||
|
name = "apple"
|
||||||
|
|
||||||
|
[fruit.physical]
|
||||||
|
color = "red"
|
||||||
|
shape = "round"
|
||||||
|
|
||||||
|
[[fruit.variety]]
|
||||||
|
name = "red delicious"
|
||||||
|
|
||||||
|
[[fruit.variety]]
|
||||||
|
name = "granny smith"
|
||||||
|
|
||||||
|
[[fruit]]
|
||||||
|
name = "banana"
|
||||||
|
|
||||||
|
[[fruit.variety]]
|
||||||
|
name = "plantain"
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = table! {
|
||||||
|
"fruit" => array! {
|
||||||
|
table! {
|
||||||
|
"name" => "apple",
|
||||||
|
"physical" => table! {
|
||||||
|
"color" => "red",
|
||||||
|
"shape" => "round",
|
||||||
|
},
|
||||||
|
"variety" => array! {
|
||||||
|
table! {
|
||||||
|
"name" => "red delicious",
|
||||||
|
},
|
||||||
|
table! {
|
||||||
|
"name" => "granny smith",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
table! {
|
||||||
|
"name" => "banana",
|
||||||
|
"variety" => array! {
|
||||||
|
table! {
|
||||||
|
"name" => "plantain",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_number() {
|
||||||
|
let actual = toml! {
|
||||||
|
positive = 1
|
||||||
|
negative = -1
|
||||||
|
table = { positive = 1, negative = -1 }
|
||||||
|
array = [ 1, -1 ]
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = table! {
|
||||||
|
"positive" => 1,
|
||||||
|
"negative" => -1,
|
||||||
|
"table" => table! {
|
||||||
|
"positive" => 1,
|
||||||
|
"negative" => -1,
|
||||||
|
},
|
||||||
|
"array" => array! {
|
||||||
|
1,
|
||||||
|
-1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime() {
|
||||||
|
let actual = toml! {
|
||||||
|
// Copied from the TOML spec.
|
||||||
|
odt1 = 1979-05-27T07:32:00Z
|
||||||
|
odt2 = 1979-05-27T00:32:00-07:00
|
||||||
|
odt3 = 1979-05-27T00:32:00.999999-07:00
|
||||||
|
ldt1 = 1979-05-27T07:32:00
|
||||||
|
ldt2 = 1979-05-27T00:32:00.999999
|
||||||
|
ld1 = 1979-05-27
|
||||||
|
lt1 = 07:32:00
|
||||||
|
lt2 = 00:32:00.999999
|
||||||
|
|
||||||
|
table = {
|
||||||
|
odt1 = 1979-05-27T07:32:00Z,
|
||||||
|
odt2 = 1979-05-27T00:32:00-07:00,
|
||||||
|
odt3 = 1979-05-27T00:32:00.999999-07:00,
|
||||||
|
ldt1 = 1979-05-27T07:32:00,
|
||||||
|
ldt2 = 1979-05-27T00:32:00.999999,
|
||||||
|
ld1 = 1979-05-27,
|
||||||
|
lt1 = 07:32:00,
|
||||||
|
lt2 = 00:32:00.999999,
|
||||||
|
}
|
||||||
|
|
||||||
|
array = [
|
||||||
|
1979-05-27T07:32:00Z,
|
||||||
|
1979-05-27T00:32:00-07:00,
|
||||||
|
1979-05-27T00:32:00.999999-07:00,
|
||||||
|
1979-05-27T07:32:00,
|
||||||
|
1979-05-27T00:32:00.999999,
|
||||||
|
1979-05-27,
|
||||||
|
07:32:00,
|
||||||
|
00:32:00.999999,
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = table! {
|
||||||
|
"odt1" => datetime!("1979-05-27T07:32:00Z"),
|
||||||
|
"odt2" => datetime!("1979-05-27T00:32:00-07:00"),
|
||||||
|
"odt3" => datetime!("1979-05-27T00:32:00.999999-07:00"),
|
||||||
|
"ldt1" => datetime!("1979-05-27T07:32:00"),
|
||||||
|
"ldt2" => datetime!("1979-05-27T00:32:00.999999"),
|
||||||
|
"ld1" => datetime!("1979-05-27"),
|
||||||
|
"lt1" => datetime!("07:32:00"),
|
||||||
|
"lt2" => datetime!("00:32:00.999999"),
|
||||||
|
|
||||||
|
"table" => table! {
|
||||||
|
"odt1" => datetime!("1979-05-27T07:32:00Z"),
|
||||||
|
"odt2" => datetime!("1979-05-27T00:32:00-07:00"),
|
||||||
|
"odt3" => datetime!("1979-05-27T00:32:00.999999-07:00"),
|
||||||
|
"ldt1" => datetime!("1979-05-27T07:32:00"),
|
||||||
|
"ldt2" => datetime!("1979-05-27T00:32:00.999999"),
|
||||||
|
"ld1" => datetime!("1979-05-27"),
|
||||||
|
"lt1" => datetime!("07:32:00"),
|
||||||
|
"lt2" => datetime!("00:32:00.999999"),
|
||||||
|
},
|
||||||
|
|
||||||
|
"array" => array! {
|
||||||
|
datetime!("1979-05-27T07:32:00Z"),
|
||||||
|
datetime!("1979-05-27T00:32:00-07:00"),
|
||||||
|
datetime!("1979-05-27T00:32:00.999999-07:00"),
|
||||||
|
datetime!("1979-05-27T07:32:00"),
|
||||||
|
datetime!("1979-05-27T00:32:00.999999"),
|
||||||
|
datetime!("1979-05-27"),
|
||||||
|
datetime!("07:32:00"),
|
||||||
|
datetime!("00:32:00.999999"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test requires rustc >= 1.20.
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "test-quoted-keys-in-macro")]
|
||||||
|
fn test_quoted_key() {
|
||||||
|
let actual = toml! {
|
||||||
|
"quoted" = true
|
||||||
|
table = { "quoted" = true }
|
||||||
|
|
||||||
|
[target."cfg(windows)".dependencies]
|
||||||
|
winapi = "0.2.8"
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = table! {
|
||||||
|
"quoted" => true,
|
||||||
|
"table" => table! {
|
||||||
|
"quoted" => true,
|
||||||
|
},
|
||||||
|
"target" => table! {
|
||||||
|
"cfg(windows)" => table! {
|
||||||
|
"dependencies" => table! {
|
||||||
|
"winapi" => "0.2.8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty() {
|
||||||
|
let actual = toml! {
|
||||||
|
empty_inline_table = {}
|
||||||
|
empty_inline_array = []
|
||||||
|
|
||||||
|
[empty_table]
|
||||||
|
|
||||||
|
[[empty_array]]
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected = table! {
|
||||||
|
"empty_inline_table" => table! {},
|
||||||
|
"empty_inline_array" => array! {},
|
||||||
|
"empty_table" => table! {},
|
||||||
|
"empty_array" => array! {
|
||||||
|
table! {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue