Add alias deserialize support

This commit is contained in:
Yuheng Chen 2015-12-16 15:10:02 +08:00
parent de8e94ab34
commit 071d338e0e
2 changed files with 55 additions and 15 deletions

View file

@ -2,6 +2,7 @@ language: rust
rust: rust:
- 1.0.0 - 1.0.0
- 1.1.0 - 1.1.0
- 1.5.0
- nightly - nightly
env: env:
global: global:

View file

@ -53,8 +53,10 @@ pub type Hash = BTreeMap<Yaml, Yaml>;
pub struct YamlLoader { pub struct YamlLoader {
docs: Vec<Yaml>, docs: Vec<Yaml>,
// states // states
doc_stack: Vec<Yaml>, // (current node, anchor_id) tuple
doc_stack: Vec<(Yaml, usize)>,
key_stack: Vec<Yaml>, key_stack: Vec<Yaml>,
anchor_map: BTreeMap<usize, Yaml>,
} }
impl EventReceiver for YamlLoader { impl EventReceiver for YamlLoader {
@ -68,19 +70,19 @@ impl EventReceiver for YamlLoader {
match self.doc_stack.len() { match self.doc_stack.len() {
// empty document // empty document
0 => self.docs.push(Yaml::BadValue), 0 => self.docs.push(Yaml::BadValue),
1 => self.docs.push(self.doc_stack.pop().unwrap()), 1 => self.docs.push(self.doc_stack.pop().unwrap().0),
_ => unreachable!() _ => unreachable!()
} }
}, },
Event::SequenceStart(_) => { Event::SequenceStart(aid) => {
self.doc_stack.push(Yaml::Array(Vec::new())); self.doc_stack.push((Yaml::Array(Vec::new()), aid));
}, },
Event::SequenceEnd => { Event::SequenceEnd => {
let node = self.doc_stack.pop().unwrap(); let node = self.doc_stack.pop().unwrap();
self.insert_new_node(node); self.insert_new_node(node);
}, },
Event::MappingStart(_) => { Event::MappingStart(aid) => {
self.doc_stack.push(Yaml::Hash(Hash::new())); self.doc_stack.push((Yaml::Hash(Hash::new()), aid));
self.key_stack.push(Yaml::BadValue); self.key_stack.push(Yaml::BadValue);
}, },
Event::MappingEnd => { Event::MappingEnd => {
@ -88,7 +90,7 @@ impl EventReceiver for YamlLoader {
let node = self.doc_stack.pop().unwrap(); let node = self.doc_stack.pop().unwrap();
self.insert_new_node(node); self.insert_new_node(node);
}, },
Event::Scalar(ref v, style, _, ref tag) => { Event::Scalar(ref v, style, aid, ref tag) => {
let node = if style != TScalarStyle::Plain { let node = if style != TScalarStyle::Plain {
Yaml::String(v.clone()) Yaml::String(v.clone())
} else { } else {
@ -133,11 +135,14 @@ impl EventReceiver for YamlLoader {
} }
}; };
self.insert_new_node(node); self.insert_new_node((node, aid));
}, },
Event::Alias(id) => { Event::Alias(id) => {
// XXX(chenyh): how to handle alias? let n = match self.anchor_map.get(&id) {
self.insert_new_node(Yaml::Alias(id)); Some(v) => v.clone(),
None => Yaml::BadValue,
};
self.insert_new_node((n, 0));
} }
_ => { /* ignore */ } _ => { /* ignore */ }
} }
@ -146,21 +151,25 @@ impl EventReceiver for YamlLoader {
} }
impl YamlLoader { impl YamlLoader {
fn insert_new_node(&mut self, node: Yaml) { 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());
}
if !self.doc_stack.is_empty() { if !self.doc_stack.is_empty() {
let parent = self.doc_stack.last_mut().unwrap(); let parent = self.doc_stack.last_mut().unwrap();
match *parent { match *parent {
Yaml::Array(ref mut v) => v.push(node), (Yaml::Array(ref mut v), _) => v.push(node.0),
Yaml::Hash(ref mut h) => { (Yaml::Hash(ref mut h), _) => {
let mut cur_key = self.key_stack.last_mut().unwrap(); let mut cur_key = self.key_stack.last_mut().unwrap();
// current node is a key // current node is a key
if cur_key.is_badvalue() { if cur_key.is_badvalue() {
*cur_key = node; *cur_key = node.0;
// current node is a value // current node is a value
} else { } else {
let mut newkey = Yaml::BadValue; let mut newkey = Yaml::BadValue;
mem::swap(&mut newkey, cur_key); mem::swap(&mut newkey, cur_key);
h.insert(newkey, node); h.insert(newkey, node.0);
} }
}, },
_ => unreachable!(), _ => unreachable!(),
@ -175,6 +184,7 @@ impl YamlLoader {
docs: Vec::new(), docs: Vec::new(),
doc_stack: Vec::new(), doc_stack: Vec::new(),
key_stack: Vec::new(), key_stack: Vec::new(),
anchor_map: BTreeMap::new(),
}; };
let mut parser = Parser::new(source.chars()); let mut parser = Parser::new(source.chars());
try!(parser.load(&mut loader, true)); try!(parser.load(&mut loader, true));
@ -327,6 +337,35 @@ a7: 你好
assert_eq!(out.len(), 3); assert_eq!(out.len(), 3);
} }
#[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);
}
#[test] #[test]
fn test_plain_datatype() { fn test_plain_datatype() {
let s = let s =