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 fmt::Display::fmt(self, f)
46 }
47}
48
49impl fmt::Display for Error {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 if !self.msg.is_null() {
52 fmt::Debug::fmt(unsafe { CStr::from_ptr(self.msg) }, f)
53 } else {
54 use ErrorType::*;
55 let msg = match self.r#type {
56 None => return Ok(()),
57 Exception => "exception",
58 Validation => "validation",
59 };
60 write!(f, "{}", msg)
61 }
62 }
63}
64
65impl Error {
66 pub(crate) fn from_str<S: Into<String>>(s: S) -> Self {
67 let c_string = CString::new(s.into()).unwrap_or_default();
68 let ptr = c_string.into_raw() ;
69 Self { r#type: ErrorType::Exception, msg: ptr }
70 }
71
72 pub fn from_err<E: StdError>(err: E) -> Self {
73 Self::from_str(err.to_string())
74 }
75
76 pub fn is_err(&self) -> bool {
77 !matches!(self.r#type, ErrorType::None)
78 }
79}