diff options
| author | Edward Barnard | 2015-08-28 21:17:14 +0700 |
|---|---|---|
| committer | Edward Barnard | 2015-08-28 21:17:14 +0700 |
| commit | 3e41485288049b1d7a9be60b84b4d78dcd400f39 (patch) | |
| tree | 66692c381e6e9f4337868ac8ca43c06dcb909e75 /src/lib.rs | |
| parent | 1ef9fbdc9377a831eb4abccaa4b18d89b5fd560d (diff) | |
| download | rust-plist-3e41485288049b1d7a9be60b84b4d78dcd400f39.tar.bz2 | |
Expand folder structure
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 191 |
1 files changed, 3 insertions, 188 deletions
@@ -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 |
