#[macro_export]
macro_rules! c_try {
($body:expr) => {{
let __result: $crate::error::RwResult<_> = $crate::error::catch_panic(|| $body);
match __result {
Ok(val) => val,
Err(e) => {
log::error!("[rust_widgets] C ABI error: {e}");
$crate::error::ffi::record_last_ffi_error(e.clone());
$crate::error::c_try_fallback(e)
}
}
}};
}
pub fn c_try_fallback<T>(_e: super::RwError) -> T
where
T: CAbiSafe,
{
T::c_abi_fallback()
}
static LAST_FFI_ERROR: std::sync::Mutex<Option<super::RwError>> = std::sync::Mutex::new(None);
pub fn record_last_ffi_error(error: super::RwError) {
if let Ok(mut slot) = LAST_FFI_ERROR.lock() {
*slot = Some(error);
}
}
#[cfg(all(feature = "desktop", not(feature = "mini")))]
pub(crate) fn last_ffi_error() -> Option<super::RwError> {
LAST_FFI_ERROR.lock().ok().and_then(|slot| slot.clone())
}
pub fn clear_last_ffi_error() {
if let Ok(mut slot) = LAST_FFI_ERROR.lock() {
*slot = None;
}
}
pub trait CAbiSafe {
fn c_abi_fallback() -> Self;
}
impl CAbiSafe for u64 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for i64 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for u32 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for i32 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for u16 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for i16 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for u8 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for i8 {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for f32 {
fn c_abi_fallback() -> Self {
0.0
}
}
impl CAbiSafe for f64 {
fn c_abi_fallback() -> Self {
0.0
}
}
impl CAbiSafe for bool {
fn c_abi_fallback() -> Self {
false
}
}
impl CAbiSafe for *const std::ffi::c_char {
fn c_abi_fallback() -> Self {
std::ptr::null()
}
}
impl CAbiSafe for *mut std::ffi::c_char {
fn c_abi_fallback() -> Self {
std::ptr::null_mut()
}
}
impl CAbiSafe for *const u64 {
fn c_abi_fallback() -> Self {
std::ptr::null()
}
}
impl CAbiSafe for *mut u64 {
fn c_abi_fallback() -> Self {
std::ptr::null_mut()
}
}
impl CAbiSafe for usize {
fn c_abi_fallback() -> Self {
0
}
}
impl CAbiSafe for isize {
fn c_abi_fallback() -> Self {
0
}
}
#[macro_export]
macro_rules! c_try_void {
($body:expr) => {{
let __result: $crate::error::RwResult<_> = $crate::error::catch_panic(|| $body);
if let Err(e) = __result {
log::error!("[rust_widgets] C ABI error: {e}");
$crate::error::ffi::record_last_ffi_error(e.clone());
}
}};
}
#[cfg(all(test, feature = "desktop", not(feature = "mini")))]
mod tests {
use super::*;
use crate::error::{ErrorId, RwError};
#[test]
fn last_ffi_error_roundtrip() {
clear_last_ffi_error();
assert!(last_ffi_error().is_none());
record_last_ffi_error(RwError::new(ErrorId::INVALID_ARGUMENT, "bad widget"));
let recorded = last_ffi_error().expect("error should be recorded");
assert_eq!(recorded.id, ErrorId::INVALID_ARGUMENT);
assert!(recorded.message.contains("bad widget"));
clear_last_ffi_error();
assert!(last_ffi_error().is_none());
}
}