tesseract_swift_utils/
string.rs

1use crate::panic::PanicContext;
2use crate::traits::AsCRef;
3
4use super::error::CError;
5use super::response::CMoveResponse;
6use super::result::Result;
7use super::traits::TryAsRef;
8use std::ffi::{CStr as FCStr, CString as FCString};
9use std::mem::ManuallyDrop;
10use std::os::raw::c_char;
11use std::borrow::Borrow;
12
13pub type CStringRef = *const c_char;
14
15#[repr(C)]
16#[derive(Debug)]
17pub struct CString(*const c_char);
18
19unsafe impl Sync for CString {}
20unsafe impl Send for CString {}
21
22impl Drop for CString {
23    fn drop(&mut self) {
24        let _ = unsafe { FCString::from_raw(self.0 as *mut c_char) };
25    }
26}
27
28impl Clone for CString {
29    fn clone(&self) -> Self {
30        self.try_as_ref().unwrap().into()
31    }
32}
33
34impl PartialEq for CString {
35    fn eq(&self, other: &Self) -> bool {
36        unsafe { FCStr::from_ptr(self.0).eq(FCStr::from_ptr(other.0)) }
37    }
38}
39
40impl TryAsRef<str> for CStringRef {
41    type Error = CError;
42
43    fn try_as_ref(&self) -> Result<&str> {
44        unsafe { FCStr::from_ptr(*self).to_str().map_err(|err| err.into()) }
45    }
46}
47
48impl std::fmt::Display for CString {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        let string = self.try_as_ref().map_err(|_| std::fmt::Error)?;
51        write!(f, "{}", string)
52    }
53}
54
55impl TryAsRef<str> for CString {
56    type Error = CError;
57
58    fn try_as_ref(&self) -> Result<&str> {
59        self.0.try_as_ref()
60    }
61}
62
63impl AsCRef<CStringRef> for CString {
64    fn as_cref(&self) -> CStringRef {
65        self.0
66    }
67}
68
69impl<'a> TryFrom<&'a CString> for &'a str {
70    type Error = CError;
71
72    fn try_from(value: &'a CString) -> Result<Self> {
73        value.0.try_as_ref()
74    }
75}
76
77impl TryFrom<CString> for String {
78    type Error = CError;
79
80    fn try_from(value: CString) -> Result<Self> {
81        if value.0.is_null() {
82            Err(CError::null::<CString>())
83        } else {
84            let value = ManuallyDrop::new(value); // This is safe. Memory will be consumed by rust CString
85            unsafe {
86                FCString::from_raw(value.0 as *mut c_char)
87                    .into_string()
88                    .map_err(|err| err.into())
89            }
90        }
91    }
92}
93
94impl<T: Borrow<str>> From<T> for CString {
95    fn from(value: T) -> Self {
96        Self(FCString::new(value.borrow()).unwrap().into_raw())
97    }
98}
99
100#[no_mangle]
101pub unsafe extern "C" fn tesseract_utils_cstring_new(
102    cstr: CStringRef,
103    res: &mut ManuallyDrop<CString>,
104    err: &mut ManuallyDrop<CError>,
105) -> bool {
106    CError::panic_context(|| cstr.try_as_ref()).response(res, err)
107}
108
109#[no_mangle]
110pub unsafe extern "C" fn tesseract_utils_cstring_free(cstr: ManuallyDrop<CString>) {
111    let _ = ManuallyDrop::into_inner(cstr);
112}