tesseract_swift_utils/
error.rs1use crate::panic::FromPanic;
2use crate::result::{Zip1, Result};
3
4use super::string::*;
5use super::traits::TryAsRef;
6use std::error::Error;
7use std::fmt::Display;
8use std::mem::ManuallyDrop;
9
10#[repr(u32)]
12#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq)]
13pub enum CErrorCode {
14 Null = 0, Panic, Utf8, Cast, Swift
15}
16
17pub trait ErrorCode: Copy {
18 fn from_u32(val: u32) -> Option<Self> {
19 if val < Self::FIRST || val >= Self::Sentinel { return None; }
20 unsafe { Some(std::mem::transmute_copy(&val)) }
21 }
22 const FIRST: u32;
23 #[allow(non_upper_case_globals)]
24 const Sentinel: u32;
25}
26
27impl ErrorCode for CErrorCode {
28 const FIRST: u32 = Self::Null as u32;
29 #[allow(non_upper_case_globals)]
30 const Sentinel: u32 = Self::Swift as u32 + 1;
31}
32
33#[repr(C)]
34#[derive(Debug, Clone)]
35pub struct CError {
36 pub code: u32,
37 pub reason: CString,
38}
39
40impl CError {
41 pub fn new(code: u32, reason: String) -> Self {
42 Self { code: code, reason: reason.into() }
43 }
44
45 pub fn null<T: ?Sized>() -> Self {
46 Self::new(CErrorCode::Null as u32, std::any::type_name::<T>().into())
47 }
48
49 pub fn panic(reason: String) -> Self {
50 Self::new(CErrorCode::Panic as u32, reason.into())
51 }
52
53 pub fn utf8(reason: String) -> Self {
54 Self::new(CErrorCode::Utf8 as u32, reason.into())
55 }
56
57 pub fn swift(reason: String) -> Self {
58 Self::new(CErrorCode::Swift as u32, reason.into())
59 }
60
61 pub fn cast<F: ?Sized, T: ?Sized>() -> Self {
62 Self::new(
63 CErrorCode::Cast as u32,
64 format!("Can't cast {} into {}",
65 std::any::type_name::<F>(),
66 std::any::type_name::<T>()
67 )
68 )
69 }
70}
71
72impl From<std::str::Utf8Error> for CError {
73 fn from(error: std::str::Utf8Error) -> Self {
74 Self::utf8(error.to_string())
75 }
76}
77
78impl From<std::ffi::IntoStringError> for CError {
79 fn from(error: std::ffi::IntoStringError) -> Self {
80 Self::utf8(error.to_string())
81 }
82}
83
84impl Display for CError {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match CErrorCode::from_u32(self.code) {
87 None => write!(f, "Error[{}]", self.code),
88 Some(code) => match code {
89 CErrorCode::Null => write!(f, "Error::Null"),
90 CErrorCode::Panic => write!(f, "Error::Panic"),
91 CErrorCode::Utf8 => write!(f, "Error::UTF8"),
92 CErrorCode::Cast => write!(f, "Error::Cast"),
93 CErrorCode::Swift => write!(f, "Error::Swift")
94 }
95 }?;
96 let reason = self.reason.try_as_ref().map_err(|_| std::fmt::Error)?;
97 if reason.len() > 0 { write!(f, ": {}", reason)? }
98 Ok(())
99 }
100}
101
102impl Error for CError {}
103
104impl FromPanic for CError {
105 fn from_panic(panic: &str) -> Self {
106 Self::panic(panic.to_owned().into())
107 }
108}
109
110#[repr(C)]
111#[derive(Debug, Clone)]
112pub struct SwiftError {
113 pub code: isize,
114 pub domain: CString,
115 pub description: CString
116}
117
118impl SwiftError {
119 pub fn new(code: isize, domain: CStringRef, description: CStringRef) -> Self {
120 Self { code, domain: domain.try_as_ref().unwrap().into(),
121 description: description.try_as_ref().unwrap().into() }
122 }
123}
124
125impl TryFrom<SwiftError> for CError {
126 type Error = CError;
127
128 fn try_from(value: SwiftError) -> Result<Self> {
129 value.domain.try_as_ref().zip(value.description.try_as_ref())
130 .map(|(dm, ds)| {
131 format!("{} ~~~ {} ~~~ {}", dm, value.code, ds)
132 }).map(|str| CError::new(CErrorCode::Swift as u32, str))
133 }
134}
135
136impl TryFrom<&CError> for SwiftError {
137 type Error = CError;
138
139 fn try_from(value: &CError) -> Result<Self> {
140 if value.code != CErrorCode::Swift as u32 { return Err(CError::cast::<CError, SwiftError>()); }
141 let reason = value.reason.try_as_ref()?;
142 let parts: Vec<&str> = reason.split(" ~~~ ").collect();
143 if parts.len() != 3 { return Err(CError::cast::<CError, SwiftError>()); }
144 let code = parts[1].parse::<isize>().map_err(|_| CError::cast::<CError, SwiftError>())?;
145 Ok(Self { code, domain: parts[0].to_owned().into(), description: parts[2].to_owned().into() })
146 }
147}
148
149impl Display for SwiftError {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 write!(f, "{} ~~~ {} ~~~ {}", self.domain, self.code, self.description)
152 }
153}
154
155impl Error for SwiftError {}
156
157#[no_mangle]
158pub unsafe extern "C" fn tesseract_utils_swift_error_new(
159 code: isize, domain: CStringRef, description: CStringRef
160) -> ManuallyDrop<SwiftError> {
161 ManuallyDrop::new(SwiftError::new(code, domain, description))
162}
163
164#[no_mangle]
165pub unsafe extern "C" fn tesseract_utils_cerr_new_swift_error(
166 code: isize, domain: CStringRef, description: CStringRef
167) -> ManuallyDrop<CError> {
168 ManuallyDrop::new(SwiftError::new(code, domain, description).try_into().unwrap())
169}
170
171#[no_mangle]
172pub unsafe extern "C" fn tesseract_utils_cerr_get_description(
173 err: &CError
174) -> ManuallyDrop<CString> {
175 ManuallyDrop::new(err.to_string().into())
176}
177
178#[no_mangle]
179pub unsafe extern "C" fn tesseract_utils_cerr_get_swift_error(error: &CError) -> ManuallyDrop<SwiftError> {
180 ManuallyDrop::new(SwiftError::try_from(error).unwrap())
181}
182
183#[no_mangle]
184pub unsafe extern "C" fn tesseract_utils_swift_error_free(err: &mut ManuallyDrop<SwiftError>) {
185 ManuallyDrop::drop(err);
186}
187
188#[no_mangle]
189pub unsafe extern "C" fn tesseract_utils_cerror_free(err: &mut ManuallyDrop<CError>) {
190 ManuallyDrop::drop(err);
191}