1use std::cell::RefCell;
2use std::ffi::CString;
3use std::os::raw::c_char;
4use std::ptr;
5
6struct LastError {
7 message: CString,
8 file: CString,
9 line: u32,
10}
11
12thread_local! {
13 static LAST_ERROR: RefCell<Option<LastError>> = const { RefCell::new(None) };
14}
15
16fn cstring_from_str(value: &str) -> CString {
17 if value.as_bytes().contains(&0) {
18 let mut bytes = value.as_bytes().to_vec();
19 for byte in &mut bytes {
20 if *byte == 0 {
21 *byte = b'?';
22 }
23 }
24 CString::new(bytes).unwrap_or_else(|_| CString::new("error").unwrap())
25 } else {
26 CString::new(value).unwrap_or_else(|_| CString::new("error").unwrap())
27 }
28}
29
30pub(crate) fn set_last_error(message: &str, file: &'static str, line: u32) {
31 let message = cstring_from_str(message);
32 let file = cstring_from_str(file);
33 LAST_ERROR.with(|slot| {
34 *slot.borrow_mut() = Some(LastError {
35 message,
36 file,
37 line,
38 });
39 });
40}
41
42pub(crate) fn clear_last_error() {
43 LAST_ERROR.with(|slot| {
44 *slot.borrow_mut() = None;
45 });
46}
47
48#[unsafe(no_mangle)]
54pub unsafe extern "C" fn diffsol_error_code() -> i32 {
55 LAST_ERROR.with(|slot| if slot.borrow().is_some() { 1 } else { 0 })
56}
57
58#[unsafe(no_mangle)]
64pub unsafe extern "C" fn diffsol_error() -> *const c_char {
65 LAST_ERROR.with(|slot| {
66 slot.borrow()
67 .as_ref()
68 .map(|err| err.message.as_ptr())
69 .unwrap_or(ptr::null())
70 })
71}
72
73#[unsafe(no_mangle)]
79pub unsafe extern "C" fn diffsol_last_error_message() -> *const c_char {
80 LAST_ERROR.with(|slot| {
81 slot.borrow()
82 .as_ref()
83 .map(|err| err.message.as_ptr())
84 .unwrap_or(ptr::null())
85 })
86}
87
88#[unsafe(no_mangle)]
94pub unsafe extern "C" fn diffsol_last_error_file() -> *const c_char {
95 LAST_ERROR.with(|slot| {
96 slot.borrow()
97 .as_ref()
98 .map(|err| err.file.as_ptr())
99 .unwrap_or(ptr::null())
100 })
101}
102
103#[unsafe(no_mangle)]
109pub unsafe extern "C" fn diffsol_last_error_line() -> u32 {
110 LAST_ERROR.with(|slot| slot.borrow().as_ref().map(|err| err.line).unwrap_or(0))
111}
112
113#[unsafe(no_mangle)]
119pub unsafe extern "C" fn diffsol_clear_last_error() {
120 clear_last_error();
121}