diff options
| author | Edward Barnard | 2015-08-11 11:40:49 +0100 |
|---|---|---|
| committer | Edward Barnard | 2015-08-11 11:40:49 +0100 |
| commit | 7fad4d1b24faee94ca5313d5411ae292f46846ff (patch) | |
| tree | 3561e537c89686c10d749631e3fde0fccf9b32ce /src/lib.rs | |
| parent | e1889668d9e077392d9172691d7530c7b2de5abf (diff) | |
| download | rust-plist-7fad4d1b24faee94ca5313d5411ae292f46846ff.tar.bz2 | |
Improved errors
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 124 |
1 files changed, 95 insertions, 29 deletions
@@ -7,8 +7,10 @@ extern crate xml as xml_rs; pub mod binary; pub mod xml; +use byteorder::Error as ByteorderError; use std::collections::HashMap; -use std::io::{Read, Seek}; +use std::io::{Read, Seek, SeekFrom}; +use std::io::Error as IoError; #[derive(Clone, Debug, PartialEq)] pub enum Plist { @@ -22,7 +24,7 @@ pub enum Plist { String(String) } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, PartialEq)] pub enum PlistEvent { StartArray, EndArray, @@ -37,7 +39,39 @@ pub enum PlistEvent { RealValue(f64), StringValue(String), - Error(()) + Error(ParserError) +} + +type ParserResult<T> = Result<T, ParserError>; + +#[derive(Debug)] +pub enum ParserError { + InvalidData, + UnexpectedEof, + UnsupportedType, + Io(IoError) +} + +// No two errors are the same - this is a bit annoying though +impl PartialEq for ParserError { + fn eq(&self, other: &ParserError) -> bool { + false + } +} + +impl From<IoError> for ParserError { + fn from(io_error: IoError) -> ParserError { + ParserError::Io(io_error) + } +} + +impl From<ByteorderError> for ParserError { + fn from(err: ByteorderError) -> ParserError { + match err { + ByteorderError::UnexpectedEOF => ParserError::UnexpectedEof, + ByteorderError::Io(err) => ParserError::Io(err) + } + } } pub enum StreamingParser<R: Read+Seek> { @@ -46,8 +80,23 @@ pub enum StreamingParser<R: Read+Seek> { } impl<R: Read+Seek> StreamingParser<R> { - pub fn new() -> StreamingParser<R> { - panic!() + pub fn new(mut reader: R) -> StreamingParser<R> { + match StreamingParser::is_binary(&mut reader) { + Ok(true) => StreamingParser::Binary(binary::StreamingParser::new(reader)), + Ok(false) | Err(_) => StreamingParser::Xml(xml::StreamingParser::new(reader)) + } + } + + fn is_binary(reader: &mut R) -> Result<bool, IoError> { + try!(reader.seek(SeekFrom::Start(0))); + let mut magic = [0; 8]; + try!(reader.read(&mut magic)); + + Ok(if &magic == b"bplist00" { + true + } else { + false + }) } } @@ -62,41 +111,57 @@ impl<R: Read+Seek> Iterator for StreamingParser<R> { } } -pub struct Parser<T> { - reader: T, +pub type BuilderResult<T> = Result<T, BuilderError>; + +#[derive(Debug, PartialEq)] +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> Parser<StreamingParser<R>> { - pub fn new(reader: R) -> Parser<StreamingParser<R>> { - Parser::from_event_stream(StreamingParser::Xml(xml::StreamingParser::new(reader))) +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=PlistEvent>> Parser<T> { - pub fn from_event_stream(stream: T) -> Parser<T> { - Parser { - reader: stream, +impl<T:Iterator<Item=PlistEvent>> Builder<T> { + pub fn from_event_stream(stream: T) -> Builder<T> { + Builder { + stream: stream, token: None } } - pub fn parse(mut self) -> Result<Plist, ()> { + pub fn build(mut self) -> BuilderResult<Plist> { self.bump(); let plist = try!(self.build_value()); self.bump(); match self.token { None => (), - _ => return Err(()) + // The stream should have finished + _ => return Err(BuilderError::InvalidEvent) }; Ok(plist) } fn bump(&mut self) { - self.token = self.reader.next(); + self.token = self.stream.next(); } - fn build_value(&mut self) -> Result<Plist, ()> { + fn build_value(&mut self) -> BuilderResult<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()))), @@ -108,14 +173,15 @@ impl<T:Iterator<Item=PlistEvent>> Parser<T> { 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::Error(_)) => Err(()), - None => Err(()) + Some(PlistEvent::EndArray) => Err(BuilderError::InvalidEvent), + Some(PlistEvent::EndDictionary) => Err(BuilderError::InvalidEvent), + Some(PlistEvent::Error(_)) => Err(BuilderError::InvalidEvent), + // The stream should not have ended here + None => Err(BuilderError::InvalidEvent) } } - fn build_array(&mut self) -> Result<Vec<Plist>, ()> { + fn build_array(&mut self) -> Result<Vec<Plist>, BuilderError> { let mut values = Vec::new(); loop { @@ -128,7 +194,7 @@ impl<T:Iterator<Item=PlistEvent>> Parser<T> { } } - fn build_dict(&mut self) -> Result<HashMap<String, Plist>, ()> { + fn build_dict(&mut self) -> Result<HashMap<String, Plist>, BuilderError> { let mut values = HashMap::new(); loop { @@ -142,7 +208,7 @@ impl<T:Iterator<Item=PlistEvent>> Parser<T> { }, _ => { // Only string keys are supported in plists - return Err(()) + return Err(BuilderError::UnsupportedDictionaryKey) } } } @@ -156,12 +222,12 @@ mod tests { use super::*; #[test] - fn parser() { + fn builder() { use super::PlistEvent::*; // Input - let events = &[ + let events = vec![ StartDictionary, StringValue("Author".to_owned()), StringValue("William Shakespeare".to_owned()), @@ -177,8 +243,8 @@ mod tests { EndDictionary ]; - let parser = Parser::from_event_stream(events.into_iter().cloned()); - let plist = parser.parse(); + let builder = Builder::from_event_stream(events.into_iter()); + let plist = builder.build(); // Expected output |
