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");
|
||||
assert!(matches!(
|
||||
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]`.
|
||||
///
|
||||
/// This is the same as a `DeserializeError` with an additional variant to return any error yealded
|
||||
/// by the inner bytes iterator.
|
||||
#[derive(Debug)]
|
||||
pub enum DecodeError<E> {
|
||||
/// Attempted to decode an object from an iterator that yielded too many bytes.
|
||||
TooManyBytes,
|
||||
/// Invalid consensus encoding.
|
||||
Consensus(Error),
|
||||
Parse(ParseError),
|
||||
/// Data unconsumed error.
|
||||
Unconsumed,
|
||||
/// Other decoding error.
|
||||
Other(E),
|
||||
Other(E), // Yielded by the inner iterator.
|
||||
}
|
||||
|
||||
internals::impl_from_infallible!(DecodeError<E>);
|
||||
|
@ -68,9 +71,8 @@ impl<E: fmt::Debug> fmt::Display for DecodeError<E> {
|
|||
use DecodeError::*;
|
||||
|
||||
match *self {
|
||||
TooManyBytes =>
|
||||
write!(f, "attempted to decode object from an iterator that yielded too many bytes"),
|
||||
Consensus(ref e) => write_err!(f, "invalid consensus encoding"; e),
|
||||
Parse(ref e) => write_err!(f, "error parsing encoded object"; e),
|
||||
Unconsumed => write!(f, "data not consumed entirely when deserializing"),
|
||||
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::*;
|
||||
|
||||
match *self {
|
||||
TooManyBytes => None,
|
||||
Consensus(ref e) => Some(e),
|
||||
Parse(ref e) => Some(e),
|
||||
Unconsumed => None,
|
||||
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>> {
|
||||
let result = T::consensus_decode(&mut self);
|
||||
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(_), 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_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_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::{Deserializer, Serializer};
|
||||
|
||||
use super::{Decodable, Encodable, Error, ParseError};
|
||||
use super::{Decodable, Encodable, ParseError};
|
||||
use crate::consensus::{DecodeError, IterReader};
|
||||
|
||||
/// Hex-encoding strategy
|
||||
|
@ -387,10 +387,8 @@ where
|
|||
fn unify(self) -> E {
|
||||
match self {
|
||||
DecodeError::Other(error) => error,
|
||||
DecodeError::TooManyBytes => E::custom(format_args!("got more bytes than expected")),
|
||||
DecodeError::Consensus(Error::Parse(e)) => consensus_error_into_serde(e),
|
||||
DecodeError::Consensus(Error::Io(_)) =>
|
||||
unreachable!("iterator never returns I/O error"),
|
||||
DecodeError::Unconsumed => E::custom(format_args!("got more bytes than expected")),
|
||||
DecodeError::Parse(e) => consensus_error_into_serde(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,10 +400,8 @@ where
|
|||
fn into_de_error<DE: serde::de::Error>(self) -> DE {
|
||||
match self {
|
||||
DecodeError::Other(error) => error.into_de_error(),
|
||||
DecodeError::TooManyBytes => DE::custom(format_args!("got more bytes than expected")),
|
||||
DecodeError::Consensus(Error::Parse(e)) => consensus_error_into_serde(e),
|
||||
DecodeError::Consensus(Error::Io(_)) =>
|
||||
unreachable!("iterator never returns I/O error"),
|
||||
DecodeError::Unconsumed => DE::custom(format_args!("got more bytes than expected")),
|
||||
DecodeError::Parse(e) => consensus_error_into_serde(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue