aboutsummaryrefslogtreecommitdiffstats
path: root/src/reader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/reader.rs')
-rw-r--r--src/reader.rs136
1 files changed, 121 insertions, 15 deletions
diff --git a/src/reader.rs b/src/reader.rs
index 64e666e..6055b74 100644
--- a/src/reader.rs
+++ b/src/reader.rs
@@ -1,11 +1,13 @@
use rustc_serialize::base64::FromBase64;
+use std::collections::HashMap;
use std::io::Read;
use std::str::FromStr;
-use xml::reader::ParserConfig;
-use xml::reader::EventReader as XmlEventReader;
+use xml::reader::{EventReader, ParserConfig};
use xml::reader::events::XmlEvent;
-#[derive(PartialEq, Debug, Clone)]
+use super::Plist;
+
+#[derive(Clone, Debug, PartialEq)]
pub enum PlistEvent {
StartArray,
EndArray,
@@ -17,19 +19,19 @@ pub enum PlistEvent {
BooleanValue(bool),
DataValue(Vec<u8>),
DateValue(String),
- FloatValue(f64),
IntegerValue(i64),
+ RealValue(f64),
StringValue(String),
Error(())
}
-pub struct EventReader<R: Read> {
- xml_reader: XmlEventReader<R>
+pub struct StreamingParser<R: Read> {
+ xml_reader: EventReader<R>
}
-impl<R: Read> EventReader<R> {
- pub fn new(reader: R) -> EventReader<R> {
+impl<R: Read> StreamingParser<R> {
+ pub fn new(reader: R) -> StreamingParser<R> {
let config = ParserConfig {
trim_whitespace: false,
whitespace_to_characters: true,
@@ -38,8 +40,8 @@ impl<R: Read> EventReader<R> {
coalesce_characters: true,
};
- EventReader {
- xml_reader: XmlEventReader::with_config(reader, config)
+ StreamingParser {
+ xml_reader: EventReader::with_config(reader, config)
}
}
@@ -51,7 +53,7 @@ impl<R: Read> EventReader<R> {
}
}
-impl<R: Read> Iterator for EventReader<R> {
+impl<R: Read> Iterator for StreamingParser<R> {
type Item = PlistEvent;
fn next(&mut self) -> Option<PlistEvent> {
@@ -80,7 +82,7 @@ impl<R: Read> Iterator for EventReader<R> {
})),
"real" => return Some(self.read_string(|s| {
match FromStr::from_str(&s) {
- Ok(f) => PlistEvent::FloatValue(f),
+ Ok(f) => PlistEvent::RealValue(f),
Err(_) => PlistEvent::Error(())
}
})),
@@ -99,20 +101,103 @@ impl<R: Read> Iterator for EventReader<R> {
}
}
+pub struct Parser<R: Read> {
+ reader: StreamingParser<R>,
+ token: Option<PlistEvent>,
+}
+
+impl<R: Read> Parser<R> {
+ pub fn new(reader: R) -> Parser<R> {
+ Parser {
+ reader: StreamingParser::new(reader),
+ token: None
+ }
+ }
+
+ pub fn parse(mut self) -> Result<Plist, ()> {
+ self.bump();
+ let plist = try!(self.build_value());
+ self.bump();
+ match self.token {
+ None => (),
+ _ => return Err(())
+ };
+ Ok(plist)
+ }
+
+ fn bump(&mut self) {
+ self.token = self.reader.next();
+ }
+
+ fn build_value(&mut self) -> Result<Plist, ()> {
+ match self.token.take() {
+ Some(PlistEvent::StartArray) => Ok(Plist::Array(try!(self.build_array()))),
+ Some(PlistEvent::StartDictionary) => Ok(Plist::Dictionary(try!(self.build_dict()))),
+
+ Some(PlistEvent::BooleanValue(b)) => Ok(Plist::Boolean(b)),
+ Some(PlistEvent::DataValue(d)) => Ok(Plist::Data(d)),
+ Some(PlistEvent::DateValue(d)) => Ok(Plist::Date(d)),
+ Some(PlistEvent::IntegerValue(i)) => Ok(Plist::Integer(i)),
+ Some(PlistEvent::RealValue(f)) => Ok(Plist::Real(f)),
+ Some(PlistEvent::StringValue(s)) => Ok(Plist::String(s)),
+
+ Some(PlistEvent::EndArray) => Err(()),
+ Some(PlistEvent::EndDictionary) => Err(()),
+ Some(PlistEvent::DictionaryKey(_)) => Err(()),
+ Some(PlistEvent::Error(_)) => Err(()),
+ None => Err(())
+ }
+ }
+
+ fn build_array(&mut self) -> Result<Vec<Plist>, ()> {
+ let mut values = Vec::new();
+
+ loop {
+ self.bump();
+ if let Some(PlistEvent::EndArray) = self.token {
+ self.token.take();
+ return Ok(values);
+ }
+ values.push(try!(self.build_value()));
+ }
+ }
+
+ fn build_dict(&mut self) -> Result<HashMap<String, Plist>, ()> {
+ let mut values = HashMap::new();
+
+ loop {
+
+ self.bump();
+ match self.token.take() {
+ Some(PlistEvent::EndDictionary) => return Ok(values),
+ Some(PlistEvent::DictionaryKey(s)) => {
+ self.bump();
+ values.insert(s, try!(self.build_value()));
+ },
+ _ => {
+ return Err(())
+ }
+ }
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
use std::fs::File;
+ use std::collections::HashMap;
use std::path::Path;
use reader::*;
+ use super::super::Plist;
#[test]
- fn simple() {
+ fn streaming_parser() {
use reader::PlistEvent::*;
let reader = File::open(&Path::new("./tests/data/simple.plist")).unwrap();
- let event_reader = EventReader::new(reader);
- let events: Vec<PlistEvent> = event_reader.collect();
+ let streaming_parser = StreamingParser::new(reader);
+ let events: Vec<PlistEvent> = streaming_parser.collect();
let comparison = &[
StartDictionary,
@@ -125,9 +210,30 @@ mod tests {
EndArray,
DictionaryKey("Birthdate".to_owned()),
IntegerValue(1564),
+ DictionaryKey("Height".to_owned()),
+ RealValue(1.60),
EndDictionary
];
assert_eq!(events, comparison);
}
+
+ #[test]
+ fn parser() {
+ let reader = File::open(&Path::new("./tests/data/simple.plist")).unwrap();
+ let parser = Parser::new(reader);
+ let plist = parser.parse();
+
+ let mut lines = Vec::new();
+ lines.push(Plist::String("It is a tale told by an idiot,".to_owned()));
+ lines.push(Plist::String("Full of sound and fury, signifying nothing.".to_owned()));
+
+ let mut dict = HashMap::new();
+ dict.insert("Author".to_owned(), Plist::String("William Shakespeare".to_owned()));
+ dict.insert("Lines".to_owned(), Plist::Array(lines));
+ dict.insert("Birthdate".to_owned(), Plist::Integer(1564));
+ dict.insert("Height".to_owned(), Plist::Real(1.60));
+
+ assert_eq!(plist, Ok(Plist::Dictionary(dict)));
+ }
} \ No newline at end of file