aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Barnard2015-08-04 17:24:37 +0100
committerEdward Barnard2015-08-04 17:24:37 +0100
commit094994360a7eb81eb545fccfe73e80765be71fd3 (patch)
treef37e86ce5e475a87598ba65ed27af6b6e55f5f77
parentda761e65e2f7b74afd2bdf1e07b19e038d990df6 (diff)
downloadrust-plist-094994360a7eb81eb545fccfe73e80765be71fd3.tar.bz2
More parsing
-rw-r--r--Cargo.toml3
-rw-r--r--src/lib.rs19
-rw-r--r--src/reader.rs136
-rw-r--r--tests/data/simple.plist2
4 files changed, 143 insertions, 17 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 809c32d..916c6da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,10 @@
[package]
name = "plist"
-version = "0.0.1"
+version = "0.0.2"
authors = ["Ed Barnard <eabarnard@gmail.com>"]
description = "A rusty plist parser. Very much a work in progress."
license = "MIT"
+repository = "https://github.com/ebarnard/rust-plist"
[dependencies]
rustc-serialize = "0.3.15"
diff --git a/src/lib.rs b/src/lib.rs
index 87aca11..9641d6b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,21 @@
extern crate rustc_serialize;
extern crate xml;
-pub mod reader; \ No newline at end of file
+mod reader;
+
+pub use reader::{Parser, StreamingParser, PlistEvent};
+
+use std::collections::HashMap;
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Plist {
+ Array(Vec<Plist>),
+ Dictionary(HashMap<String, Plist>),
+ Boolean(bool),
+ Data(Vec<u8>),
+ Date(String),
+ Real(f64),
+ Integer(i64),
+ String(String)
+}
+
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
diff --git a/tests/data/simple.plist b/tests/data/simple.plist
index c48e224..7fb0208 100644
--- a/tests/data/simple.plist
+++ b/tests/data/simple.plist
@@ -11,5 +11,7 @@
</array>
<key>Birthdate</key>
<integer>1564</integer>
+ <key>Height</key>
+ <real>1.60</real>
</dict>
</plist> \ No newline at end of file