1use std::error::Error as StdError;
2use std::ffi::{c_char, CStr, CString};
3use std::fmt;
4
5use thiserror::Error as ThisError;
6
7#[derive(Clone, ThisError, Eq, PartialEq, Hash)]
11#[repr(C)]
12pub struct Error {
13 r#type: ErrorType,
14 msg: *mut c_char,
15}
16
17unsafe impl Send for Error {}
18unsafe impl Sync for Error {}
19
20#[derive(Copy, Clone, Eq, PartialEq, Hash)]
22#[repr(C)]
23enum ErrorType {
24 None = -1,
25 Exception,
26 #[allow(dead_code)]
27 Validation,
28}
29
30impl Error {
31 pub const fn new() -> Self {
32 Self { r#type: ErrorType::None, msg: std::ptr::null_mut() }
33 }
34}
35
36impl Default for Error {
37 #[inline]
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl fmt::Debug for Error {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 if !self.msg.is_null() {
46 let msg = unsafe { CStr::from_ptr(self.msg) };
47
48 match self.r#type {
49 ErrorType::Exception => {
50 f.debug_tuple("Exception").field(&msg).finish()
51 },
52 ErrorType::Validation => {
53 f.debug_tuple("Validation").field(&msg).finish()
54 },
55 _ => fmt::Debug::fmt(msg, f),
56 }
57 } else if let ErrorType::Exception = self.r#type {
58 write!(f, "Exception")
59 } else if let ErrorType::Validation = self.r#type {
60 write!(f, "Validation")
61 } else {
62 Ok(())
63 }
64 }
65}
66
67impl fmt::Display for Error {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 fmt::Debug::fmt(self, f)
70 }
71}
72
73impl Error {
74 pub(crate) fn from_str<S: Into<String>>(s: S) -> Self {
75 let c_string = CString::new(s.into()).unwrap_or_default();
76 let ptr = c_string.into_raw() ;
77 Self { r#type: ErrorType::Exception, msg: ptr }
78 }
79
80 pub fn from_err<E: StdError>(err: E) -> Self {
81 Self::from_str(err.to_string())
82 }
83
84 pub fn is_err(&self) -> bool {
85 !matches!(self.r#type, ErrorType::None)
86 }
87}