1 //! A TOML-parsing library
3 //! This library is an implementation in Rust of a parser for TOML configuration
4 //! files [1]. It is focused around high quality errors including specific spans
5 //! and detailed error messages when things go wrong.
7 //! This implementation currently passes the language agnostic [test suite][2].
17 //! let value = toml::Parser::new(toml).parse().unwrap();
18 //! println!("{:?}", value);
23 //! This library also supports using the standard `Encodable` and `Decodable`
24 //! traits with TOML values. This library provides the following conversion
27 //! * `String` => `toml::Value` - via `Parser`
28 //! * `toml::Value` => `String` - via `Display`
29 //! * `toml::Value` => rust object - via `Decoder`
30 //! * rust object => `toml::Value` - via `Encoder`
32 //! Convenience functions for performing multiple conversions at a time are also
35 //! [1]: https://github.com/mojombo/toml
36 //! [2]: https://github.com/BurntSushi/toml-test
38 #![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
39 #![deny(missing_docs)]
40 #![cfg_attr(test, deny(warnings))]
42 #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
43 #[cfg(feature = "serde")] extern crate serde;
45 use std
::collections
::BTreeMap
;
46 use std
::str::FromStr
;
48 pub use parser
::{Parser, ParserError}
;
50 #[cfg(any(feature = "rustc-serialize", feature = "serde"))]
51 pub use self::encoder
::{Encoder, Error, encode, encode_str}
;
52 #[cfg(any(feature = "rustc-serialize", feature = "serde"))]
53 pub use self::decoder
::{Decoder, DecodeError, DecodeErrorKind, decode, decode_str}
;
57 #[cfg(any(feature = "rustc-serialize", feature = "serde"))]
59 #[cfg(any(feature = "rustc-serialize", feature = "serde"))]
62 /// Representation of a TOML value.
63 #[derive(PartialEq, Clone, Debug)]
64 #[allow(missing_docs)]
75 /// Type representing a TOML array, payload of the Value::Array variant
76 pub type Array
= Vec
<Value
>;
78 /// Type representing a TOML table, payload of the Value::Table variant
79 pub type Table
= BTreeMap
<String
, Value
>;
82 /// Tests whether this and another value have the same type.
83 pub fn same_type(&self, other
: &Value
) -> bool
{
85 (&Value
::String(..), &Value
::String(..)) |
86 (&Value
::Integer(..), &Value
::Integer(..)) |
87 (&Value
::Float(..), &Value
::Float(..)) |
88 (&Value
::Boolean(..), &Value
::Boolean(..)) |
89 (&Value
::Datetime(..), &Value
::Datetime(..)) |
90 (&Value
::Array(..), &Value
::Array(..)) |
91 (&Value
::Table(..), &Value
::Table(..)) => true,
97 /// Returns a human-readable representation of the type of this value.
98 pub fn type_str(&self) -> &'
static str {
100 Value
::String(..) => "string",
101 Value
::Integer(..) => "integer",
102 Value
::Float(..) => "float",
103 Value
::Boolean(..) => "boolean",
104 Value
::Datetime(..) => "datetime",
105 Value
::Array(..) => "array",
106 Value
::Table(..) => "table",
110 /// Extracts the string of this value if it is a string.
111 pub fn as_str(&self) -> Option
<&str> {
112 match *self { Value::String(ref s) => Some(&**s), _ => None }
115 /// Extracts the integer value if it is an integer.
116 pub fn as_integer(&self) -> Option
<i64> {
117 match *self { Value::Integer(i) => Some(i), _ => None }
120 /// Extracts the float value if it is a float.
121 pub fn as_float(&self) -> Option
<f64> {
122 match *self { Value::Float(f) => Some(f), _ => None }
125 /// Extracts the boolean value if it is a boolean.
126 pub fn as_bool(&self) -> Option
<bool
> {
127 match *self { Value::Boolean(b) => Some(b), _ => None }
130 /// Extracts the datetime value if it is a datetime.
132 /// Note that a parsed TOML value will only contain ISO 8601 dates. An
136 /// 1979-05-27T07:32:00Z
138 pub fn as_datetime(&self) -> Option
<&str> {
139 match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
142 /// Extracts the array value if it is an array.
143 pub fn as_slice(&self) -> Option
<&[Value
]> {
144 match *self { Value::Array(ref s) => Some(&**s), _ => None }
147 /// Extracts the table value if it is a table.
148 pub fn as_table(&self) -> Option
<&Table
> {
149 match *self { Value::Table(ref s) => Some(s), _ => None }
152 /// Lookups for value at specified path.
154 /// Uses '.' as a path separator.
156 /// Note: arrays have zero-based indexes.
158 /// Note: empty path returns self.
161 /// # #![allow(unstable)]
172 /// let value: toml::Value = toml.parse().unwrap();
174 /// let foo = value.lookup("test.foo").unwrap();
175 /// assert_eq!(foo.as_str().unwrap(), "bar");
177 /// let foo = value.lookup("values.1.foo").unwrap();
178 /// assert_eq!(foo.as_str().unwrap(), "qux");
180 /// let no_bar = value.lookup("test.bar");
181 /// assert_eq!(no_bar.is_none(), true);
183 pub fn lookup
<'a
>(&'a
self, path
: &'a
str) -> Option
<&'a Value
> {
184 let ref path
= match Parser
::new(path
).lookup() {
188 let mut cur_value
= self;
190 return Some(cur_value
)
195 Value
::Table(ref hm
) => {
197 Some(v
) => cur_value
= v
,
201 Value
::Array(ref v
) => {
202 match key
.parse
::<usize>().ok() {
203 Some(idx
) if idx
< v
.len() => cur_value
= &v
[idx
],
214 /// Lookups for mutable value at specified path.
216 /// Uses '.' as a path separator.
218 /// Note: arrays have zero-based indexes.
220 /// Note: empty path returns self.
223 /// # #![allow(unstable)]
234 /// let mut value: toml::Value = toml.parse().unwrap();
236 /// let string = value.lookup_mut("test.foo").unwrap();
237 /// assert_eq!(string, &mut toml::Value::String(String::from("bar")));
238 /// *string = toml::Value::String(String::from("foo"));
240 /// let result = value.lookup_mut("test.foo").unwrap();
241 /// assert_eq!(result.as_str().unwrap(), "foo");
243 pub fn lookup_mut(&mut self, path
: &str) -> Option
<&mut Value
> {
244 let ref path
= match Parser
::new(path
).lookup() {
257 Value
::Table(ref mut hm
) => {
258 match hm
.get_mut(key
) {
263 Value
::Array(ref mut v
) => {
264 match key
.parse
::<usize>().ok() {
265 Some(idx
) if idx
< v
.len() => cur
= &mut v
[idx
],
276 impl FromStr
for Value
{
277 type Err
= Vec
<ParserError
>;
278 fn from_str(s
: &str) -> Result
<Value
, Vec
<ParserError
>> {
279 let mut p
= Parser
::new(s
);
280 match p
.parse().map(Value
::Table
) {
282 None
=> Err(p
.errors
),
292 fn lookup_mut_change() {
304 let mut value
: Value
= toml
.parse().unwrap();
306 let foo
= value
.lookup_mut("values.0.foo").unwrap();
307 *foo
= Value
::String(String
::from("bar"));
309 let foo
= value
.lookup("values.0.foo").unwrap();
310 assert_eq
!(foo
.as_str().unwrap(), "bar");
314 fn lookup_mut_valid() {
326 let mut value
: Value
= toml
.parse().unwrap();
329 let test_foo
= value
.lookup_mut("test.foo").unwrap();
330 assert_eq
!(test_foo
.as_str().unwrap(), "bar");
334 let foo1
= value
.lookup_mut("values.1.foo").unwrap();
335 assert_eq
!(foo1
.as_str().unwrap(), "qux");
338 assert
!(value
.lookup_mut("test.bar").is_none());
339 assert
!(value
.lookup_mut("test.foo.bar").is_none());
343 fn lookup_mut_invalid_index() {
349 let mut value
: Value
= toml
.parse().unwrap();
352 let foo
= value
.lookup_mut("test.foo");
353 assert
!(foo
.is_none());
357 let foo
= value
.lookup_mut("values.100.foo");
358 assert
!(foo
.is_none());
362 let foo
= value
.lookup_mut("values.str.foo");
363 assert
!(foo
.is_none());
368 fn lookup_mut_self() {
369 let mut value
: Value
= r
#"foo = "bar""#.parse().unwrap();
372 let foo
= value
.lookup_mut("foo").unwrap();
373 assert_eq
!(foo
.as_str().unwrap(), "bar");
376 let foo
= value
.lookup_mut("").unwrap();
377 assert
!(foo
.as_table().is_some());
379 let baz
= foo
.lookup_mut("foo").unwrap();
380 assert_eq
!(baz
.as_str().unwrap(), "bar");
396 let value
: Value
= toml
.parse().unwrap();
398 let test_foo
= value
.lookup("test.foo").unwrap();
399 assert_eq
!(test_foo
.as_str().unwrap(), "bar");
401 let foo1
= value
.lookup("values.1.foo").unwrap();
402 assert_eq
!(foo1
.as_str().unwrap(), "qux");
404 assert
!(value
.lookup("test.bar").is_none());
405 assert
!(value
.lookup("test.foo.bar").is_none());
409 fn lookup_invalid_index() {
415 let value
: Value
= toml
.parse().unwrap();
417 let foo
= value
.lookup("test.foo");
418 assert
!(foo
.is_none());
420 let foo
= value
.lookup("values.100.foo");
421 assert
!(foo
.is_none());
423 let foo
= value
.lookup("values.str.foo");
424 assert
!(foo
.is_none());
429 let value
: Value
= r
#"foo = "bar""#.parse().unwrap();
431 let foo
= value
.lookup("foo").unwrap();
432 assert_eq
!(foo
.as_str().unwrap(), "bar");
434 let foo
= value
.lookup("").unwrap();
435 assert
!(foo
.as_table().is_some());
437 let baz
= foo
.lookup("foo").unwrap();
438 assert_eq
!(baz
.as_str().unwrap(), "bar");
442 fn lookup_advanced() {
443 let value
: Value
= "[table]\n\"value\" = 0".parse().unwrap();
444 let looked
= value
.lookup("table.\"value\"").unwrap();
445 assert_eq
!(*looked
, Value
::Integer(0));
449 fn lookup_advanced_table() {
450 let value
: Value
= "[table.\"name.other\"]\nvalue = \"my value\"".parse().unwrap();
451 let looked
= value
.lookup(r
#"table."name.other".value"#).unwrap();
452 assert_eq
!(*looked
, Value
::String(String
::from("my value")));
456 fn lookup_mut_advanced() {
457 let mut value
: Value
= "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
458 let looked
= value
.lookup_mut("table.\"value\".1").unwrap();
459 assert_eq
!(*looked
, Value
::Integer(1));
464 let value
: Value
= "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
465 assert_eq
!(None
, value
.lookup("."));
470 let value
: Value
= "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
471 assert_eq
!(None
, value
.lookup("0."));
476 let value
: Value
= "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
477 assert_eq
!(None
, value
.lookup("table.\"value.0\""));
481 fn table_with_quotes() {
482 let value
: Value
= "[table.\"element\"]\n\"value\" = [0, 1, 2]".parse().unwrap();
483 assert_eq
!(None
, value
.lookup("\"table.element\".\"value\".0"));
487 fn table_with_quotes_2() {
488 let value
: Value
= "[table.\"element\"]\n\"value\" = [0, 1, 2]".parse().unwrap();
489 assert_eq
!(Value
::Integer(0), *value
.lookup("table.\"element\".\"value\".0").unwrap());