aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs191
1 files changed, 3 insertions, 188 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 7a00ca0..9a8da49 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,12 +5,13 @@ extern crate xml as xml_rs;
pub mod binary;
pub mod xml;
+mod builder;
+
+pub use builder::{Builder, BuilderError, BuilderResult};
-use byteorder::Error as ByteorderError;
use std::collections::HashMap;
use std::io::{Read, Seek, SeekFrom};
use std::io::Error as IoError;
-use std::string::FromUtf16Error;
#[derive(Clone, Debug, PartialEq)]
pub enum Plist {
@@ -59,21 +60,6 @@ impl From<IoError> for ParserError {
}
}
-impl From<ByteorderError> for ParserError {
- fn from(err: ByteorderError) -> ParserError {
- match err {
- ByteorderError::UnexpectedEOF => ParserError::UnexpectedEof,
- ByteorderError::Io(err) => ParserError::Io(err)
- }
- }
-}
-
-impl From<FromUtf16Error> for ParserError {
- fn from(_: FromUtf16Error) -> ParserError {
- ParserError::InvalidData
- }
-}
-
pub enum StreamingParser<R: Read+Seek> {
Xml(xml::StreamingParser<R>),
Binary(binary::StreamingParser<R>)
@@ -109,175 +95,4 @@ impl<R: Read+Seek> Iterator for StreamingParser<R> {
StreamingParser::Binary(ref mut parser) => parser.next()
}
}
-}
-
-pub type BuilderResult<T> = Result<T, BuilderError>;
-
-#[derive(Debug)]
-pub enum BuilderError {
- InvalidEvent,
- UnsupportedDictionaryKey,
- ParserError(ParserError)
-}
-
-impl From<ParserError> for BuilderError {
- fn from(err: ParserError) -> BuilderError {
- BuilderError::ParserError(err)
- }
-}
-
-pub struct Builder<T> {
- stream: T,
- token: Option<PlistEvent>,
-}
-
-impl<R: Read + Seek> Builder<StreamingParser<R>> {
- pub fn new(reader: R) -> Builder<StreamingParser<R>> {
- Builder::from_event_stream(StreamingParser::new(reader))
- }
-}
-
-impl<T:Iterator<Item=ParserResult<PlistEvent>>> Builder<T> {
- pub fn from_event_stream(stream: T) -> Builder<T> {
- Builder {
- stream: stream,
- token: None
- }
- }
-
- pub fn build(mut self) -> BuilderResult<Plist> {
- try!(self.bump());
- if let Some(PlistEvent::StartPlist) = self.token {
- try!(self.bump());
- }
-
- let plist = try!(self.build_value());
- try!(self.bump());
- match self.token {
- None => (),
- Some(PlistEvent::EndPlist) => try!(self.bump()),
- // The stream should have finished
- _ => return Err(BuilderError::InvalidEvent)
- };
- Ok(plist)
- }
-
- fn bump(&mut self) -> BuilderResult<()> {
- self.token = match self.stream.next() {
- Some(Ok(token)) => Some(token),
- Some(Err(err)) => return Err(BuilderError::ParserError(err)),
- None => None,
- };
- Ok(())
- }
-
- fn build_value(&mut self) -> BuilderResult<Plist> {
- match self.token.take() {
- Some(PlistEvent::StartPlist) => Err(BuilderError::InvalidEvent),
- Some(PlistEvent::EndPlist) => Err(BuilderError::InvalidEvent),
-
- Some(PlistEvent::StartArray(len)) => Ok(Plist::Array(try!(self.build_array(len)))),
- Some(PlistEvent::StartDictionary(len)) => Ok(Plist::Dictionary(try!(self.build_dict(len)))),
-
- 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(BuilderError::InvalidEvent),
- Some(PlistEvent::EndDictionary) => Err(BuilderError::InvalidEvent),
-
- // The stream should not have ended here
- None => Err(BuilderError::InvalidEvent)
- }
- }
-
- fn build_array(&mut self, len: Option<u64>) -> Result<Vec<Plist>, BuilderError> {
- let mut values = match len {
- Some(len) => Vec::with_capacity(len as usize),
- None => Vec::new()
- };
-
- loop {
- try!(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, len: Option<u64>) -> Result<HashMap<String, Plist>, BuilderError> {
- let mut values = match len {
- Some(len) => HashMap::with_capacity(len as usize),
- None => HashMap::new()
- };
-
- loop {
- try!(self.bump());
- match self.token.take() {
- Some(PlistEvent::EndDictionary) => return Ok(values),
- Some(PlistEvent::StringValue(s)) => {
- try!(self.bump());
- values.insert(s, try!(self.build_value()));
- },
- _ => {
- // Only string keys are supported in plists
- return Err(BuilderError::UnsupportedDictionaryKey)
- }
- }
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use std::collections::HashMap;
-
- use super::*;
-
- #[test]
- fn builder() {
- use super::PlistEvent::*;
-
- // Input
-
- let events = vec![
- StartPlist,
- StartDictionary(None),
- StringValue("Author".to_owned()),
- StringValue("William Shakespeare".to_owned()),
- StringValue("Lines".to_owned()),
- StartArray(None),
- StringValue("It is a tale told by an idiot,".to_owned()),
- StringValue("Full of sound and fury, signifying nothing.".to_owned()),
- EndArray,
- StringValue("Birthdate".to_owned()),
- IntegerValue(1564),
- StringValue("Height".to_owned()),
- RealValue(1.60),
- EndDictionary,
- EndPlist,
- ];
-
- let builder = Builder::from_event_stream(events.into_iter().map(|e| Ok(e)));
- let plist = builder.build();
-
- // Expected output
-
- 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.unwrap(), Plist::Dictionary(dict));
- }
} \ No newline at end of file