]> git.proxmox.com Git - rustc.git/blob - src/vendor/toml-0.1.30/src/lib.rs
New upstream version 1.17.0+dfsg1
[rustc.git] / src / vendor / toml-0.1.30 / src / lib.rs
1 //! A TOML-parsing library
2 //!
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.
6 //!
7 //! This implementation currently passes the language agnostic [test suite][2].
8 //!
9 //! # Example
10 //!
11 //! ```
12 //! let toml = r#"
13 //! [test]
14 //! foo = "bar"
15 //! "#;
16 //!
17 //! let value = toml::Parser::new(toml).parse().unwrap();
18 //! println!("{:?}", value);
19 //! ```
20 //!
21 //! # Conversions
22 //!
23 //! This library also supports using the standard `Encodable` and `Decodable`
24 //! traits with TOML values. This library provides the following conversion
25 //! capabilities:
26 //!
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`
31 //!
32 //! Convenience functions for performing multiple conversions at a time are also
33 //! provided.
34 //!
35 //! [1]: https://github.com/mojombo/toml
36 //! [2]: https://github.com/BurntSushi/toml-test
37
38 #![doc(html_root_url = "http://alexcrichton.com/toml-rs")]
39 #![deny(missing_docs)]
40 #![cfg_attr(test, deny(warnings))]
41
42 #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize;
43 #[cfg(feature = "serde")] extern crate serde;
44
45 use std::collections::BTreeMap;
46 use std::str::FromStr;
47
48 pub use parser::{Parser, ParserError};
49
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};
54
55 mod parser;
56 mod display;
57 #[cfg(any(feature = "rustc-serialize", feature = "serde"))]
58 mod encoder;
59 #[cfg(any(feature = "rustc-serialize", feature = "serde"))]
60 mod decoder;
61
62 /// Representation of a TOML value.
63 #[derive(PartialEq, Clone, Debug)]
64 #[allow(missing_docs)]
65 pub enum Value {
66 String(String),
67 Integer(i64),
68 Float(f64),
69 Boolean(bool),
70 Datetime(String),
71 Array(Array),
72 Table(Table),
73 }
74
75 /// Type representing a TOML array, payload of the Value::Array variant
76 pub type Array = Vec<Value>;
77
78 /// Type representing a TOML table, payload of the Value::Table variant
79 pub type Table = BTreeMap<String, Value>;
80
81 impl Value {
82 /// Tests whether this and another value have the same type.
83 pub fn same_type(&self, other: &Value) -> bool {
84 match (self, other) {
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,
92
93 _ => false,
94 }
95 }
96
97 /// Returns a human-readable representation of the type of this value.
98 pub fn type_str(&self) -> &'static str {
99 match *self {
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",
107 }
108 }
109
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 }
113 }
114
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 }
118 }
119
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 }
123 }
124
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 }
128 }
129
130 /// Extracts the datetime value if it is a datetime.
131 ///
132 /// Note that a parsed TOML value will only contain ISO 8601 dates. An
133 /// example date is:
134 ///
135 /// ```notrust
136 /// 1979-05-27T07:32:00Z
137 /// ```
138 pub fn as_datetime(&self) -> Option<&str> {
139 match *self { Value::Datetime(ref s) => Some(&**s), _ => None }
140 }
141
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 }
145 }
146
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 }
150 }
151
152 /// Lookups for value at specified path.
153 ///
154 /// Uses '.' as a path separator.
155 ///
156 /// Note: arrays have zero-based indexes.
157 ///
158 /// Note: empty path returns self.
159 ///
160 /// ```
161 /// # #![allow(unstable)]
162 /// let toml = r#"
163 /// [test]
164 /// foo = "bar"
165 ///
166 /// [[values]]
167 /// foo = "baz"
168 ///
169 /// [[values]]
170 /// foo = "qux"
171 /// "#;
172 /// let value: toml::Value = toml.parse().unwrap();
173 ///
174 /// let foo = value.lookup("test.foo").unwrap();
175 /// assert_eq!(foo.as_str().unwrap(), "bar");
176 ///
177 /// let foo = value.lookup("values.1.foo").unwrap();
178 /// assert_eq!(foo.as_str().unwrap(), "qux");
179 ///
180 /// let no_bar = value.lookup("test.bar");
181 /// assert_eq!(no_bar.is_none(), true);
182 /// ```
183 pub fn lookup<'a>(&'a self, path: &'a str) -> Option<&'a Value> {
184 let ref path = match Parser::new(path).lookup() {
185 Some(path) => path,
186 None => return None,
187 };
188 let mut cur_value = self;
189 if path.len() == 0 {
190 return Some(cur_value)
191 }
192
193 for key in path {
194 match *cur_value {
195 Value::Table(ref hm) => {
196 match hm.get(key) {
197 Some(v) => cur_value = v,
198 None => return None
199 }
200 },
201 Value::Array(ref v) => {
202 match key.parse::<usize>().ok() {
203 Some(idx) if idx < v.len() => cur_value = &v[idx],
204 _ => return None
205 }
206 },
207 _ => return None
208 }
209 };
210
211 Some(cur_value)
212
213 }
214 /// Lookups for mutable value at specified path.
215 ///
216 /// Uses '.' as a path separator.
217 ///
218 /// Note: arrays have zero-based indexes.
219 ///
220 /// Note: empty path returns self.
221 ///
222 /// ```
223 /// # #![allow(unstable)]
224 /// let toml = r#"
225 /// [test]
226 /// foo = "bar"
227 ///
228 /// [[values]]
229 /// foo = "baz"
230 ///
231 /// [[values]]
232 /// foo = "qux"
233 /// "#;
234 /// let mut value: toml::Value = toml.parse().unwrap();
235 /// {
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"));
239 /// }
240 /// let result = value.lookup_mut("test.foo").unwrap();
241 /// assert_eq!(result.as_str().unwrap(), "foo");
242 /// ```
243 pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
244 let ref path = match Parser::new(path).lookup() {
245 Some(path) => path,
246 None => return None,
247 };
248
249 let mut cur = self;
250 if path.len() == 0 {
251 return Some(cur)
252 }
253
254 for key in path {
255 let tmp = cur;
256 match *tmp {
257 Value::Table(ref mut hm) => {
258 match hm.get_mut(key) {
259 Some(v) => cur = v,
260 None => return None
261 }
262 }
263 Value::Array(ref mut v) => {
264 match key.parse::<usize>().ok() {
265 Some(idx) if idx < v.len() => cur = &mut v[idx],
266 _ => return None
267 }
268 }
269 _ => return None
270 }
271 }
272 Some(cur)
273 }
274 }
275
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) {
281 Some(n) => Ok(n),
282 None => Err(p.errors),
283 }
284 }
285 }
286
287 #[cfg(test)]
288 mod tests {
289 use super::Value;
290
291 #[test]
292 fn lookup_mut_change() {
293 let toml = r#"
294 [test]
295 foo = "bar"
296
297 [[values]]
298 foo = "baz"
299
300 [[values]]
301 foo = "qux"
302 "#;
303
304 let mut value: Value = toml.parse().unwrap();
305 {
306 let foo = value.lookup_mut("values.0.foo").unwrap();
307 *foo = Value::String(String::from("bar"));
308 }
309 let foo = value.lookup("values.0.foo").unwrap();
310 assert_eq!(foo.as_str().unwrap(), "bar");
311 }
312
313 #[test]
314 fn lookup_mut_valid() {
315 let toml = r#"
316 [test]
317 foo = "bar"
318
319 [[values]]
320 foo = "baz"
321
322 [[values]]
323 foo = "qux"
324 "#;
325
326 let mut value: Value = toml.parse().unwrap();
327
328 {
329 let test_foo = value.lookup_mut("test.foo").unwrap();
330 assert_eq!(test_foo.as_str().unwrap(), "bar");
331 }
332
333 {
334 let foo1 = value.lookup_mut("values.1.foo").unwrap();
335 assert_eq!(foo1.as_str().unwrap(), "qux");
336 }
337
338 assert!(value.lookup_mut("test.bar").is_none());
339 assert!(value.lookup_mut("test.foo.bar").is_none());
340 }
341
342 #[test]
343 fn lookup_mut_invalid_index() {
344 let toml = r#"
345 [[values]]
346 foo = "baz"
347 "#;
348
349 let mut value: Value = toml.parse().unwrap();
350
351 {
352 let foo = value.lookup_mut("test.foo");
353 assert!(foo.is_none());
354 }
355
356 {
357 let foo = value.lookup_mut("values.100.foo");
358 assert!(foo.is_none());
359 }
360
361 {
362 let foo = value.lookup_mut("values.str.foo");
363 assert!(foo.is_none());
364 }
365 }
366
367 #[test]
368 fn lookup_mut_self() {
369 let mut value: Value = r#"foo = "bar""#.parse().unwrap();
370
371 {
372 let foo = value.lookup_mut("foo").unwrap();
373 assert_eq!(foo.as_str().unwrap(), "bar");
374 }
375
376 let foo = value.lookup_mut("").unwrap();
377 assert!(foo.as_table().is_some());
378
379 let baz = foo.lookup_mut("foo").unwrap();
380 assert_eq!(baz.as_str().unwrap(), "bar");
381 }
382
383 #[test]
384 fn lookup_valid() {
385 let toml = r#"
386 [test]
387 foo = "bar"
388
389 [[values]]
390 foo = "baz"
391
392 [[values]]
393 foo = "qux"
394 "#;
395
396 let value: Value = toml.parse().unwrap();
397
398 let test_foo = value.lookup("test.foo").unwrap();
399 assert_eq!(test_foo.as_str().unwrap(), "bar");
400
401 let foo1 = value.lookup("values.1.foo").unwrap();
402 assert_eq!(foo1.as_str().unwrap(), "qux");
403
404 assert!(value.lookup("test.bar").is_none());
405 assert!(value.lookup("test.foo.bar").is_none());
406 }
407
408 #[test]
409 fn lookup_invalid_index() {
410 let toml = r#"
411 [[values]]
412 foo = "baz"
413 "#;
414
415 let value: Value = toml.parse().unwrap();
416
417 let foo = value.lookup("test.foo");
418 assert!(foo.is_none());
419
420 let foo = value.lookup("values.100.foo");
421 assert!(foo.is_none());
422
423 let foo = value.lookup("values.str.foo");
424 assert!(foo.is_none());
425 }
426
427 #[test]
428 fn lookup_self() {
429 let value: Value = r#"foo = "bar""#.parse().unwrap();
430
431 let foo = value.lookup("foo").unwrap();
432 assert_eq!(foo.as_str().unwrap(), "bar");
433
434 let foo = value.lookup("").unwrap();
435 assert!(foo.as_table().is_some());
436
437 let baz = foo.lookup("foo").unwrap();
438 assert_eq!(baz.as_str().unwrap(), "bar");
439 }
440
441 #[test]
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));
446 }
447
448 #[test]
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")));
453 }
454
455 #[test]
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));
460 }
461
462 #[test]
463 fn single_dot() {
464 let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
465 assert_eq!(None, value.lookup("."));
466 }
467
468 #[test]
469 fn array_dot() {
470 let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
471 assert_eq!(None, value.lookup("0."));
472 }
473
474 #[test]
475 fn dot_inside() {
476 let value: Value = "[table]\n\"value\" = [0, 1, 2]".parse().unwrap();
477 assert_eq!(None, value.lookup("table.\"value.0\""));
478 }
479
480 #[test]
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"));
484 }
485
486 #[test]
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());
490 }
491
492 }