use core::fmt;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
UnexpectedEof,
BufferFull,
VarintOverflow,
FrameTooLarge {
len: usize,
limit: usize,
},
InvalidLengthPrefix,
DelimiterNotFound,
InvalidEncoding,
BitOverflow,
EmptyDelimiter,
DelimiterInPayload,
ChecksumMismatch,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::UnexpectedEof => f.write_str("unexpected end of input"),
Error::BufferFull => f.write_str("output buffer is full"),
Error::VarintOverflow => f.write_str("varint encoded length exceeded the target width"),
Error::FrameTooLarge { len, limit } => {
write!(f, "frame length {len} exceeds configured limit {limit}")
}
Error::InvalidLengthPrefix => f.write_str("length prefix is structurally invalid"),
Error::DelimiterNotFound => f.write_str("delimiter not found in input"),
Error::InvalidEncoding => f.write_str("encoded data violates a structural invariant"),
Error::BitOverflow => f.write_str("bit width or value out of range"),
Error::EmptyDelimiter => f.write_str("delimiter must be non-empty"),
Error::DelimiterInPayload => f.write_str("payload contains the frame delimiter"),
Error::ChecksumMismatch => f.write_str("frame checksum mismatch"),
}
}
}
impl core::error::Error for Error {}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl From<Error> for std::io::Error {
fn from(err: Error) -> Self {
use std::io::ErrorKind;
let kind = match err {
Error::UnexpectedEof => ErrorKind::UnexpectedEof,
Error::BufferFull => ErrorKind::WriteZero,
Error::BitOverflow | Error::EmptyDelimiter | Error::DelimiterInPayload => {
ErrorKind::InvalidInput
}
_ => ErrorKind::InvalidData,
};
std::io::Error::new(kind, err)
}
}
pub type Result<T> = core::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_messages_are_distinct_and_non_empty() {
let all = [
Error::UnexpectedEof,
Error::BufferFull,
Error::VarintOverflow,
Error::FrameTooLarge { len: 9, limit: 4 },
Error::InvalidLengthPrefix,
Error::DelimiterNotFound,
Error::InvalidEncoding,
Error::BitOverflow,
Error::EmptyDelimiter,
Error::DelimiterInPayload,
Error::ChecksumMismatch,
];
let mut seen: [Option<String>; 11] = Default::default();
for (slot, err) in seen.iter_mut().zip(all) {
let text = err.to_string();
assert!(!text.is_empty());
*slot = Some(text);
}
for i in 0..seen.len() {
for j in (i + 1)..seen.len() {
assert_ne!(seen[i], seen[j]);
}
}
assert_eq!(
Error::FrameTooLarge { len: 9, limit: 4 }.to_string(),
"frame length 9 exceeds configured limit 4"
);
}
#[cfg(feature = "std")]
#[test]
fn io_error_kinds() {
use std::io::{self, ErrorKind};
let cases = [
(Error::UnexpectedEof, ErrorKind::UnexpectedEof),
(Error::BufferFull, ErrorKind::WriteZero),
(Error::BitOverflow, ErrorKind::InvalidInput),
(Error::EmptyDelimiter, ErrorKind::InvalidInput),
(Error::DelimiterInPayload, ErrorKind::InvalidInput),
(Error::VarintOverflow, ErrorKind::InvalidData),
(Error::InvalidEncoding, ErrorKind::InvalidData),
];
for (err, kind) in cases {
let io_err = io::Error::from(err);
assert_eq!(io_err.kind(), kind);
assert_eq!(
io_err.get_ref().and_then(|e| e.downcast_ref::<Error>()),
Some(&err)
);
}
}
#[test]
fn implements_core_error() {
fn takes_error(_: &dyn core::error::Error) {}
takes_error(&Error::BufferFull);
}
}