#![expect(
clippy::renamed_function_params,
reason = "Implementation parameter names are clearer than generic trait names"
)]
#[cfg(test)]
mod container_tests;
pub(crate) mod format;
pub(crate) mod io;
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Error {
kind: ErrorKind,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum ErrorKind {
UnexpectedEnd,
InvalidMagic,
UnsupportedWireFormat(u16),
LengthOverflow,
TrailingBytes,
InvalidReserved,
SectionLengthMismatch,
}
impl Error {
pub(crate) const UNEXPECTED_END: Self = Self::new(ErrorKind::UnexpectedEnd);
pub(crate) const INVALID_MAGIC: Self = Self::new(ErrorKind::InvalidMagic);
pub(crate) const LENGTH_OVERFLOW: Self = Self::new(ErrorKind::LengthOverflow);
pub(crate) const TRAILING_BYTES: Self = Self::new(ErrorKind::TrailingBytes);
pub(crate) const INVALID_RESERVED: Self = Self::new(ErrorKind::InvalidReserved);
pub(crate) const SECTION_LENGTH_MISMATCH: Self = Self::new(ErrorKind::SectionLengthMismatch);
const fn new(kind: ErrorKind) -> Self {
Self { kind }
}
#[must_use]
pub const fn kind(self) -> ErrorKind {
self.kind
}
pub(crate) const fn unsupported_wire_format(version: u16) -> Self {
Self::new(ErrorKind::UnsupportedWireFormat(version))
}
}
impl core::fmt::Display for Error {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.kind {
ErrorKind::UnexpectedEnd => formatter.write_str("the input or output ended unexpectedly"),
ErrorKind::InvalidMagic => formatter.write_str("the container magic bytes are invalid"),
ErrorKind::UnsupportedWireFormat(version) => write!(formatter, "wire-format version {version} is unsupported"),
ErrorKind::LengthOverflow => formatter.write_str("a length cannot be represented"),
ErrorKind::TrailingBytes => formatter.write_str("the output contains unused trailing bytes"),
ErrorKind::InvalidReserved => formatter.write_str("a reserved field contains a nonzero value"),
ErrorKind::SectionLengthMismatch => formatter.write_str("a section payload differs from its declared length"),
}
}
}
impl core::fmt::Debug for Error {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(formatter, "Error({self})")
}
}
impl core::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_kind_exposes_stable_categories() {
let cases = [
(Error::UNEXPECTED_END, ErrorKind::UnexpectedEnd),
(Error::INVALID_MAGIC, ErrorKind::InvalidMagic),
(Error::unsupported_wire_format(7), ErrorKind::UnsupportedWireFormat(7)),
(Error::LENGTH_OVERFLOW, ErrorKind::LengthOverflow),
(Error::TRAILING_BYTES, ErrorKind::TrailingBytes),
(Error::INVALID_RESERVED, ErrorKind::InvalidReserved),
(Error::SECTION_LENGTH_MISMATCH, ErrorKind::SectionLengthMismatch),
];
for (error, kind) in cases {
assert_eq!(error.kind(), kind);
}
}
}