Remove the IO error from DecodeError
The `DecodeError` (badly named) consensus decodes an object from an iterator that implements `Read`. The `Read` impl never returns a real IO error, we use the `io::Error` to temporarily wrap the error returned by the inner iterator and unwrap it in `IterReader::decode`. As such there is no reason for the `DecodeError` to hold an `encode::Error`, it can hold an `encode::ParseError`. The value of this change is easily seen in the removal of calls to `unreachable`.
This commit is contained in:
parent
713196be0d
commit
bbffa3db43
|
@ -1164,7 +1164,7 @@ mod tests {
|
||||||
hex.push_str("abcdef");
|
hex.push_str("abcdef");
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
deserialize_hex::<Transaction>(&hex).unwrap_err(),
|
deserialize_hex::<Transaction>(&hex).unwrap_err(),
|
||||||
FromHexError::Decode(DecodeError::TooManyBytes)
|
FromHexError::Decode(DecodeError::Unconsumed)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,14 +51,17 @@ impl From<ParseError> for DeserializeError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error when consensus decoding from an `[IterReader]`.
|
/// Error when consensus decoding from an `[IterReader]`.
|
||||||
|
///
|
||||||
|
/// This is the same as a `DeserializeError` with an additional variant to return any error yealded
|
||||||
|
/// by the inner bytes iterator.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DecodeError<E> {
|
pub enum DecodeError<E> {
|
||||||
/// Attempted to decode an object from an iterator that yielded too many bytes.
|
|
||||||
TooManyBytes,
|
|
||||||
/// Invalid consensus encoding.
|
/// Invalid consensus encoding.
|
||||||
Consensus(Error),
|
Parse(ParseError),
|
||||||
|
/// Data unconsumed error.
|
||||||
|
Unconsumed,
|
||||||
/// Other decoding error.
|
/// Other decoding error.
|
||||||
Other(E),
|
Other(E), // Yielded by the inner iterator.
|
||||||
}
|
}
|
||||||
|
|
||||||
internals::impl_from_infallible!(DecodeError<E>);
|
internals::impl_from_infallible!(DecodeError<E>);
|
||||||
|
@ -68,9 +71,8 @@ impl<E: fmt::Debug> fmt::Display for DecodeError<E> {
|
||||||
use DecodeError::*;
|
use DecodeError::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
TooManyBytes =>
|
Parse(ref e) => write_err!(f, "error parsing encoded object"; e),
|
||||||
write!(f, "attempted to decode object from an iterator that yielded too many bytes"),
|
Unconsumed => write!(f, "data not consumed entirely when deserializing"),
|
||||||
Consensus(ref e) => write_err!(f, "invalid consensus encoding"; e),
|
|
||||||
Other(ref other) => write!(f, "other decoding error: {:?}", other),
|
Other(ref other) => write!(f, "other decoding error: {:?}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,8 +84,8 @@ impl<E: fmt::Debug + std::error::Error + 'static> std::error::Error for DecodeEr
|
||||||
use DecodeError::*;
|
use DecodeError::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
TooManyBytes => None,
|
Parse(ref e) => Some(e),
|
||||||
Consensus(ref e) => Some(e),
|
Unconsumed => None,
|
||||||
Other(ref e) => Some(e),
|
Other(ref e) => Some(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,12 +38,12 @@ impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
|
||||||
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
|
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
|
||||||
let result = T::consensus_decode(&mut self);
|
let result = T::consensus_decode(&mut self);
|
||||||
match (result, self.error) {
|
match (result, self.error) {
|
||||||
(Ok(_), None) if self.iterator.next().is_some() => Err(DecodeError::TooManyBytes),
|
(Ok(_), None) if self.iterator.next().is_some() => Err(DecodeError::Unconsumed),
|
||||||
(Ok(value), None) => Ok(value),
|
(Ok(value), None) => Ok(value),
|
||||||
(Ok(_), Some(error)) => panic!("{} silently ate the error: {:?}", core::any::type_name::<T>(), error),
|
(Ok(_), Some(error)) => panic!("{} silently ate the error: {:?}", core::any::type_name::<T>(), error),
|
||||||
|
|
||||||
(Err(consensus::encode::Error::Io(io_error)), Some(de_error)) if io_error.kind() == io::ErrorKind::Other && io_error.get_ref().is_none() => Err(DecodeError::Other(de_error)),
|
(Err(consensus::encode::Error::Io(io_error)), Some(de_error)) if io_error.kind() == io::ErrorKind::Other && io_error.get_ref().is_none() => Err(DecodeError::Other(de_error)),
|
||||||
(Err(consensus_error), None) => Err(DecodeError::Consensus(consensus_error)),
|
(Err(consensus::encode::Error::Parse(parse_error)), None) => Err(DecodeError::Parse(parse_error)),
|
||||||
(Err(consensus::encode::Error::Io(io_error)), de_error) => panic!("unexpected IO error {:?} returned from {}::consensus_decode(), deserialization error: {:?}", io_error, core::any::type_name::<T>(), de_error),
|
(Err(consensus::encode::Error::Io(io_error)), de_error) => panic!("unexpected IO error {:?} returned from {}::consensus_decode(), deserialization error: {:?}", io_error, core::any::type_name::<T>(), de_error),
|
||||||
(Err(consensus_error), Some(de_error)) => panic!("{} should've returned `Other` IO error because of deserialization error {:?} but it returned consensus error {:?} instead", core::any::type_name::<T>(), de_error, consensus_error),
|
(Err(consensus_error), Some(de_error)) => panic!("{} should've returned `Other` IO error because of deserialization error {:?} but it returned consensus error {:?} instead", core::any::type_name::<T>(), de_error, consensus_error),
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use serde::de::{SeqAccess, Unexpected, Visitor};
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
use serde::{Deserializer, Serializer};
|
use serde::{Deserializer, Serializer};
|
||||||
|
|
||||||
use super::{Decodable, Encodable, Error, ParseError};
|
use super::{Decodable, Encodable, ParseError};
|
||||||
use crate::consensus::{DecodeError, IterReader};
|
use crate::consensus::{DecodeError, IterReader};
|
||||||
|
|
||||||
/// Hex-encoding strategy
|
/// Hex-encoding strategy
|
||||||
|
@ -387,10 +387,8 @@ where
|
||||||
fn unify(self) -> E {
|
fn unify(self) -> E {
|
||||||
match self {
|
match self {
|
||||||
DecodeError::Other(error) => error,
|
DecodeError::Other(error) => error,
|
||||||
DecodeError::TooManyBytes => E::custom(format_args!("got more bytes than expected")),
|
DecodeError::Unconsumed => E::custom(format_args!("got more bytes than expected")),
|
||||||
DecodeError::Consensus(Error::Parse(e)) => consensus_error_into_serde(e),
|
DecodeError::Parse(e) => consensus_error_into_serde(e),
|
||||||
DecodeError::Consensus(Error::Io(_)) =>
|
|
||||||
unreachable!("iterator never returns I/O error"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,10 +400,8 @@ where
|
||||||
fn into_de_error<DE: serde::de::Error>(self) -> DE {
|
fn into_de_error<DE: serde::de::Error>(self) -> DE {
|
||||||
match self {
|
match self {
|
||||||
DecodeError::Other(error) => error.into_de_error(),
|
DecodeError::Other(error) => error.into_de_error(),
|
||||||
DecodeError::TooManyBytes => DE::custom(format_args!("got more bytes than expected")),
|
DecodeError::Unconsumed => DE::custom(format_args!("got more bytes than expected")),
|
||||||
DecodeError::Consensus(Error::Parse(e)) => consensus_error_into_serde(e),
|
DecodeError::Parse(e) => consensus_error_into_serde(e),
|
||||||
DecodeError::Consensus(Error::Io(_)) =>
|
|
||||||
unreachable!("iterator never returns I/O error"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue