rgbds_obj/
assertion.rs

1use crate::util::{read_str, read_u32le, read_u8};
2use crate::RpnExpr;
3use std::convert::TryInto;
4use std::fmt::{self, Display, Formatter};
5use std::io::{self, Read};
6
7/// A link-time assertion.
8/// Functions mostly like a [`Patch`][crate::Patch].
9#[derive(Debug)]
10pub struct Assertion {
11    source_file_id: u32,
12    line_no: u32,
13    offset: u32,
14    pc_section_id: u32,
15    pc_offset: u32,
16    err_type: AssertionType,
17    expr: RpnExpr,
18    message: Vec<u8>,
19}
20impl Assertion {
21    pub(crate) fn read_from(mut input: impl Read) -> Result<Self, io::Error> {
22        let source_file_id = read_u32le(&mut input)?;
23        let line_no = read_u32le(&mut input)?;
24        let offset = read_u32le(&mut input)?;
25        let pc_section_id = read_u32le(&mut input)?;
26        let pc_offset = read_u32le(&mut input)?;
27        let err_type = AssertionType::try_from(read_u8(&mut input)?)?;
28
29        let expr_size = read_u32le(&mut input)?.try_into().unwrap();
30        let mut expr = vec![0; expr_size];
31        input.read_exact(&mut expr)?;
32        let expr = RpnExpr::from_bytes(expr);
33        let message = read_str(input)?;
34
35        Ok(Self {
36            source_file_id,
37            line_no,
38            offset,
39            pc_section_id,
40            pc_offset,
41            err_type,
42            expr,
43            message,
44        })
45    }
46
47    /// Where the assertion was defined.
48    /// That is, the [file stack node][crate::Node] ID, and the line number.
49    pub fn source(&self) -> (u32, u32) {
50        (self.source_file_id, self.line_no)
51    }
52
53    /// The offset within the [section][crate::Section]'s data where the assertion's expression
54    /// shall be computed.
55    ///
56    /// This doesn't serve much purpose, since assertions only compute an expression, and don't
57    /// patch the data.
58    /// It should be equal to the [PC offset][Self::pc_offset].
59    ///
60    /// [PC offset]: #method.pc_offset
61    pub fn offset(&self) -> u32 {
62        self.offset
63    }
64
65    /// The assertion's error type (warning, error, fatal).
66    pub fn err_type(&self) -> AssertionType {
67        self.err_type
68    }
69
70    /// The ID of the expression's PC section. See [`pc_offset`][Self::pc_offset] for more info.
71    pub fn pc_section_id(&self) -> u32 {
72        self.pc_section_id
73    }
74
75    /// The expression's PC offset.
76    ///
77    /// This is separate from the [offset][Self::offset], probably as legacy due to assertions
78    /// inheriting a lot from [patches][crate::Patch].
79    pub fn pc_offset(&self) -> u32 {
80        self.pc_offset
81    }
82
83    /// The assertion's RPN expression.
84    pub fn expr(&self) -> &RpnExpr {
85        &self.expr
86    }
87
88    /// The assertion's message.
89    /// As with all text pulled from object files, this is not guaranteed to be valid UTF-8.
90    pub fn message(&self) -> &[u8] {
91        &self.message
92    }
93}
94
95/// An assertion's error type.
96#[derive(Debug, Clone, Copy)]
97pub enum AssertionType {
98    /// The assertion should produce a warning, but not fail linking.
99    Warning,
100    /// The assertion should produce an error, and cause the linker to exit unsuccessfully.
101    Error,
102    /// The assertion should produce an error, and abort linking immediately.
103    Fatal,
104}
105impl AssertionType {
106    fn try_from(byte: u8) -> Result<Self, io::Error> {
107        use AssertionType::*;
108
109        Ok(match byte {
110            0 => Warning,
111            1 => Error,
112            2 => Fatal,
113            _ => {
114                return Err(io::Error::new(
115                    io::ErrorKind::InvalidData,
116                    "Invalid assertion type",
117                ))
118            }
119        })
120    }
121
122    /// The assertion error type's name.
123    pub fn name(&self) -> &'static str {
124        use AssertionType::*;
125
126        match self {
127            Warning => "warning",
128            Error => "error",
129            Fatal => "fatal",
130        }
131    }
132}
133impl Display for AssertionType {
134    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
135        write!(fmt, "{}", self.name())
136    }
137}