Skip to main content

iree_embedded/
status.rs

1//! Mapping IREE's `iree_status_t` to a Rust `Result`.
2//!
3//! A status is a tagged pointer: the low 5 bits hold the code, and the OK
4//! status is the all-zero (null) value. A non-OK status may own a heap message,
5//! so we always free it after reading the code to avoid leaks.
6
7use iree_embedded_sys as sys;
8
9const CODE_MASK: usize = 0x1F;
10
11/// A coarse classification of an IREE failure, mapped from the raw status code.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum StatusCode {
14    /// The operation was aborted.
15    Aborted,
16    /// An allocation could not be satisfied (the arena is too small).
17    OutOfMemory,
18    /// A requested entity (function or symbol) was not found.
19    NotFound,
20    /// An argument was invalid.
21    InvalidArgument,
22    /// The operation is not implemented for this configuration.
23    Unimplemented,
24    /// An internal runtime error.
25    Internal,
26    /// A status code this crate does not classify.
27    Unknown,
28}
29
30const MSG_CAP: usize = 192;
31
32/// An IREE failure: a classified [`StatusCode`], the raw code, and the
33/// formatted status message (source location and annotations).
34#[derive(Clone, Copy)]
35pub struct Error {
36    code: StatusCode,
37    raw: u32,
38    msg: [u8; MSG_CAP],
39    msg_len: usize,
40}
41
42impl Error {
43    /// The classified status code.
44    pub fn code(&self) -> StatusCode {
45        self.code
46    }
47
48    /// The raw IREE status code (the low 5 bits of the status).
49    pub fn raw_code(&self) -> u32 {
50        self.raw
51    }
52
53    /// The formatted IREE status message (source location + annotations), if any.
54    pub fn message(&self) -> &str {
55        core::str::from_utf8(&self.msg[..self.msg_len]).unwrap_or("<non-utf8>")
56    }
57}
58
59impl core::fmt::Debug for Error {
60    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61        write!(
62            f,
63            "Error({:?}, raw={}, {})",
64            self.code,
65            self.raw,
66            self.message()
67        )
68    }
69}
70
71/// The result type returned by fallible operations in this crate.
72pub type Result<T> = core::result::Result<T, Error>;
73
74/// Consume an `iree_status_t`: `Ok` for the OK (null) status, otherwise map the
75/// code and free the status so any message buffer is released.
76pub(crate) fn check(status: sys::iree_status_t) -> Result<()> {
77    if status.is_null() {
78        return Ok(());
79    }
80    let code = (status as usize & CODE_MASK) as u32;
81    let mut msg = [0u8; MSG_CAP];
82    let mut len: sys::iree_host_size_t = 0;
83    // SAFETY: format into our buffer, then free the status (we own it).
84    unsafe {
85        sys::iree_status_format(status, msg.len(), msg.as_mut_ptr() as *mut _, &mut len);
86        sys::iree_status_free(status);
87    }
88    Err(Error {
89        code: map(code),
90        raw: code,
91        msg,
92        msg_len: (len as usize).min(MSG_CAP),
93    })
94}
95
96fn map(code: u32) -> StatusCode {
97    use StatusCode::*;
98    match code {
99        sys::IREE_STATUS_ABORTED => Aborted,
100        sys::IREE_STATUS_RESOURCE_EXHAUSTED => OutOfMemory,
101        sys::IREE_STATUS_NOT_FOUND => NotFound,
102        sys::IREE_STATUS_INVALID_ARGUMENT => InvalidArgument,
103        sys::IREE_STATUS_UNIMPLEMENTED => Unimplemented,
104        sys::IREE_STATUS_INTERNAL => Internal,
105        _ => Unknown,
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    /// Build a code-only status (no heap message): the code in the low bits.
114    fn status_of(code: u32) -> sys::iree_status_t {
115        code as usize as sys::iree_status_t
116    }
117
118    #[test]
119    fn ok_status_is_ok() {
120        assert!(check(core::ptr::null_mut()).is_ok());
121    }
122
123    #[test]
124    fn aborted_maps_to_error() {
125        let st = status_of(sys::IREE_STATUS_ABORTED);
126        assert_eq!(check(st).unwrap_err().code(), StatusCode::Aborted);
127    }
128
129    #[test]
130    fn resource_exhausted_maps_to_oom() {
131        let st = status_of(sys::IREE_STATUS_RESOURCE_EXHAUSTED);
132        assert_eq!(check(st).unwrap_err().code(), StatusCode::OutOfMemory);
133    }
134}