use crate::util::{read_str, read_u32le, read_u8};
use crate::RpnExpr;
use std::convert::TryInto;
use std::fmt::{self, Display, Formatter};
use std::io::{self, Read};
#[derive(Debug)]
pub struct Assertion {
source_file_id: u32,
line_no: u32,
offset: u32,
pc_section_id: u32,
pc_offset: u32,
err_type: AssertionType,
expr: RpnExpr,
message: Vec<u8>,
}
impl Assertion {
pub(crate) fn read_from(mut input: impl Read) -> Result<Self, io::Error> {
let source_file_id = read_u32le(&mut input)?;
let line_no = read_u32le(&mut input)?;
let offset = read_u32le(&mut input)?;
let pc_section_id = read_u32le(&mut input)?;
let pc_offset = read_u32le(&mut input)?;
let err_type = AssertionType::try_from(read_u8(&mut input)?)?;
let expr_size = read_u32le(&mut input)?.try_into().unwrap();
let mut expr = vec![0; expr_size];
input.read_exact(&mut expr)?;
let expr = RpnExpr::from_bytes(expr);
let message = read_str(input)?;
Ok(Self {
source_file_id,
line_no,
offset,
pc_section_id,
pc_offset,
err_type,
expr,
message,
})
}
pub fn source(&self) -> (u32, u32) {
(self.source_file_id, self.line_no)
}
pub fn offset(&self) -> u32 {
self.offset
}
pub fn err_type(&self) -> AssertionType {
self.err_type
}
pub fn pc_section_id(&self) -> u32 {
self.pc_section_id
}
pub fn pc_offset(&self) -> u32 {
self.pc_offset
}
pub fn expr(&self) -> &RpnExpr {
&self.expr
}
pub fn message(&self) -> &[u8] {
&self.message
}
}
#[derive(Debug, Clone, Copy)]
pub enum AssertionType {
Warning,
Error,
Fatal,
}
impl AssertionType {
fn try_from(byte: u8) -> Result<Self, io::Error> {
use AssertionType::*;
Ok(match byte {
0 => Warning,
1 => Error,
2 => Fatal,
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Invalid assertion type",
))
}
})
}
pub fn name(&self) -> &'static str {
use AssertionType::*;
match self {
Warning => "warning",
Error => "error",
Fatal => "fatal",
}
}
}
impl Display for AssertionType {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", self.name())
}
}