use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BufferTooShort {
pub need: usize,
pub have: usize,
pub what: &'static str,
}
impl fmt::Display for BufferTooShort {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"buffer too short: need {} bytes, have {} (while parsing {})",
self.need, self.have, self.what
)
}
}
impl core::error::Error for BufferTooShort {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutputBufferTooSmall {
pub need: usize,
pub have: usize,
}
impl fmt::Display for OutputBufferTooSmall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"output buffer too small: need {}, have {}",
self.need, self.have
)
}
}
impl core::error::Error for OutputBufferTooSmall {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FieldOverflow {
pub field: &'static str,
pub value: u64,
pub max: u64,
}
impl fmt::Display for FieldOverflow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} = {} exceeds the field maximum {}",
self.field, self.value, self.max
)
}
}
impl core::error::Error for FieldOverflow {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CrcMismatch {
pub what: &'static str,
pub computed: u32,
pub expected: u32,
}
impl fmt::Display for CrcMismatch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} CRC-32 mismatch: computed {:#010x}, expected {:#010x}",
self.what, self.computed, self.expected
)
}
}
impl core::error::Error for CrcMismatch {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidSync {
pub what: &'static str,
pub expected: u32,
pub found: u32,
}
impl fmt::Display for InvalidSync {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"invalid {}: expected {:#x}, got {:#x}",
self.what, self.expected, self.found
)
}
}
impl core::error::Error for InvalidSync {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ReservedBits {
pub field: &'static str,
pub expected: u64,
pub found: u64,
}
impl fmt::Display for ReservedBits {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"reserved field {} must be {:#x}, found {:#x}",
self.field, self.expected, self.found
)
}
}
impl core::error::Error for ReservedBits {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidValue {
pub field: &'static str,
pub value: u64,
pub reason: &'static str,
}
impl fmt::Display for InvalidValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"field {} value {} invalid: {}",
self.field, self.value, self.reason
)
}
}
impl core::error::Error for InvalidValue {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidField {
pub field: &'static str,
pub reason: &'static str,
}
impl fmt::Display for InvalidField {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid field {}: {}", self.field, self.reason)
}
}
impl core::error::Error for InvalidField {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UnsupportedVersion {
pub what: &'static str,
pub found: u8,
}
impl fmt::Display for UnsupportedVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unsupported {} version {}", self.what, self.found)
}
}
impl core::error::Error for UnsupportedVersion {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LengthMismatch {
pub what: &'static str,
pub declared: usize,
pub actual: usize,
}
impl fmt::Display for LengthMismatch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"length mismatch for {}: declared {}, actual {}",
self.what, self.declared, self.actual
)
}
}
impl core::error::Error for LengthMismatch {}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use alloc::string::ToString;
#[test]
fn display_messages() {
assert_eq!(
BufferTooShort {
need: 4,
have: 1,
what: "PAT"
}
.to_string(),
"buffer too short: need 4 bytes, have 1 (while parsing PAT)"
);
assert_eq!(
OutputBufferTooSmall { need: 4, have: 1 }.to_string(),
"output buffer too small: need 4, have 1"
);
assert_eq!(
FieldOverflow {
field: "section_length",
value: 5000,
max: 4095
}
.to_string(),
"section_length = 5000 exceeds the field maximum 4095"
);
assert_eq!(
CrcMismatch {
what: "PSM",
computed: 0xAB,
expected: 0xCD
}
.to_string(),
"PSM CRC-32 mismatch: computed 0x000000ab, expected 0x000000cd"
);
assert_eq!(
InvalidSync {
what: "TS sync byte",
expected: 0x47,
found: 0
}
.to_string(),
"invalid TS sync byte: expected 0x47, got 0x0"
);
assert_eq!(
ReservedBits {
field: "reserved",
expected: 0x7,
found: 0x2
}
.to_string(),
"reserved field reserved must be 0x7, found 0x2"
);
assert_eq!(
InvalidValue {
field: "version",
value: 9,
reason: "out of range"
}
.to_string(),
"field version value 9 invalid: out of range"
);
assert_eq!(
InvalidField {
field: "pts",
reason: "missing"
}
.to_string(),
"invalid field pts: missing"
);
assert_eq!(
UnsupportedVersion {
what: "RTP",
found: 1
}
.to_string(),
"unsupported RTP version 1"
);
assert_eq!(
LengthMismatch {
what: "APDU",
declared: 9,
actual: 7
}
.to_string(),
"length mismatch for APDU: declared 9, actual 7"
);
}
#[test]
fn equality_distinguishes_every_field() {
let a = CrcMismatch {
what: "PSM",
computed: 1,
expected: 2,
};
assert_eq!(a, a);
assert_ne!(a, CrcMismatch { what: "SNDU", ..a });
assert_ne!(a, CrcMismatch { computed: 3, ..a });
assert_ne!(a, CrcMismatch { expected: 3, ..a });
let b = LengthMismatch {
what: "x",
declared: 1,
actual: 2,
};
assert_ne!(b, LengthMismatch { declared: 2, ..b });
assert_ne!(b, LengthMismatch { actual: 1, ..b });
}
#[test]
fn len_reexports_are_the_same_types() {
let e: BufferTooShort = crate::len::need_in(&[], 1, "x").unwrap_err();
assert_eq!(
e,
BufferTooShort {
need: 1,
have: 0,
what: "x"
}
);
let o: OutputBufferTooSmall = crate::len::need_out(&[], 1).unwrap_err();
assert_eq!(o, OutputBufferTooSmall { need: 1, have: 0 });
let _: FieldOverflow = crate::len::fit_bits(256, 8, "f").unwrap_err();
}
#[test]
fn kinds_are_core_errors() {
fn is_error<E: core::error::Error + Copy + Send + Sync + 'static>() {}
is_error::<BufferTooShort>();
is_error::<CrcMismatch>();
is_error::<InvalidSync>();
is_error::<ReservedBits>();
is_error::<InvalidValue>();
is_error::<InvalidField>();
is_error::<UnsupportedVersion>();
is_error::<LengthMismatch>();
}
}