blazesym_c/
error.rs

1use std::cell::Cell;
2use std::ffi::c_char;
3
4use blazesym::ErrorKind;
5
6
7/// An enum providing a rough classification of errors.
8///
9/// C ABI compatible version of [`blazesym::ErrorKind`].
10#[repr(transparent)]
11#[derive(Copy, Clone, Debug, Eq, PartialEq)]
12pub struct blaze_err(i16);
13
14impl blaze_err {
15    /// The operation was successful.
16    pub const OK: blaze_err = blaze_err(0);
17    /// An entity was not found, often a file.
18    pub const NOT_FOUND: blaze_err = blaze_err(-2);
19    /// The operation lacked the necessary privileges to complete.
20    pub const PERMISSION_DENIED: blaze_err = blaze_err(-1);
21    /// An entity already exists, often a file.
22    pub const ALREADY_EXISTS: blaze_err = blaze_err(-17);
23    /// The operation needs to block to complete, but the blocking
24    /// operation was requested to not occur.
25    pub const WOULD_BLOCK: blaze_err = blaze_err(-11);
26    /// Data not valid for the operation were encountered.
27    pub const INVALID_DATA: blaze_err = blaze_err(-22);
28    /// The I/O operation's timeout expired, causing it to be canceled.
29    pub const TIMED_OUT: blaze_err = blaze_err(-110);
30    /// This operation is unsupported on this platform.
31    pub const UNSUPPORTED: blaze_err = blaze_err(-95);
32    /// An operation could not be completed, because it failed
33    /// to allocate enough memory.
34    pub const OUT_OF_MEMORY: blaze_err = blaze_err(-12);
35    /// A parameter was incorrect.
36    pub const INVALID_INPUT: blaze_err = blaze_err(-256);
37    /// An error returned when an operation could not be completed
38    /// because a call to [`write`] returned [`Ok(0)`].
39    pub const WRITE_ZERO: blaze_err = blaze_err(-257);
40    /// An error returned when an operation ould not be completed
41    /// because an "end of file" was reached prematurely.
42    pub const UNEXPECTED_EOF: blaze_err = blaze_err(-258);
43    /// DWARF input data was invalid.
44    pub const INVALID_DWARF: blaze_err = blaze_err(-259);
45    /// A custom error that does not fall under any other I/O error
46    /// kind.
47    pub const OTHER: blaze_err = blaze_err(-260);
48}
49
50impl From<ErrorKind> for blaze_err {
51    fn from(other: ErrorKind) -> Self {
52        match other {
53            ErrorKind::NotFound => blaze_err::NOT_FOUND,
54            ErrorKind::PermissionDenied => blaze_err::PERMISSION_DENIED,
55            ErrorKind::AlreadyExists => blaze_err::ALREADY_EXISTS,
56            ErrorKind::WouldBlock => blaze_err::WOULD_BLOCK,
57            ErrorKind::InvalidInput => blaze_err::INVALID_INPUT,
58            ErrorKind::InvalidData => blaze_err::INVALID_DATA,
59            ErrorKind::InvalidDwarf => blaze_err::INVALID_DWARF,
60            ErrorKind::TimedOut => blaze_err::TIMED_OUT,
61            ErrorKind::WriteZero => blaze_err::WRITE_ZERO,
62            ErrorKind::Unsupported => blaze_err::UNSUPPORTED,
63            ErrorKind::UnexpectedEof => blaze_err::UNEXPECTED_EOF,
64            ErrorKind::OutOfMemory => blaze_err::OUT_OF_MEMORY,
65            ErrorKind::Other => blaze_err::OTHER,
66            _ => unreachable!(),
67        }
68    }
69}
70
71
72thread_local! {
73    /// The error reported by the last fallible API function invoked.
74    static LAST_ERR: Cell<blaze_err> = const { Cell::new(blaze_err::OK) };
75}
76
77/// Retrieve the error reported by the last fallible API function invoked.
78#[no_mangle]
79pub extern "C" fn blaze_err_last() -> blaze_err {
80    LAST_ERR.with(Cell::get)
81}
82
83/// Retrieve the error reported by the last fallible API function invoked.
84pub(crate) fn set_last_err(err: blaze_err) {
85    LAST_ERR.with(|cell| cell.set(err))
86}
87
88
89/// Retrieve a textual representation of the error code.
90#[no_mangle]
91pub extern "C" fn blaze_err_str(err: blaze_err) -> *const c_char {
92    match err {
93        blaze_err::OK => b"success\0".as_ptr().cast(),
94        blaze_err::NOT_FOUND => ErrorKind::NotFound.as_bytes().as_ptr().cast(),
95        blaze_err::PERMISSION_DENIED => ErrorKind::PermissionDenied.as_bytes().as_ptr().cast(),
96        blaze_err::ALREADY_EXISTS => ErrorKind::AlreadyExists.as_bytes().as_ptr().cast(),
97        blaze_err::WOULD_BLOCK => ErrorKind::WouldBlock.as_bytes().as_ptr().cast(),
98        blaze_err::INVALID_INPUT => ErrorKind::InvalidInput.as_bytes().as_ptr().cast(),
99        blaze_err::INVALID_DATA => ErrorKind::InvalidData.as_bytes().as_ptr().cast(),
100        blaze_err::INVALID_DWARF => ErrorKind::InvalidDwarf.as_bytes().as_ptr().cast(),
101        blaze_err::TIMED_OUT => ErrorKind::TimedOut.as_bytes().as_ptr().cast(),
102        blaze_err::WRITE_ZERO => ErrorKind::WriteZero.as_bytes().as_ptr().cast(),
103        blaze_err::UNSUPPORTED => ErrorKind::Unsupported.as_bytes().as_ptr().cast(),
104        blaze_err::UNEXPECTED_EOF => ErrorKind::UnexpectedEof.as_bytes().as_ptr().cast(),
105        blaze_err::OUT_OF_MEMORY => ErrorKind::OutOfMemory.as_bytes().as_ptr().cast(),
106        _ => ErrorKind::Other.as_bytes().as_ptr().cast(),
107    }
108}
109
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    use std::ffi::CStr;
116
117
118    /// Check that we can convert `ErrorKind` instances into `blaze_err`.
119    #[test]
120    fn error_conversion() {
121        let data = [
122            (ErrorKind::NotFound, blaze_err::NOT_FOUND),
123            (ErrorKind::PermissionDenied, blaze_err::PERMISSION_DENIED),
124            (ErrorKind::AlreadyExists, blaze_err::ALREADY_EXISTS),
125            (ErrorKind::WouldBlock, blaze_err::WOULD_BLOCK),
126            (ErrorKind::InvalidInput, blaze_err::INVALID_INPUT),
127            (ErrorKind::InvalidData, blaze_err::INVALID_DATA),
128            (ErrorKind::InvalidDwarf, blaze_err::INVALID_DWARF),
129            (ErrorKind::TimedOut, blaze_err::TIMED_OUT),
130            (ErrorKind::WriteZero, blaze_err::WRITE_ZERO),
131            (ErrorKind::Unsupported, blaze_err::UNSUPPORTED),
132            (ErrorKind::UnexpectedEof, blaze_err::UNEXPECTED_EOF),
133            (ErrorKind::OutOfMemory, blaze_err::OUT_OF_MEMORY),
134            (ErrorKind::Other, blaze_err::OTHER),
135        ];
136
137        for (kind, expected) in data {
138            assert_eq!(blaze_err::from(kind), expected);
139            let cstr = unsafe { CStr::from_ptr(blaze_err_str(expected)) };
140            let expected = CStr::from_bytes_with_nul(kind.as_bytes()).unwrap();
141            assert_eq!(cstr, expected);
142        }
143    }
144}