177 invalid encodings (#212)
* split out invalid encoding errors * detail breaking changes
This commit is contained in:
parent
45e70e297e
commit
c8f02e30aa
|
|
@ -3,6 +3,7 @@ name = "bincode"
|
|||
version = "0.8.1"
|
||||
authors = ["Ty Overby <ty@pre-alpha.com>", "Francesco Mazzoli <f@mazzo.li>", "David Tolnay <dtolnay@gmail.com>", "Daniel Griffen"]
|
||||
|
||||
# Adding ErrorKind::Invalid*Encoding is a breaking change
|
||||
# Adding ErrorKind::DeserializeAnyNotSupported is a breaking change
|
||||
publish = false
|
||||
|
||||
|
|
|
|||
|
|
@ -56,11 +56,9 @@ impl<'de, R: BincodeRead<'de>, E: ByteOrder, S: SizeLimit> Deserializer<R, S, E>
|
|||
}
|
||||
|
||||
fn read_string(&mut self) -> Result<String> {
|
||||
String::from_utf8(try!(self.read_vec())).map_err(|err|
|
||||
ErrorKind::InvalidEncoding{
|
||||
desc: "error while decoding utf8 string",
|
||||
detail: Some(format!("Deserialize error: {}", err))
|
||||
}.into())
|
||||
let vec = self.read_vec()?;
|
||||
String::from_utf8(vec).map_err(|e|
|
||||
ErrorKind::InvalidUtf8Encoding(e.utf8_error()).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,10 +94,7 @@ where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder {
|
|||
1 => visitor.visit_bool(true),
|
||||
0 => visitor.visit_bool(false),
|
||||
value => {
|
||||
Err(ErrorKind::InvalidEncoding{
|
||||
desc: "invalid u8 when decoding bool",
|
||||
detail: Some(format!("Expected 0 or 1, got {}", value))
|
||||
}.into())
|
||||
Err(ErrorKind::InvalidBoolEncoding(value).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -142,10 +137,7 @@ where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder {
|
|||
use std::str;
|
||||
|
||||
let error = || {
|
||||
ErrorKind::InvalidEncoding{
|
||||
desc: "invalid char encoding",
|
||||
detail: None,
|
||||
}.into()
|
||||
ErrorKind::InvalidCharEncoding.into()
|
||||
};
|
||||
|
||||
let mut buf = [0u8; 4];
|
||||
|
|
@ -255,10 +247,7 @@ where R: BincodeRead<'de>, S: SizeLimit, E: ByteOrder {
|
|||
match value {
|
||||
0 => visitor.visit_none(),
|
||||
1 => visitor.visit_some(&mut *self),
|
||||
_ => Err(ErrorKind::InvalidEncoding{
|
||||
desc: "invalid tag when decoding Option",
|
||||
detail: Some(format!("Expected 0 or 1, got {}", value))
|
||||
}.into()),
|
||||
v => Err(ErrorKind::InvalidTagEncoding(v as usize).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,10 +81,7 @@ impl <'storage> BincodeRead<'storage> for SliceReader<'storage> {
|
|||
|
||||
let string = match ::std::str::from_utf8(&self.slice[..length]) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(Box::new(ErrorKind::InvalidEncoding {
|
||||
desc: "string was not valid utf8",
|
||||
detail: None,
|
||||
})),
|
||||
Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()),
|
||||
};
|
||||
let r = visitor.visit_borrowed_str(string);
|
||||
self.slice = &self.slice[length..];
|
||||
|
|
@ -133,10 +130,7 @@ impl <R> BincodeRead<'static> for IoReader<R> where R: io::Read {
|
|||
|
||||
let string = match ::std::str::from_utf8(&self.temp_buffer[..length]) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(Box::new(::ErrorKind::InvalidEncoding {
|
||||
desc: "string was not valid utf8",
|
||||
detail: None,
|
||||
})),
|
||||
Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()),
|
||||
};
|
||||
|
||||
let r = visitor.visit_str(string);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
use std::io::{self, Write, Read};
|
||||
use std::{error, fmt, result};
|
||||
use std::str::Utf8Error;
|
||||
use ::{CountSize, SizeLimit};
|
||||
use byteorder::{ByteOrder};
|
||||
use std::error::Error as StdError;
|
||||
|
||||
pub use super::de::{
|
||||
Deserializer,
|
||||
|
|
@ -31,16 +33,16 @@ pub enum ErrorKind {
|
|||
/// If the error stems from the reader/writer that is being used
|
||||
/// during (de)serialization, that error will be stored and returned here.
|
||||
Io(io::Error),
|
||||
/// If the bytes in the reader are not decodable because of an invalid
|
||||
/// encoding, this error will be returned. This error is only possible
|
||||
/// if a stream is corrupted. A stream produced from `encode` or `encode_into`
|
||||
/// should **never** produce an InvalidEncoding error.
|
||||
InvalidEncoding {
|
||||
#[allow(missing_docs)]
|
||||
desc: &'static str,
|
||||
#[allow(missing_docs)]
|
||||
detail: Option<String>
|
||||
},
|
||||
/// Returned if the deserializer attempts to deserialize a string that is not valid utf8
|
||||
InvalidUtf8Encoding(Utf8Error),
|
||||
/// Returned if the deserializer attempts to deserialize a bool that was
|
||||
/// not encoded as either a 1 or a 0
|
||||
InvalidBoolEncoding(u8),
|
||||
/// Returned if the deserializer attempts to deserialize a char that is not in the correct format.
|
||||
InvalidCharEncoding,
|
||||
/// Returned if the deserializer attempts to deserialize the tag of an enum that is
|
||||
/// not in the expected ranges
|
||||
InvalidTagEncoding(usize),
|
||||
/// Serde has a deserialize_any method that lets the format hint to the
|
||||
/// object which route to take in deserializing.
|
||||
DeserializeAnyNotSupported,
|
||||
|
|
@ -53,11 +55,14 @@ pub enum ErrorKind {
|
|||
Custom(String)
|
||||
}
|
||||
|
||||
impl error::Error for ErrorKind {
|
||||
impl StdError for ErrorKind {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
ErrorKind::Io(ref err) => error::Error::description(err),
|
||||
ErrorKind::InvalidEncoding{desc, ..} => desc,
|
||||
ErrorKind::InvalidUtf8Encoding(_) => "string is not valid utf8",
|
||||
ErrorKind::InvalidBoolEncoding(_) => "invalid u8 while decoding bool",
|
||||
ErrorKind::InvalidCharEncoding => "char is not valid",
|
||||
ErrorKind::InvalidTagEncoding(_) => "tag for enum is not valid",
|
||||
ErrorKind::SequenceMustHaveLength => "bincode can't encode infinite sequences",
|
||||
ErrorKind::DeserializeAnyNotSupported => "bincode doesn't support serde::Deserializer::deserialize_any",
|
||||
ErrorKind::SizeLimit => "the size limit for decoding has been reached",
|
||||
|
|
@ -69,7 +74,10 @@ impl error::Error for ErrorKind {
|
|||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
ErrorKind::Io(ref err) => Some(err),
|
||||
ErrorKind::InvalidEncoding{..} => None,
|
||||
ErrorKind::InvalidUtf8Encoding(_) => None,
|
||||
ErrorKind::InvalidBoolEncoding(_) => None,
|
||||
ErrorKind::InvalidCharEncoding => None,
|
||||
ErrorKind::InvalidTagEncoding(_) => None,
|
||||
ErrorKind::SequenceMustHaveLength => None,
|
||||
ErrorKind::DeserializeAnyNotSupported => None,
|
||||
ErrorKind::SizeLimit => None,
|
||||
|
|
@ -89,10 +97,14 @@ impl fmt::Display for ErrorKind {
|
|||
match *self {
|
||||
ErrorKind::Io(ref ioerr) =>
|
||||
write!(fmt, "io error: {}", ioerr),
|
||||
ErrorKind::InvalidEncoding{desc, detail: None}=>
|
||||
write!(fmt, "invalid encoding: {}", desc),
|
||||
ErrorKind::InvalidEncoding{desc, detail: Some(ref detail)}=>
|
||||
write!(fmt, "invalid encoding: {} ({})", desc, detail),
|
||||
ErrorKind::InvalidUtf8Encoding(ref e) =>
|
||||
write!(fmt, "{}: {}", self.description(), e),
|
||||
ErrorKind::InvalidBoolEncoding(b) =>
|
||||
write!(fmt, "{}, expected 0 or 1, found {}", self.description(), b),
|
||||
ErrorKind::InvalidCharEncoding =>
|
||||
write!(fmt, "{}", self.description()),
|
||||
ErrorKind::InvalidTagEncoding(tag) =>
|
||||
write!(fmt, "{}, found {}", self.description(), tag),
|
||||
ErrorKind::SequenceMustHaveLength =>
|
||||
write!(fmt, "bincode can only encode sequences and maps that have a knowable size ahead of time."),
|
||||
ErrorKind::SizeLimit =>
|
||||
|
|
|
|||
|
|
@ -195,25 +195,32 @@ fn test_fixed_size_array() {
|
|||
|
||||
#[test]
|
||||
fn deserializing_errors() {
|
||||
fn isize_invalid_deserialize<T: Debug>(res: Result<T>) {
|
||||
match res.map_err(|e| *e) {
|
||||
Err(ErrorKind::InvalidEncoding{..}) => {},
|
||||
Err(ErrorKind::Custom(ref s)) if s.contains("invalid encoding") => {},
|
||||
Err(ErrorKind::Custom(ref s)) if s.contains("invalid value") => {},
|
||||
other => panic!("Expecting InvalidEncoding, got {:?}", other),
|
||||
}
|
||||
|
||||
match *deserialize_little::<bool>(&vec![0xA][..]).unwrap_err() {
|
||||
ErrorKind::InvalidBoolEncoding(0xA) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
match *deserialize_little::<String>(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]).unwrap_err() {
|
||||
ErrorKind::InvalidUtf8Encoding(_) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
isize_invalid_deserialize(deserialize_little::<bool>(&vec![0xA][..]));
|
||||
isize_invalid_deserialize(deserialize_little::<String>(&vec![1, 0, 0, 0, 0, 0, 0, 0, 0xFF][..]));
|
||||
// Out-of-bounds variant
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
enum Test {
|
||||
One,
|
||||
Two,
|
||||
};
|
||||
isize_invalid_deserialize(deserialize_little::<Test>(&vec![0, 0, 0, 5][..]));
|
||||
isize_invalid_deserialize(deserialize_little::<Option<u8>>(&vec![5, 0][..]));
|
||||
|
||||
match *deserialize_little::<Test>(&vec![0, 0, 0, 5][..]).unwrap_err() {
|
||||
// Error message comes from serde
|
||||
ErrorKind::Custom(_) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
match *deserialize_little::<Option<u8>>(&vec![5, 0][..]).unwrap_err() {
|
||||
ErrorKind::InvalidTagEncoding(_) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in New Issue