diff --git a/src/lib.rs b/src/lib.rs index b7315a9..befb969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ use rustc_serialize::Encodable; use rustc_serialize::Decodable; pub use writer::EncoderWriter; -pub use reader::DecoderReader; +pub use reader::{DecoderReader, DecodingResult, DecodingError}; mod writer; mod reader; @@ -32,7 +32,7 @@ pub fn encode(t: &T, size_limit: SizeLimit) -> IoResult> { } } -pub fn decode(b: Vec, size_limit: SizeLimit) -> IoResult { +pub fn decode(b: Vec, size_limit: SizeLimit) -> DecodingResult { decode_from(&mut MemReader::new(b), size_limit) } @@ -40,7 +40,7 @@ pub fn encode_into(t: &T, w: &mut W, size_limit: SizeLi t.encode(&mut writer::EncoderWriter::new(w, size_limit)) } -pub fn decode_from(r: &mut R, size_limit: SizeLimit) -> IoResult { +pub fn decode_from(r: &mut R, size_limit: SizeLimit) -> DecodingResult { Decodable::decode(&mut reader::DecoderReader::new(r, size_limit)) } diff --git a/src/reader.rs b/src/reader.rs index 9ff116a..c665860 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -1,10 +1,46 @@ -use std::io::{Buffer, Reader, IoError, IoResult, OtherIoError}; -use std::error::Error; +use std::io::{Buffer, Reader, IoError}; +use std::error::{Error, FromError}; use rustc_serialize::Decoder; use super::SizeLimit; +#[derive(PartialEq, Clone, Show)] +pub struct InvalidBytes { + desc: &'static str, + detail: Option, +} + +#[derive(PartialEq, Clone, Show)] +pub enum DecodingError { + IoError(IoError), + InvalidBytes(InvalidBytes), +} + +pub type DecodingResult = Result; + +impl Error for DecodingError { + fn description(&self) -> &str { + match *self { + DecodingError::IoError(ref err) => err.description(), + DecodingError::InvalidBytes(ref ib) => ib.desc + } + } + + fn detail(&self) -> Option { + match *self { + DecodingError::IoError(ref err) => err.detail(), + DecodingError::InvalidBytes(ref ib) => ib.detail.clone() + } + } +} + +impl FromError for DecodingError { + fn from_error(err: IoError) -> DecodingError { + DecodingError::IoError(err) + } +} + pub struct DecoderReader<'a, R: 'a> { reader: &'a mut R, size_limit: SizeLimit @@ -20,161 +56,171 @@ impl<'a, R: Reader+Buffer> DecoderReader<'a, R> { } impl<'a, R: Reader+Buffer> Decoder for DecoderReader<'a, R> { - type Error = IoError; + type Error = DecodingError; - fn read_nil(&mut self) -> IoResult<()> { + fn read_nil(&mut self) -> DecodingResult<()> { Ok(()) } - fn read_uint(&mut self) -> IoResult { - self.read_u64().map(|x| x as uint) + fn read_uint(&mut self) -> DecodingResult { + Ok(try!(self.read_u64().map(|x| x as uint))) } - fn read_u64(&mut self) -> IoResult { - self.reader.read_be_u64() + fn read_u64(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_u64())) } - fn read_u32(&mut self) -> IoResult { - self.reader.read_be_u32() + fn read_u32(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_u32())) } - fn read_u16(&mut self) -> IoResult { - self.reader.read_be_u16() + fn read_u16(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_u16())) } - fn read_u8(&mut self) -> IoResult { - self.reader.read_u8() + fn read_u8(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_u8())) } - fn read_int(&mut self) -> IoResult { - self.read_i64().map(|x| x as int) + fn read_int(&mut self) -> DecodingResult { + Ok(try!(self.read_i64().map(|x| x as int))) } - fn read_i64(&mut self) -> IoResult { - self.reader.read_be_i64() + fn read_i64(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_i64())) } - fn read_i32(&mut self) -> IoResult { - self.reader.read_be_i32() + fn read_i32(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_i32())) } - fn read_i16(&mut self) -> IoResult { - self.reader.read_be_i16() + fn read_i16(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_i16())) } - fn read_i8(&mut self) -> IoResult { - self.reader.read_i8() + fn read_i8(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_i8())) } - fn read_bool(&mut self) -> IoResult { - match try!(self.reader.read_i8()) { + fn read_bool(&mut self) -> DecodingResult { + let x = try!(self.reader.read_u8()); + match x { 1 => Ok(true), - _ => Ok(false) + 0 => Ok(false), + _ => Err(DecodingError::InvalidBytes(InvalidBytes{ + desc: "invalid u8 when decoding bool", + detail: Some(format!("Expected 0 or 1, got {}", x)) + })), } } - fn read_f64(&mut self) -> IoResult { - self.reader.read_be_f64() + fn read_f64(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_f64())) } - fn read_f32(&mut self) -> IoResult { - self.reader.read_be_f32() + fn read_f32(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_be_f32())) } - fn read_char(&mut self) -> IoResult { - self.reader.read_char() + fn read_char(&mut self) -> DecodingResult { + Ok(try!(self.reader.read_char())) } - fn read_str(&mut self) -> IoResult { + fn read_str(&mut self) -> DecodingResult { let len = try!(self.read_uint()); let vector = try!(self.reader.read_exact(len)); - String::from_utf8(vector).map_err(|e| IoError { - kind: OtherIoError, - desc: "invalid utf-8", - detail: e.detail() - }) + match String::from_utf8(vector) { + Ok(s) => Ok(s), + Err(err) => Err(DecodingError::InvalidBytes(InvalidBytes { + desc: "error while decoding utf8 string", + detail: Some(format!("Decoding error: {}", err)) + })), + } } - fn read_enum(&mut self, _: &str, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_enum(&mut self, _: &str, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_enum_variant(&mut self, names: &[&str], mut f: F) -> IoResult where - F: FnMut(&mut DecoderReader<'a, R>, uint) -> IoResult { + fn read_enum_variant(&mut self, names: &[&str], mut f: F) -> DecodingResult where + F: FnMut(&mut DecoderReader<'a, R>, uint) -> DecodingResult { let id = try!(self.read_u32()); let id = id as uint; if id >= names.len() { - Err(IoError { - kind: OtherIoError, + Err(DecodingError::InvalidBytes(InvalidBytes { desc: "out of bounds tag when reading enum variant", detail: Some(format!("Expected tag < {}, got {}", names.len(), id)) - }) + })) } else { f(self, id) } } - fn read_enum_variant_arg(&mut self, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_enum_variant_arg(&mut self, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> IoResult where - F: FnMut(&mut DecoderReader<'a, R>, uint) -> IoResult { + fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> DecodingResult where + F: FnMut(&mut DecoderReader<'a, R>, uint) -> DecodingResult { self.read_enum_variant(names, f) } fn read_enum_struct_variant_field(&mut self, _: &str, f_idx: uint, f: F) - -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { self.read_enum_variant_arg(f_idx, f) } - fn read_struct(&mut self, _: &str, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_struct(&mut self, _: &str, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } fn read_struct_field(&mut self, _: &str, _: uint, f: F) - -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_tuple(&mut self, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_tuple(&mut self, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_tuple_arg(&mut self, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_tuple_arg(&mut self, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_tuple_struct(&mut self, _: &str, len: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_tuple_struct(&mut self, _: &str, len: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { self.read_tuple(len, f) } - fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_tuple_struct_arg(&mut self, a_idx: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { self.read_tuple_arg(a_idx, f) } - fn read_option(&mut self, mut f: F) -> IoResult where - F: FnMut(&mut DecoderReader<'a, R>, bool) -> IoResult { - match try!(self.reader.read_u8()) { + fn read_option(&mut self, mut f: F) -> DecodingResult where + F: FnMut(&mut DecoderReader<'a, R>, bool) -> DecodingResult { + let x = try!(self.reader.read_u8()); + match x { 1 => f(self, true), - _ => f(self, false) + 0 => f(self, false), + _ => Err(DecodingError::InvalidBytes(InvalidBytes { + desc: "invalid tag when decoding Option", + detail: Some(format!("Expected 0 or 1, got {}", x)) + })), } } - fn read_seq(&mut self, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>, uint) -> IoResult { + fn read_seq(&mut self, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>, uint) -> DecodingResult { let len = try!(self.read_uint()); f(self, len) } - fn read_seq_elt(&mut self, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_seq_elt(&mut self, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_map(&mut self, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>, uint) -> IoResult { + fn read_map(&mut self, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>, uint) -> DecodingResult { let len = try!(self.read_uint()); f(self, len) } - fn read_map_elt_key(&mut self, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_map_elt_key(&mut self, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn read_map_elt_val(&mut self, _: uint, f: F) -> IoResult where - F: FnOnce(&mut DecoderReader<'a, R>) -> IoResult { + fn read_map_elt_val(&mut self, _: uint, f: F) -> DecodingResult where + F: FnOnce(&mut DecoderReader<'a, R>) -> DecodingResult { f(self) } - fn error(&mut self, err: &str) -> IoError { - IoError { - kind: OtherIoError, - desc: "failure decoding or something, I don't know", - detail: Some(err.to_string()) - } + fn error(&mut self, err: &str) -> DecodingError { + DecodingError::InvalidBytes(InvalidBytes { + desc: "user-induced error", + detail: Some(err.to_string()), + }) } } diff --git a/src/test.rs b/src/test.rs index ff41263..4f85023 100644 --- a/src/test.rs +++ b/src/test.rs @@ -13,6 +13,8 @@ use rustc_serialize::{ use super::{ encode, decode, + DecodingError, + DecodingResult }; use super::SizeLimit::Infinite; @@ -49,7 +51,6 @@ fn test_numbers() { fn test_string() { the_same("".to_string()); the_same("a".to_string()); - the_same("ƒoo".to_string()); } #[test] @@ -166,12 +167,25 @@ fn unicode() { the_same("aåååååååa".to_string()); } -#[test] -fn bad_unicode() { - // This is a malformed message that contains bad utf8. - // The decoding should return Err but not panic. - let encoded = vec![0,0,0,0, 0,0,0,2, 97, 195]; - let decoded: Result = decode(encoded, Infinite); - - assert!(decoded.is_err()); +#[cfg(test)] +fn is_invalid_bytes(res: DecodingResult) { + match res { + Ok(_) => panic!("Expecting error"), + Err(DecodingError::IoError(_)) => panic!("Expecting InvalidBytes"), + Err(DecodingError::InvalidBytes(_)) => {}, + } +} + +#[test] +fn decoding_errors() { + is_invalid_bytes(decode::(vec![0xA], Infinite)); + is_invalid_bytes(decode::(vec![0, 0, 0, 0, 0, 0, 0, 1, 0xFF], Infinite)); + // Out-of-bounds variant + #[derive(RustcEncodable, RustcDecodable)] + enum Test { + One, + Two, + }; + is_invalid_bytes(decode::(vec![0, 0, 0, 5], Infinite)); + is_invalid_bytes(decode::>(vec![5, 0], Infinite)); }