use std::fmt;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct ErrorId(pub i32);
impl ErrorId {
pub const SUCCESS: Self = Self(0);
pub const NOT_IMPLEMENTED: Self = Self(1);
pub const UNSUPPORTED_OPERATION: Self = Self(2);
pub const INVALID_ARGUMENT: Self = Self(3);
pub const NULL_POINTER: Self = Self(4);
pub const OUT_OF_MEMORY: Self = Self(5);
pub const LOCK_POISONED: Self = Self(6);
pub const WIDGET_BASE_NOT_IMPL: Self = Self(100);
pub const WIDGET_NOT_FOUND: Self = Self(101);
pub const WIDGET_INVALID_STATE: Self = Self(102);
pub const WIDGET_DEPRECATED: Self = Self(103);
pub const PLATFORM_UNSUPPORTED: Self = Self(200);
pub const PLATFORM_INIT_FAILED: Self = Self(201);
pub const CLIPBOARD_FAILED: Self = Self(202);
pub const DRAG_DROP_FAILED: Self = Self(203);
pub const RENDER_CONTEXT_INVALID: Self = Self(300);
pub const RENDER_PIPELINE_FAILED: Self = Self(301);
pub const I18N_LOAD_FAILED: Self = Self(400);
pub const FILE_NOT_FOUND: Self = Self(401);
}
#[derive(Debug, Clone)]
pub struct RwError {
pub id: ErrorId,
pub message: String,
}
impl RwError {
pub fn new(id: ErrorId, message: impl Into<String>) -> Self {
Self { id, message: message.into() }
}
pub fn not_implemented(feature: impl Into<String>) -> Self {
Self::new(ErrorId::NOT_IMPLEMENTED, format!("not implemented: {}", feature.into()))
}
pub fn msg(message: impl Into<String>) -> Self {
Self::new(ErrorId::SUCCESS, message)
}
pub fn from_panic(panic_info: &dyn std::any::Any) -> Self {
let msg = panic_info
.downcast_ref::<&str>()
.map(|s| s.to_string())
.or_else(|| panic_info.downcast_ref::<String>().cloned())
.unwrap_or_else(|| String::from("unknown panic"));
Self::new(ErrorId::NOT_IMPLEMENTED, msg)
}
}
impl fmt::Display for RwError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[RW-{:03}] {}", self.id.0, self.message)
}
}
impl std::error::Error for RwError {}
impl From<crate::core::CoreError> for RwError {
fn from(err: crate::core::CoreError) -> Self {
match err {
crate::core::CoreError::InvalidArgument(msg) => {
RwError::new(ErrorId::INVALID_ARGUMENT, msg)
}
crate::core::CoreError::NotSupported(msg) => {
RwError::new(ErrorId::UNSUPPORTED_OPERATION, msg)
}
crate::core::CoreError::NotFound(msg) => RwError::new(ErrorId::FILE_NOT_FOUND, msg),
crate::core::CoreError::Internal(msg) => RwError::new(ErrorId::NOT_IMPLEMENTED, msg),
}
}
}
pub type RwResult<T> = Result<T, RwError>;
pub fn catch_panic<F, T>(f: F) -> RwResult<T>
where
F: FnOnce() -> T + std::panic::UnwindSafe,
{
match std::panic::catch_unwind(f) {
Ok(v) => Ok(v),
Err(e) => Err(RwError::from_panic(&*e)),
}
}
pub mod ffi;
pub use ffi::{c_try_fallback, CAbiSafe};
pub fn to_error_id(result: RwResult<()>) -> i32 {
match result {
Ok(()) => ErrorId::SUCCESS.0,
Err(e) => {
log::error!("[rust_widgets] {}", e);
e.id.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rw_error_display() {
let e = RwError::msg("test error");
assert!(e.to_string().contains("test"));
}
#[test]
fn rw_error_not_implemented() {
let e = RwError::not_implemented("feature");
assert!(e.to_string().contains("not implemented"));
assert!(e.to_string().contains("feature"));
}
}