use super::*; use core::cell::RefCell; use std::os::raw::{c_char, c_int, c_uchar, c_uint}; #[derive(Default)] struct StoredError { // invariant: len is zero IFF its occupied // contents are 1+ bytes because we also store the NULL TERMINATOR buf: Vec, } impl StoredError { const NULL_TERMINATOR: u8 = 0; fn clear(&mut self) { // no null terminator either! self.buf.clear(); } fn store(&mut self, error: &E) { write!(&mut self.buf, "{:?}", error); self.buf.push(Self::NULL_TERMINATOR); } fn tl_store(error: &E) { STORED_ERROR.with(|stored_error| { let mut stored_error = stored_error.borrow_mut(); stored_error.clear(); stored_error.store(error); }) } fn tl_clear() { STORED_ERROR.with(|stored_error| { let mut stored_error = stored_error.borrow_mut(); stored_error.clear(); }) } fn tl_raw_peek() -> (*const u8, usize) { STORED_ERROR.with(|stored_error| { let stored_error = stored_error.borrow(); match stored_error.buf.len() { 0 => (core::ptr::null(), 0), // no error! n => { // stores an error of length n-1 AND a NULL TERMINATOR (stored_error.buf.as_ptr(), n - 1) } } }) } } thread_local! { static STORED_ERROR: RefCell = RefCell::new(StoredError::default()); } type ErrorCode = i32; ////////////////////////////////////// /// Returns length (via out pointer) and pointer (via return value) of the last Reowolf error. /// - pointer is NULL iff there was no last error /// - data at pointer is null-delimited /// - len does NOT include the length of the null-delimiter #[no_mangle] pub unsafe extern "C" fn reowolf_error_peek(len: *mut usize) -> *const u8 { let (err_ptr, err_len) = StoredError::tl_raw_peek(); len.write(err_len); err_ptr } #[no_mangle] pub unsafe extern "C" fn protocol_description_parse( pdl: *const u8, pdl_len: usize, pd: *mut Arc, ) -> ErrorCode { StoredError::tl_clear(); let slice: *const [u8] = std::slice::from_raw_parts(pdl, pdl_len); let slice: &[u8] = &*slice; match ProtocolDescription::parse(slice) { Ok(new) => { pd.write(Arc::new(new)); 0 } Err(err) => { StoredError::tl_store(&err); -1 } } } #[no_mangle] pub unsafe extern "C" fn protocol_description_destroy(pd: Arc) { drop(pd) } #[no_mangle] pub unsafe extern "C" fn protocol_description_clone( pd: &Arc, ) -> Arc { pd.clone() } // #[no_mangle] // pub extern "C" fn connector_new(pd: *const Arc) -> *mut Connector { // Box::into_raw(Box::new(Connector::default())) // } // /// Creates and returns Reowolf Connector structure allocated on the heap. // #[no_mangle] // pub extern "C" fn connector_with_controller_id(controller_id: ControllerId) -> *mut Connector { // Box::into_raw(Box::new(Connector::Unconfigured(Unconfigured { controller_id }))) // }