use std::cell::RefCell;
use std::ffi::CStr;
use std::ffi::CString;
use libc::c_char;
use nemo_flow::error::FlowError;
use nemo_flow::plugin::PluginError;
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NemoFlowStatus {
Ok = 0,
AlreadyExists = 1,
NotFound = 2,
ScopeStackEmpty = 3,
GuardrailRejected = 4,
Internal = 5,
NullPointer = 6,
InvalidJson = 7,
InvalidUtf8 = 8,
InvalidArg = 9,
}
thread_local! {
static LAST_ERROR: RefCell<Option<CString>> = const { RefCell::new(None) };
}
pub fn set_last_error(msg: &str) {
LAST_ERROR.with(|cell| {
*cell.borrow_mut() = CString::new(msg).ok();
});
}
pub fn clear_last_error() {
LAST_ERROR.with(|cell| {
*cell.borrow_mut() = None;
});
}
pub fn last_error_message() -> Option<String> {
LAST_ERROR.with(|cell| {
cell.borrow()
.as_ref()
.map(|s| s.to_string_lossy().into_owned())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn nemo_flow_last_error() -> *const c_char {
LAST_ERROR.with(|cell| {
cell.borrow()
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or(std::ptr::null())
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nemo_flow_set_last_error_message(msg: *const c_char) {
if msg.is_null() {
set_last_error("unknown callback error");
return;
}
match unsafe { CStr::from_ptr(msg) }.to_str() {
Ok(s) => set_last_error(s),
Err(_) => set_last_error("callback error was not valid UTF-8"),
}
}
impl From<&FlowError> for NemoFlowStatus {
fn from(e: &FlowError) -> Self {
match e {
FlowError::AlreadyExists(_) => NemoFlowStatus::AlreadyExists,
FlowError::NotFound(_) => NemoFlowStatus::NotFound,
FlowError::InvalidArgument(_) => NemoFlowStatus::InvalidArg,
FlowError::ScopeStackEmpty => NemoFlowStatus::ScopeStackEmpty,
FlowError::GuardrailRejected(_) => NemoFlowStatus::GuardrailRejected,
FlowError::Internal(_) => NemoFlowStatus::Internal,
}
}
}
pub fn status_from_error(e: &FlowError) -> NemoFlowStatus {
set_last_error(&e.to_string());
NemoFlowStatus::from(e)
}
pub fn status_from_plugin_error(e: &PluginError) -> NemoFlowStatus {
set_last_error(&e.to_string());
match e {
PluginError::NotFound(_) => NemoFlowStatus::NotFound,
PluginError::InvalidConfig(_) | PluginError::Serialization(_) => NemoFlowStatus::InvalidArg,
PluginError::Internal(_) | PluginError::RegistrationFailed(_) => NemoFlowStatus::Internal,
}
}
#[cfg(test)]
#[path = "../tests/coverage/error_tests.rs"]
mod tests;