use core::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EncodeError {
BufferTooSmall {
needed: usize,
available: usize,
},
ValueOutOfRange {
message: &'static str,
},
MissingNonOptionalMember {
member_id: u32,
},
}
impl fmt::Display for EncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BufferTooSmall { needed, available } => write!(
f,
"encoder buffer too small: needed {needed} bytes, available {available}"
),
Self::ValueOutOfRange { message } => write!(f, "value out of range: {message}"),
Self::MissingNonOptionalMember { member_id } => write!(
f,
"mutable struct missing non-optional member: id={member_id}"
),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for EncodeError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecodeError {
UnexpectedEof {
needed: usize,
offset: usize,
},
InvalidUtf8 {
offset: usize,
},
InvalidBool {
value: u8,
offset: usize,
},
InvalidChar {
value: u32,
offset: usize,
},
LengthExceeded {
announced: usize,
remaining: usize,
offset: usize,
},
InvalidString {
offset: usize,
reason: &'static str,
},
InvalidEnum {
kind: &'static str,
value: u32,
},
UnknownMustUnderstandMember {
member_id: u32,
},
MissingNonOptionalMember {
member_id: u32,
},
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnexpectedEof { needed, offset } => {
write!(
f,
"unexpected EOF: needed {needed} more bytes at offset {offset}"
)
}
Self::InvalidUtf8 { offset } => write!(f, "invalid UTF-8 at offset {offset}"),
Self::InvalidBool { value, offset } => {
write!(f, "invalid bool byte 0x{value:02x} at offset {offset}")
}
Self::InvalidChar { value, offset } => {
write!(f, "invalid char codepoint U+{value:04X} at offset {offset}")
}
Self::LengthExceeded {
announced,
remaining,
offset,
} => write!(
f,
"length {announced} at offset {offset} exceeds remaining {remaining} bytes"
),
Self::InvalidString { offset, reason } => {
write!(f, "invalid CDR string at offset {offset}: {reason}")
}
Self::InvalidEnum { kind, value } => {
write!(f, "invalid {kind} discriminator: {value}")
}
Self::UnknownMustUnderstandMember { member_id } => {
write!(f, "unknown must_understand member id: {member_id}")
}
Self::MissingNonOptionalMember { member_id } => {
write!(f, "missing non-optional member id: {member_id}")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::format;
#[test]
fn encode_error_display_buffer_too_small() {
let e = EncodeError::BufferTooSmall {
needed: 8,
available: 4,
};
let s = format!("{e}");
assert!(s.contains("8"));
assert!(s.contains("4"));
}
#[test]
fn encode_error_display_value_out_of_range() {
let e = EncodeError::ValueOutOfRange {
message: "string too long",
};
assert!(format!("{e}").contains("string too long"));
}
#[test]
fn decode_error_display_unexpected_eof() {
let e = DecodeError::UnexpectedEof {
needed: 4,
offset: 12,
};
let s = format!("{e}");
assert!(s.contains("4"));
assert!(s.contains("12"));
}
#[test]
fn decode_error_display_invalid_utf8() {
let e = DecodeError::InvalidUtf8 { offset: 5 };
assert!(format!("{e}").contains("5"));
}
#[test]
fn decode_error_display_invalid_bool() {
let e = DecodeError::InvalidBool {
value: 0xff,
offset: 0,
};
assert!(format!("{e}").contains("ff"));
}
#[test]
fn decode_error_display_invalid_char() {
let e = DecodeError::InvalidChar {
value: 0xD800,
offset: 0,
};
assert!(format!("{e}").contains("D800"));
}
#[test]
fn decode_error_display_length_exceeded() {
let e = DecodeError::LengthExceeded {
announced: 100,
remaining: 4,
offset: 0,
};
let s = format!("{e}");
assert!(s.contains("100"));
assert!(s.contains("4"));
}
#[test]
fn errors_are_clone_eq() {
let e1 = EncodeError::ValueOutOfRange { message: "x" };
let e2 = e1.clone();
assert_eq!(e1, e2);
let d1 = DecodeError::UnexpectedEof {
needed: 1,
offset: 0,
};
assert_eq!(d1.clone(), d1);
}
}