2015-05-24 18:16:28 +00:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
use std::ops::Index;
|
2015-05-24 06:27:42 +00:00
|
|
|
use std::string;
|
2016-02-07 21:52:20 +00:00
|
|
|
use std::i64;
|
2015-05-24 19:29:52 +00:00
|
|
|
use std::str::FromStr;
|
2015-05-26 18:50:51 +00:00
|
|
|
use std::mem;
|
|
|
|
use parser::*;
|
2015-05-30 14:39:50 +00:00
|
|
|
use scanner::{TScalarStyle, ScanError, TokenType};
|
2015-05-24 06:27:42 +00:00
|
|
|
|
2016-03-10 09:55:21 +00:00
|
|
|
/// A YAML node is stored as this `Yaml` enumeration, which provides an easy way to
|
2015-05-31 09:59:43 +00:00
|
|
|
/// access your YAML document.
|
2015-06-29 16:31:22 +00:00
|
|
|
///
|
2015-05-31 09:59:43 +00:00
|
|
|
/// # Examples
|
2015-06-29 16:31:22 +00:00
|
|
|
///
|
2015-05-31 09:59:43 +00:00
|
|
|
/// ```
|
|
|
|
/// use yaml_rust::Yaml;
|
|
|
|
/// let foo = Yaml::from_str("-123"); // convert the string to the appropriate YAML type
|
|
|
|
/// assert_eq!(foo.as_i64().unwrap(), -123);
|
2015-06-29 16:31:22 +00:00
|
|
|
///
|
2016-03-10 09:55:21 +00:00
|
|
|
/// // iterate over an Array
|
2015-05-31 09:59:43 +00:00
|
|
|
/// let vec = Yaml::Array(vec![Yaml::Integer(1), Yaml::Integer(2)]);
|
|
|
|
/// for v in vec.as_vec().unwrap() {
|
|
|
|
/// assert!(v.as_i64().is_some());
|
|
|
|
/// }
|
|
|
|
/// ```
|
2016-03-20 05:06:44 +00:00
|
|
|
#[derive(Clone, PartialEq, PartialOrd, Debug, Eq, Ord, Hash)]
|
2015-05-24 06:27:42 +00:00
|
|
|
pub enum Yaml {
|
2016-03-10 09:55:21 +00:00
|
|
|
/// Float types are stored as String and parsed on demand.
|
|
|
|
/// Note that f64 does NOT implement Eq trait and can NOT be stored in BTreeMap.
|
2015-05-30 14:39:50 +00:00
|
|
|
Real(string::String),
|
2016-03-10 09:55:21 +00:00
|
|
|
/// YAML int is stored as i64.
|
2015-05-30 14:39:50 +00:00
|
|
|
Integer(i64),
|
2016-03-10 09:55:21 +00:00
|
|
|
/// YAML scalar.
|
2015-05-24 06:27:42 +00:00
|
|
|
String(string::String),
|
2016-03-10 09:55:21 +00:00
|
|
|
/// YAML bool, e.g. `true` or `false`.
|
2015-05-24 06:27:42 +00:00
|
|
|
Boolean(bool),
|
2016-03-10 09:55:21 +00:00
|
|
|
/// YAML array, can be accessed as a `Vec`.
|
2015-05-24 06:27:42 +00:00
|
|
|
Array(self::Array),
|
2016-03-10 09:55:21 +00:00
|
|
|
/// YAML hash, can be accessed as a `BTreeMap`.
|
2016-03-20 05:06:44 +00:00
|
|
|
///
|
|
|
|
/// If the order of keys is meaningful, enable the `preserve_order` feature to
|
|
|
|
/// store hashes as a `LinkedHashMap` intead of `BTreeMap`. When using a
|
|
|
|
/// `LinkedHashMap`, the itertion order will match the order of insertion into
|
|
|
|
/// the map.
|
|
|
|
///
|
|
|
|
/// ```toml
|
|
|
|
/// yaml-rust = { version = "*", features = ["preserve_order"] }
|
|
|
|
/// ```
|
2015-05-24 06:27:42 +00:00
|
|
|
Hash(self::Hash),
|
2015-05-31 09:59:43 +00:00
|
|
|
/// Alias, not fully supported yet.
|
2015-05-28 17:56:03 +00:00
|
|
|
Alias(usize),
|
2016-03-10 09:55:21 +00:00
|
|
|
/// YAML null, e.g. `null` or `~`.
|
2015-05-24 06:27:42 +00:00
|
|
|
Null,
|
2016-03-10 09:55:21 +00:00
|
|
|
/// Accessing a nonexistent node via the Index trait returns `BadValue`. This
|
|
|
|
/// simplifies error handling in the calling code. Invalid type conversion also
|
|
|
|
/// returns `BadValue`.
|
2015-05-24 18:16:28 +00:00
|
|
|
BadValue,
|
2015-05-24 06:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub type Array = Vec<Yaml>;
|
2016-03-20 05:06:44 +00:00
|
|
|
|
|
|
|
#[cfg(not(feature = "preserve_order"))]
|
2015-05-24 17:34:18 +00:00
|
|
|
pub type Hash = BTreeMap<Yaml, Yaml>;
|
2016-03-20 05:06:44 +00:00
|
|
|
#[cfg(feature = "preserve_order")]
|
|
|
|
pub type Hash = ::linked_hash_map::LinkedHashMap<Yaml, Yaml>;
|
2015-05-24 06:27:42 +00:00
|
|
|
|
2015-05-26 18:50:51 +00:00
|
|
|
pub struct YamlLoader {
|
|
|
|
docs: Vec<Yaml>,
|
|
|
|
// states
|
2015-12-16 07:10:02 +00:00
|
|
|
// (current node, anchor_id) tuple
|
|
|
|
doc_stack: Vec<(Yaml, usize)>,
|
2015-05-26 18:50:51 +00:00
|
|
|
key_stack: Vec<Yaml>,
|
2015-12-16 07:10:02 +00:00
|
|
|
anchor_map: BTreeMap<usize, Yaml>,
|
2015-05-26 18:50:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl EventReceiver for YamlLoader {
|
|
|
|
fn on_event(&mut self, ev: &Event) {
|
2015-05-30 14:39:50 +00:00
|
|
|
// println!("EV {:?}", ev);
|
2015-05-26 18:50:51 +00:00
|
|
|
match *ev {
|
|
|
|
Event::DocumentStart => {
|
|
|
|
// do nothing
|
|
|
|
},
|
|
|
|
Event::DocumentEnd => {
|
|
|
|
match self.doc_stack.len() {
|
|
|
|
// empty document
|
|
|
|
0 => self.docs.push(Yaml::BadValue),
|
2015-12-16 07:10:02 +00:00
|
|
|
1 => self.docs.push(self.doc_stack.pop().unwrap().0),
|
2015-05-26 18:50:51 +00:00
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
},
|
2015-12-16 07:10:02 +00:00
|
|
|
Event::SequenceStart(aid) => {
|
|
|
|
self.doc_stack.push((Yaml::Array(Vec::new()), aid));
|
2015-05-26 18:50:51 +00:00
|
|
|
},
|
|
|
|
Event::SequenceEnd => {
|
|
|
|
let node = self.doc_stack.pop().unwrap();
|
|
|
|
self.insert_new_node(node);
|
|
|
|
},
|
2015-12-16 07:10:02 +00:00
|
|
|
Event::MappingStart(aid) => {
|
|
|
|
self.doc_stack.push((Yaml::Hash(Hash::new()), aid));
|
2015-05-26 18:50:51 +00:00
|
|
|
self.key_stack.push(Yaml::BadValue);
|
|
|
|
},
|
|
|
|
Event::MappingEnd => {
|
|
|
|
self.key_stack.pop().unwrap();
|
|
|
|
let node = self.doc_stack.pop().unwrap();
|
|
|
|
self.insert_new_node(node);
|
|
|
|
},
|
2015-12-16 07:10:02 +00:00
|
|
|
Event::Scalar(ref v, style, aid, ref tag) => {
|
2015-05-26 18:50:51 +00:00
|
|
|
let node = if style != TScalarStyle::Plain {
|
|
|
|
Yaml::String(v.clone())
|
2016-02-28 00:30:13 +00:00
|
|
|
} else if let Some(TokenType::Tag(ref handle, ref suffix)) = *tag {
|
|
|
|
// XXX tag:yaml.org,2002:
|
|
|
|
if handle == "!!" {
|
|
|
|
match suffix.as_ref() {
|
|
|
|
"bool" => {
|
|
|
|
// "true" or "false"
|
|
|
|
match v.parse::<bool>() {
|
|
|
|
Err(_) => Yaml::BadValue,
|
|
|
|
Ok(v) => Yaml::Boolean(v)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"int" => {
|
|
|
|
match v.parse::<i64>() {
|
|
|
|
Err(_) => Yaml::BadValue,
|
|
|
|
Ok(v) => Yaml::Integer(v)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"float" => {
|
|
|
|
match v.parse::<f64>() {
|
|
|
|
Err(_) => Yaml::BadValue,
|
|
|
|
Ok(_) => Yaml::Real(v.clone())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"null" => {
|
|
|
|
match v.as_ref() {
|
|
|
|
"~" | "null" => Yaml::Null,
|
|
|
|
_ => Yaml::BadValue,
|
2015-05-30 14:39:50 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-28 00:30:13 +00:00
|
|
|
_ => Yaml::String(v.clone()),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Yaml::String(v.clone())
|
2015-05-26 18:50:51 +00:00
|
|
|
}
|
2016-02-28 00:30:13 +00:00
|
|
|
} else {
|
|
|
|
// Datatype is not specified, or unrecognized
|
|
|
|
Yaml::from_str(v.as_ref())
|
2015-05-26 18:50:51 +00:00
|
|
|
};
|
|
|
|
|
2015-12-16 07:10:02 +00:00
|
|
|
self.insert_new_node((node, aid));
|
2015-05-26 18:50:51 +00:00
|
|
|
},
|
2015-05-28 17:56:03 +00:00
|
|
|
Event::Alias(id) => {
|
2015-12-16 07:10:02 +00:00
|
|
|
let n = match self.anchor_map.get(&id) {
|
|
|
|
Some(v) => v.clone(),
|
|
|
|
None => Yaml::BadValue,
|
|
|
|
};
|
|
|
|
self.insert_new_node((n, 0));
|
2015-05-28 17:56:03 +00:00
|
|
|
}
|
2015-05-26 18:50:51 +00:00
|
|
|
_ => { /* ignore */ }
|
|
|
|
}
|
|
|
|
// println!("DOC {:?}", self.doc_stack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl YamlLoader {
|
2015-12-16 07:10:02 +00:00
|
|
|
fn insert_new_node(&mut self, node: (Yaml, usize)) {
|
|
|
|
// valid anchor id starts from 1
|
|
|
|
if node.1 > 0 {
|
|
|
|
self.anchor_map.insert(node.1, node.0.clone());
|
|
|
|
}
|
2016-03-10 12:49:02 +00:00
|
|
|
if self.doc_stack.is_empty() {
|
|
|
|
self.doc_stack.push(node);
|
|
|
|
} else {
|
2015-05-26 18:50:51 +00:00
|
|
|
let parent = self.doc_stack.last_mut().unwrap();
|
|
|
|
match *parent {
|
2015-12-16 07:10:02 +00:00
|
|
|
(Yaml::Array(ref mut v), _) => v.push(node.0),
|
|
|
|
(Yaml::Hash(ref mut h), _) => {
|
2015-05-26 18:50:51 +00:00
|
|
|
let mut cur_key = self.key_stack.last_mut().unwrap();
|
|
|
|
// current node is a key
|
|
|
|
if cur_key.is_badvalue() {
|
2015-12-16 07:10:02 +00:00
|
|
|
*cur_key = node.0;
|
2015-05-26 18:50:51 +00:00
|
|
|
// current node is a value
|
|
|
|
} else {
|
|
|
|
let mut newkey = Yaml::BadValue;
|
|
|
|
mem::swap(&mut newkey, cur_key);
|
2015-12-16 07:10:02 +00:00
|
|
|
h.insert(newkey, node.0);
|
2015-05-26 18:50:51 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_from_str(source: &str) -> Result<Vec<Yaml>, ScanError>{
|
|
|
|
let mut loader = YamlLoader {
|
|
|
|
docs: Vec::new(),
|
|
|
|
doc_stack: Vec::new(),
|
|
|
|
key_stack: Vec::new(),
|
2015-12-16 07:10:02 +00:00
|
|
|
anchor_map: BTreeMap::new(),
|
2015-05-26 18:50:51 +00:00
|
|
|
};
|
|
|
|
let mut parser = Parser::new(source.chars());
|
|
|
|
try!(parser.load(&mut loader, true));
|
|
|
|
Ok(loader.docs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-24 17:34:18 +00:00
|
|
|
macro_rules! define_as (
|
|
|
|
($name:ident, $t:ident, $yt:ident) => (
|
|
|
|
pub fn $name(&self) -> Option<$t> {
|
|
|
|
match *self {
|
|
|
|
Yaml::$yt(v) => Some(v),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
macro_rules! define_as_ref (
|
|
|
|
($name:ident, $t:ty, $yt:ident) => (
|
|
|
|
pub fn $name(&self) -> Option<$t> {
|
|
|
|
match *self {
|
|
|
|
Yaml::$yt(ref v) => Some(v),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
2016-08-08 02:25:30 +00:00
|
|
|
macro_rules! define_into (
|
|
|
|
($name:ident, $t:ty, $yt:ident) => (
|
|
|
|
pub fn $name(self) -> Option<$t> {
|
|
|
|
match self {
|
|
|
|
Yaml::$yt(v) => Some(v),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
2015-05-24 17:34:18 +00:00
|
|
|
impl Yaml {
|
|
|
|
define_as!(as_bool, bool, Boolean);
|
2015-05-30 14:39:50 +00:00
|
|
|
define_as!(as_i64, i64, Integer);
|
2015-05-24 17:34:18 +00:00
|
|
|
|
|
|
|
define_as_ref!(as_str, &str, String);
|
|
|
|
define_as_ref!(as_hash, &Hash, Hash);
|
|
|
|
define_as_ref!(as_vec, &Array, Array);
|
|
|
|
|
2016-08-08 02:25:30 +00:00
|
|
|
define_into!(into_bool, bool, Boolean);
|
|
|
|
define_into!(into_i64, i64, Integer);
|
|
|
|
define_into!(into_string, String, String);
|
|
|
|
define_into!(into_hash, Hash, Hash);
|
|
|
|
define_into!(into_vec, Array, Array);
|
|
|
|
|
2015-05-24 17:34:18 +00:00
|
|
|
pub fn is_null(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
Yaml::Null => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-24 18:16:28 +00:00
|
|
|
pub fn is_badvalue(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
Yaml::BadValue => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-30 14:39:50 +00:00
|
|
|
pub fn as_f64(&self) -> Option<f64> {
|
2015-05-24 17:34:18 +00:00
|
|
|
match *self {
|
2015-05-30 14:39:50 +00:00
|
|
|
Yaml::Real(ref v) => {
|
|
|
|
v.parse::<f64>().ok()
|
2015-05-24 17:34:18 +00:00
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
2016-08-08 02:25:30 +00:00
|
|
|
|
|
|
|
pub fn into_f64(self) -> Option<f64> {
|
|
|
|
match self {
|
|
|
|
Yaml::Real(v) => {
|
|
|
|
v.parse::<f64>().ok()
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
2016-02-28 00:30:13 +00:00
|
|
|
}
|
2015-05-24 18:16:28 +00:00
|
|
|
|
2016-02-28 00:30:13 +00:00
|
|
|
#[cfg_attr(feature="clippy", allow(should_implement_trait))]
|
|
|
|
impl Yaml {
|
|
|
|
// Not implementing FromStr because there is no possibility of Error.
|
|
|
|
// This function falls back to Yaml::String if nothing else matches.
|
2015-05-30 14:39:50 +00:00
|
|
|
pub fn from_str(v: &str) -> Yaml {
|
2016-02-07 21:52:20 +00:00
|
|
|
if v.starts_with("0x") {
|
2016-03-10 09:55:21 +00:00
|
|
|
let n = i64::from_str_radix(&v[2..], 16);
|
2016-02-07 21:52:20 +00:00
|
|
|
if n.is_ok() {
|
|
|
|
return Yaml::Integer(n.unwrap());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if v.starts_with("0o") {
|
2016-03-10 09:55:21 +00:00
|
|
|
let n = i64::from_str_radix(&v[2..], 8);
|
2016-02-07 21:52:20 +00:00
|
|
|
if n.is_ok() {
|
|
|
|
return Yaml::Integer(n.unwrap());
|
|
|
|
}
|
|
|
|
}
|
2016-02-28 00:30:13 +00:00
|
|
|
if v.starts_with('+') && v[1..].parse::<i64>().is_ok() {
|
|
|
|
return Yaml::Integer(v[1..].parse::<i64>().unwrap());
|
2016-02-07 22:21:05 +00:00
|
|
|
}
|
2015-05-30 14:39:50 +00:00
|
|
|
match v {
|
|
|
|
"~" | "null" => Yaml::Null,
|
|
|
|
"true" => Yaml::Boolean(true),
|
|
|
|
"false" => Yaml::Boolean(false),
|
|
|
|
_ if v.parse::<i64>().is_ok() => Yaml::Integer(v.parse::<i64>().unwrap()),
|
|
|
|
// try parsing as f64
|
2016-02-28 00:30:13 +00:00
|
|
|
_ if v.parse::<f64>().is_ok() => Yaml::Real(v.to_owned()),
|
|
|
|
_ => Yaml::String(v.to_owned())
|
2015-05-30 14:39:50 +00:00
|
|
|
}
|
2015-05-24 18:16:28 +00:00
|
|
|
}
|
2015-05-24 17:34:18 +00:00
|
|
|
}
|
|
|
|
|
2015-05-24 18:16:28 +00:00
|
|
|
static BAD_VALUE: Yaml = Yaml::BadValue;
|
|
|
|
impl<'a> Index<&'a str> for Yaml {
|
|
|
|
type Output = Yaml;
|
|
|
|
|
|
|
|
fn index(&self, idx: &'a str) -> &Yaml {
|
2016-02-28 00:30:13 +00:00
|
|
|
let key = Yaml::String(idx.to_owned());
|
2015-05-24 18:16:28 +00:00
|
|
|
match self.as_hash() {
|
|
|
|
Some(h) => h.get(&key).unwrap_or(&BAD_VALUE),
|
|
|
|
None => &BAD_VALUE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<usize> for Yaml {
|
|
|
|
type Output = Yaml;
|
|
|
|
|
|
|
|
fn index(&self, idx: usize) -> &Yaml {
|
|
|
|
match self.as_vec() {
|
|
|
|
Some(v) => v.get(idx).unwrap_or(&BAD_VALUE),
|
|
|
|
None => &BAD_VALUE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-08 21:31:36 +00:00
|
|
|
impl IntoIterator for Yaml {
|
|
|
|
type Item = Yaml;
|
|
|
|
type IntoIter = YamlIter;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
YamlIter {yaml: self, index: 0}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct YamlIter {
|
|
|
|
yaml: Yaml,
|
|
|
|
index: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for YamlIter {
|
|
|
|
type Item = Yaml;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Yaml> {
|
|
|
|
let result = self.yaml[self.index].clone();
|
|
|
|
self.index += 1;
|
|
|
|
Some(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-24 17:34:18 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2015-05-26 18:50:51 +00:00
|
|
|
use yaml::*;
|
2015-05-24 18:16:28 +00:00
|
|
|
#[test]
|
2015-05-24 17:34:18 +00:00
|
|
|
fn test_coerce() {
|
|
|
|
let s = "---
|
|
|
|
a: 1
|
|
|
|
b: 2.2
|
|
|
|
c: [1, 2]
|
|
|
|
";
|
2015-05-26 18:50:51 +00:00
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let doc = &out[0];
|
2015-05-30 14:39:50 +00:00
|
|
|
assert_eq!(doc["a"].as_i64().unwrap(), 1i64);
|
|
|
|
assert_eq!(doc["b"].as_f64().unwrap(), 2.2f64);
|
|
|
|
assert_eq!(doc["c"][1].as_i64().unwrap(), 2i64);
|
2015-05-26 18:50:51 +00:00
|
|
|
assert!(doc["d"][0].is_badvalue());
|
|
|
|
}
|
|
|
|
|
2016-05-25 05:19:36 +00:00
|
|
|
#[test]
|
|
|
|
fn test_empty_doc() {
|
|
|
|
let s: String = "".to_owned();
|
|
|
|
YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let s: String = "---".to_owned();
|
|
|
|
assert_eq!(YamlLoader::load_from_str(&s).unwrap()[0], Yaml::Null);
|
|
|
|
}
|
|
|
|
|
2015-05-26 18:50:51 +00:00
|
|
|
#[test]
|
|
|
|
fn test_parser() {
|
|
|
|
let s: String = "
|
|
|
|
# comment
|
|
|
|
a0 bb: val
|
|
|
|
a1:
|
|
|
|
b1: 4
|
|
|
|
b2: d
|
|
|
|
a2: 4 # i'm comment
|
|
|
|
a3: [1, 2, 3]
|
|
|
|
a4:
|
|
|
|
- - a1
|
|
|
|
- a2
|
|
|
|
- 2
|
|
|
|
a5: 'single_quoted'
|
|
|
|
a6: \"double_quoted\"
|
|
|
|
a7: 你好
|
2016-02-28 00:30:13 +00:00
|
|
|
".to_owned();
|
2015-05-26 18:50:51 +00:00
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let doc = &out[0];
|
|
|
|
assert_eq!(doc["a7"].as_str().unwrap(), "你好");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_multi_doc() {
|
2015-06-29 16:31:22 +00:00
|
|
|
let s =
|
2015-05-26 18:50:51 +00:00
|
|
|
"
|
|
|
|
'a scalar'
|
|
|
|
---
|
|
|
|
'a scalar'
|
|
|
|
---
|
|
|
|
'a scalar'
|
|
|
|
";
|
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
assert_eq!(out.len(), 3);
|
2015-05-24 17:34:18 +00:00
|
|
|
}
|
2015-05-26 18:50:51 +00:00
|
|
|
|
2015-12-16 07:10:02 +00:00
|
|
|
#[test]
|
|
|
|
fn test_anchor() {
|
|
|
|
let s =
|
|
|
|
"
|
|
|
|
a1: &DEFAULT
|
|
|
|
b1: 4
|
|
|
|
b2: d
|
|
|
|
a2: *DEFAULT
|
|
|
|
";
|
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let doc = &out[0];
|
|
|
|
assert_eq!(doc["a2"]["b1"].as_i64().unwrap(), 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bad_anchor() {
|
|
|
|
let s =
|
|
|
|
"
|
|
|
|
a1: &DEFAULT
|
|
|
|
b1: 4
|
|
|
|
b2: *DEFAULT
|
|
|
|
";
|
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let doc = &out[0];
|
|
|
|
assert_eq!(doc["a1"]["b2"], Yaml::BadValue);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-07-28 09:36:25 +00:00
|
|
|
#[test]
|
|
|
|
fn test_github_27() {
|
|
|
|
// https://github.com/chyh1990/yaml-rust/issues/27
|
|
|
|
let s = "&a";
|
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let doc = &out[0];
|
|
|
|
assert_eq!(doc.as_str().unwrap(), "");
|
|
|
|
}
|
2015-12-16 07:10:02 +00:00
|
|
|
|
2015-05-30 14:39:50 +00:00
|
|
|
#[test]
|
|
|
|
fn test_plain_datatype() {
|
|
|
|
let s =
|
|
|
|
"
|
|
|
|
- 'string'
|
|
|
|
- \"string\"
|
|
|
|
- string
|
|
|
|
- 123
|
|
|
|
- -321
|
|
|
|
- 1.23
|
|
|
|
- -1e4
|
|
|
|
- ~
|
|
|
|
- null
|
|
|
|
- true
|
|
|
|
- false
|
|
|
|
- !!str 0
|
|
|
|
- !!int 100
|
|
|
|
- !!float 2
|
|
|
|
- !!null ~
|
|
|
|
- !!bool true
|
|
|
|
- !!bool false
|
2016-02-07 21:52:20 +00:00
|
|
|
- 0xFF
|
2015-05-30 14:39:50 +00:00
|
|
|
# bad values
|
|
|
|
- !!int string
|
|
|
|
- !!float string
|
|
|
|
- !!bool null
|
|
|
|
- !!null val
|
2016-02-07 21:52:20 +00:00
|
|
|
- 0o77
|
|
|
|
- [ 0xF, 0xF ]
|
|
|
|
- +12345
|
|
|
|
- [ true, false ]
|
2015-05-30 14:39:50 +00:00
|
|
|
";
|
|
|
|
let out = YamlLoader::load_from_str(&s).unwrap();
|
|
|
|
let doc = &out[0];
|
|
|
|
|
|
|
|
assert_eq!(doc[0].as_str().unwrap(), "string");
|
|
|
|
assert_eq!(doc[1].as_str().unwrap(), "string");
|
|
|
|
assert_eq!(doc[2].as_str().unwrap(), "string");
|
|
|
|
assert_eq!(doc[3].as_i64().unwrap(), 123);
|
|
|
|
assert_eq!(doc[4].as_i64().unwrap(), -321);
|
|
|
|
assert_eq!(doc[5].as_f64().unwrap(), 1.23);
|
|
|
|
assert_eq!(doc[6].as_f64().unwrap(), -1e4);
|
|
|
|
assert!(doc[7].is_null());
|
|
|
|
assert!(doc[8].is_null());
|
|
|
|
assert_eq!(doc[9].as_bool().unwrap(), true);
|
|
|
|
assert_eq!(doc[10].as_bool().unwrap(), false);
|
|
|
|
assert_eq!(doc[11].as_str().unwrap(), "0");
|
|
|
|
assert_eq!(doc[12].as_i64().unwrap(), 100);
|
|
|
|
assert_eq!(doc[13].as_f64().unwrap(), 2.0);
|
|
|
|
assert!(doc[14].is_null());
|
|
|
|
assert_eq!(doc[15].as_bool().unwrap(), true);
|
|
|
|
assert_eq!(doc[16].as_bool().unwrap(), false);
|
2016-02-07 21:52:20 +00:00
|
|
|
assert_eq!(doc[17].as_i64().unwrap(), 255);
|
2015-05-30 14:39:50 +00:00
|
|
|
assert!(doc[18].is_badvalue());
|
|
|
|
assert!(doc[19].is_badvalue());
|
|
|
|
assert!(doc[20].is_badvalue());
|
2016-02-07 21:52:20 +00:00
|
|
|
assert!(doc[21].is_badvalue());
|
|
|
|
assert_eq!(doc[22].as_i64().unwrap(), 63);
|
|
|
|
assert_eq!(doc[23][0].as_i64().unwrap(), 15);
|
|
|
|
assert_eq!(doc[23][1].as_i64().unwrap(), 15);
|
|
|
|
assert_eq!(doc[24].as_i64().unwrap(), 12345);
|
|
|
|
assert!(doc[25][0].as_bool().unwrap());
|
|
|
|
assert!(!doc[25][1].as_bool().unwrap());
|
2015-05-30 14:39:50 +00:00
|
|
|
}
|
2016-06-21 19:50:27 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bad_hypen() {
|
|
|
|
// See: https://github.com/chyh1990/yaml-rust/issues/23
|
|
|
|
let s = "{-";
|
|
|
|
assert!(YamlLoader::load_from_str(&s).is_err());
|
|
|
|
}
|
2016-06-22 21:57:24 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bad_docstart() {
|
|
|
|
assert!(YamlLoader::load_from_str("---This used to cause an infinite loop").is_ok());
|
|
|
|
assert_eq!(YamlLoader::load_from_str("----"), Ok(vec![Yaml::String(String::from("----"))]));
|
|
|
|
assert_eq!(YamlLoader::load_from_str("--- #here goes a comment"), Ok(vec![Yaml::Null]));
|
2016-08-08 02:25:30 +00:00
|
|
|
assert_eq!(YamlLoader::load_from_str("---- #here goes a comment"), Ok(vec![Yaml::String(String::from("----"))]));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_plain_datatype_with_into_methods() {
|
|
|
|
let s =
|
|
|
|
"
|
|
|
|
- 'string'
|
|
|
|
- \"string\"
|
|
|
|
- string
|
|
|
|
- 123
|
|
|
|
- -321
|
|
|
|
- 1.23
|
|
|
|
- -1e4
|
|
|
|
- true
|
|
|
|
- false
|
|
|
|
- !!str 0
|
|
|
|
- !!int 100
|
|
|
|
- !!float 2
|
|
|
|
- !!bool true
|
|
|
|
- !!bool false
|
|
|
|
- 0xFF
|
|
|
|
- 0o77
|
|
|
|
- +12345
|
|
|
|
";
|
2016-08-08 21:31:36 +00:00
|
|
|
let mut out = YamlLoader::load_from_str(&s).unwrap().into_iter();
|
|
|
|
let mut doc = out.next().unwrap().into_iter();
|
2016-08-08 02:25:30 +00:00
|
|
|
|
2016-08-08 21:31:36 +00:00
|
|
|
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
|
|
|
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
|
|
|
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
|
|
|
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 123);
|
|
|
|
assert_eq!(doc.next().unwrap().into_i64().unwrap(), -321);
|
|
|
|
assert_eq!(doc.next().unwrap().into_f64().unwrap(), 1.23);
|
|
|
|
assert_eq!(doc.next().unwrap().into_f64().unwrap(), -1e4);
|
|
|
|
assert_eq!(doc.next().unwrap().into_bool().unwrap(), true);
|
|
|
|
assert_eq!(doc.next().unwrap().into_bool().unwrap(), false);
|
|
|
|
assert_eq!(doc.next().unwrap().into_string().unwrap(), "0");
|
|
|
|
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 100);
|
|
|
|
assert_eq!(doc.next().unwrap().into_f64().unwrap(), 2.0);
|
|
|
|
assert_eq!(doc.next().unwrap().into_bool().unwrap(), true);
|
|
|
|
assert_eq!(doc.next().unwrap().into_bool().unwrap(), false);
|
|
|
|
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 255);
|
|
|
|
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 63);
|
|
|
|
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 12345);
|
2016-06-22 21:57:24 +00:00
|
|
|
}
|
2015-05-24 17:34:18 +00:00
|
|
|
}
|