aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
authorEdward Barnard2015-08-11 11:40:49 +0100
committerEdward Barnard2015-08-11 11:40:49 +0100
commit7fad4d1b24faee94ca5313d5411ae292f46846ff (patch)
tree3561e537c89686c10d749631e3fde0fccf9b32ce /src/lib.rs
parente1889668d9e077392d9172691d7530c7b2de5abf (diff)
downloadrust-plist-7fad4d1b24faee94ca5313d5411ae292f46846ff.tar.bz2
Improved errors
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs124
1 files changed, 95 insertions, 29 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 1613e53..2d0bc79 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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