pub type ParsingResult<T> = Result<T, ParsingError>;
impl std::error::Error for ParsingError {}
#[derive(Debug)]
pub struct ParsingError {
pub offset: usize,
pub ty: ParsingErrorType,
}
#[derive(Debug)]
pub enum ParsingErrorType {
NotEnoughData {
tried_to_parse: String,
expected_size: usize,
remaining_bytes: usize,
},
TooMuchData { remaining_bytes: usize },
InvalidPointer { value: u64 },
WrongPointer { name: String, expected_offset: usize, actual_offset: usize },
InvalidSize { value: u32 },
WrongSize { expected_size: usize, actual_size: usize },
InvalidDiscriminant { value: u32 },
}
impl ParsingError {
pub fn not_enough_data(
offset: usize,
tried_to_parse: String,
expected_size: usize,
remaining_bytes: usize,
) -> ParsingError {
ParsingError {
offset,
ty: ParsingErrorType::NotEnoughData { tried_to_parse, expected_size, remaining_bytes },
}
}
pub fn too_much_data(offset: usize, remaining_bytes: usize) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::TooMuchData { remaining_bytes } }
}
pub fn invalid_pointer(offset: usize, value: u64) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::InvalidPointer { value } }
}
pub fn invalid_size(offset: usize, value: u32) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::InvalidSize { value } }
}
pub fn wrong_pointer(
offset: usize,
name: String,
expected_offset: usize,
actual_offset: usize,
) -> ParsingError {
ParsingError {
offset,
ty: ParsingErrorType::WrongPointer { name, expected_offset, actual_offset },
}
}
pub fn wrong_size(offset: usize, expected_size: usize, actual_size: usize) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::WrongSize { expected_size, actual_size } }
}
pub fn invalid_discriminant(offset: usize, value: u32) -> ParsingError {
ParsingError { offset, ty: ParsingErrorType::InvalidDiscriminant { value } }
}
}
impl std::fmt::Display for ParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"An error occurred at byte {} when parsing the message. Details:\n",
self.offset
)?;
match &self.ty {
ParsingErrorType::NotEnoughData { tried_to_parse, expected_size, remaining_bytes } => {
write!(
f,
"Tried to parse {tried_to_parse} ({expected_size} bytes), \
but only {remaining_bytes} bytes remained."
)
}
ParsingErrorType::TooMuchData { remaining_bytes } => {
write!(f, "There were {remaining_bytes} bytes remaining after parsing finished.")
}
ParsingErrorType::InvalidPointer { value } => {
if *value < 8 {
write!(f, "Pointer value {value} is less than its own size (8).")
} else if *value % 8 != 0 {
write!(
f,
"Pointer value {value} points to unaligned data \
(because it is not divisible by 8)."
)
} else {
write!(f, "Pointer value {value} doesn't fit into 64 bits.")
}
}
ParsingErrorType::InvalidSize { value } => {
if *value < 8 {
write!(f, "Size value {value} is less than the size of a header(8).")
} else if *value % 8 != 0 {
write!(f, "Size value {value} is not divisible by 8.")
} else {
write!(f, "Pointer value {value} doesn't fit into 32 bits.")
}
}
ParsingErrorType::WrongPointer { name, expected_offset, actual_offset } => {
write!(
f,
"Expected to find nested field {name} at {expected_offset} bytes from the \
beginning of the struct, but it was actually at {actual_offset} bytes."
)
}
ParsingErrorType::WrongSize { expected_size, actual_size } => {
write!(
f,
"Struct/Array claimed to have {expected_size} bytes, \
but we parsed {actual_size} bytes."
)
}
ParsingErrorType::InvalidDiscriminant { value } => {
write!(f, "Enum/Union value {value} is not a valid discriminant for its type.")
}
}
}
}