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`][std::io::Write::write] returned
39    /// [`Ok(0)`][Ok].
40    pub const WRITE_ZERO: blaze_err = blaze_err(-257);
41    /// An error returned when an operation ould not be completed
42    /// because an "end of file" was reached prematurely.
43    pub const UNEXPECTED_EOF: blaze_err = blaze_err(-258);
44    /// DWARF input data was invalid.
45    pub const INVALID_DWARF: blaze_err = blaze_err(-259);
46    /// A custom error that does not fall under any other I/O error
47    /// kind.
48    pub const OTHER: blaze_err = blaze_err(-260);
49}
50
51impl From<ErrorKind> for blaze_err {
52    fn from(other: ErrorKind) -> Self {
53        match other {
54            ErrorKind::NotFound => blaze_err::NOT_FOUND,
55            ErrorKind::PermissionDenied => blaze_err::PERMISSION_DENIED,
56            ErrorKind::AlreadyExists => blaze_err::ALREADY_EXISTS,
57            ErrorKind::WouldBlock => blaze_err::WOULD_BLOCK,
58            ErrorKind::InvalidInput => blaze_err::INVALID_INPUT,
59            ErrorKind::InvalidData => blaze_err::INVALID_DATA,
60            ErrorKind::InvalidDwarf => blaze_err::INVALID_DWARF,
61            ErrorKind::TimedOut => blaze_err::TIMED_OUT,
62            ErrorKind::WriteZero => blaze_err::WRITE_ZERO,
63            ErrorKind::Unsupported => blaze_err::UNSUPPORTED,
64            ErrorKind::UnexpectedEof => blaze_err::UNEXPECTED_EOF,
65            ErrorKind::OutOfMemory => blaze_err::OUT_OF_MEMORY,
66            ErrorKind::Other => blaze_err::OTHER,
67            _ => unreachable!(),
68        }
69    }
70}
71
72
73thread_local! {
74    /// The error reported by the last fallible API function invoked.
75    static LAST_ERR: Cell<blaze_err> = const { Cell::new(blaze_err::OK) };
76}
77
78/// Retrieve the error reported by the last fallible API function invoked.
79#[no_mangle]
80pub extern "C" fn blaze_err_last() -> blaze_err {
81    LAST_ERR.with(Cell::get)
82}
83
84/// Retrieve the error reported by the last fallible API function invoked.
85pub(crate) fn set_last_err(err: blaze_err) {
86    LAST_ERR.with(|cell| cell.set(err))
87}
88
89
90/// Retrieve a textual representation of the error code.
91#[no_mangle]
92pub extern "C" fn blaze_err_str(err: blaze_err) -> *const c_char {
93    match err {
94        blaze_err::OK => b"success\0".as_ptr().cast(),
95        blaze_err::NOT_FOUND => ErrorKind::NotFound.as_bytes().as_ptr().cast(),
96        blaze_err::PERMISSION_DENIED => ErrorKind::PermissionDenied.as_bytes().as_ptr().cast(),
97        blaze_err::ALREADY_EXISTS => ErrorKind::AlreadyExists.as_bytes().as_ptr().cast(),
98        blaze_err::WOULD_BLOCK => ErrorKind::WouldBlock.as_bytes().as_ptr().cast(),
99        blaze_err::INVALID_INPUT => ErrorKind::InvalidInput.as_bytes().as_ptr().cast(),
100        blaze_err::INVALID_DATA => ErrorKind::InvalidData.as_bytes().as_ptr().cast(),
101        blaze_err::INVALID_DWARF => ErrorKind::InvalidDwarf.as_bytes().as_ptr().cast(),
102        blaze_err::TIMED_OUT => ErrorKind::TimedOut.as_bytes().as_ptr().cast(),
103        blaze_err::WRITE_ZERO => ErrorKind::WriteZero.as_bytes().as_ptr().cast(),
104        blaze_err::UNSUPPORTED => ErrorKind::Unsupported.as_bytes().as_ptr().cast(),
105        blaze_err::UNEXPECTED_EOF => ErrorKind::UnexpectedEof.as_bytes().as_ptr().cast(),
106        blaze_err::OUT_OF_MEMORY => ErrorKind::OutOfMemory.as_bytes().as_ptr().cast(),
107        _ => ErrorKind::Other.as_bytes().as_ptr().cast(),
108    }
109}
110
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    use std::ffi::CStr;
117
118
119    /// Check that we can convert `ErrorKind` instances into `blaze_err`.
120    #[test]
121    fn error_conversion() {
122        let data = [
123            (ErrorKind::NotFound, blaze_err::NOT_FOUND),
124            (ErrorKind::PermissionDenied, blaze_err::PERMISSION_DENIED),
125            (ErrorKind::AlreadyExists, blaze_err::ALREADY_EXISTS),
126            (ErrorKind::WouldBlock, blaze_err::WOULD_BLOCK),
127            (ErrorKind::InvalidInput, blaze_err::INVALID_INPUT),
128            (ErrorKind::InvalidData, blaze_err::INVALID_DATA),
129            (ErrorKind::InvalidDwarf, blaze_err::INVALID_DWARF),
130            (ErrorKind::TimedOut, blaze_err::TIMED_OUT),
131            (ErrorKind::WriteZero, blaze_err::WRITE_ZERO),
132            (ErrorKind::Unsupported, blaze_err::UNSUPPORTED),
133            (ErrorKind::UnexpectedEof, blaze_err::UNEXPECTED_EOF),
134            (ErrorKind::OutOfMemory, blaze_err::OUT_OF_MEMORY),
135            (ErrorKind::Other, blaze_err::OTHER),
136        ];
137
138        for (kind, expected) in data {
139            assert_eq!(blaze_err::from(kind), expected);
140            let cstr = unsafe { CStr::from_ptr(blaze_err_str(expected)) };
141            let expected = CStr::from_bytes_with_nul(kind.as_bytes()).unwrap();
142            assert_eq!(cstr, expected);
143        }
144    }
145}