zsplg_core/
lib.rs

1use std::{any::Any, ffi::c_void, fmt, io::Error as IoError, sync::Arc};
2
3mod fatptr;
4
5/// === C FFI ===
6#[derive(Debug)]
7pub enum Error {
8    Io(IoError),
9    Cast,
10    Encoding,
11}
12
13impl From<IoError> for Error {
14    #[inline(always)]
15    fn from(x: IoError) -> Error {
16        Error::Io(x)
17    }
18}
19
20impl fmt::Display for Error {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            Error::Io(e) => fmt::Display::fmt(e, f),
24            Error::Cast => write!(f, "wrapper cast failed"),
25            Error::Encoding => write!(
26                f,
27                "byte sequence is not representable in the platform encoding"
28            ),
29        }
30    }
31}
32
33/// real FFI wrapper
34#[derive(Copy, Clone, Debug, PartialEq, Eq)]
35#[must_use]
36pub struct Object {
37    pub data: *const c_void,
38    pub meta: usize,
39}
40
41pub struct FFIResult {
42    pub data: Object,
43    // optimize padding
44    pub is_success: bool,
45}
46
47pub type RealOptObj = Option<Arc<dyn Any + Send + Sync>>;
48
49impl Object {
50    pub fn is_null(&self) -> bool {
51        self.data.is_null() && self.meta == 0
52    }
53}
54
55impl From<RealOptObj> for Object {
56    fn from(x: RealOptObj) -> Object {
57        match x {
58            Some(y) => unsafe {
59                let [data, meta] = crate::fatptr::decomp(Arc::into_raw(y));
60                Object {
61                    data: data as *const c_void,
62                    meta,
63                }
64            },
65            None => Object {
66                data: std::ptr::null(),
67                meta: 0,
68            },
69        }
70    }
71}
72
73impl Into<RealOptObj> for Object {
74    fn into(self) -> RealOptObj {
75        if !self.is_null() {
76            Some(unsafe { Arc::from_raw(crate::fatptr::recomp([self.data as usize, self.meta])) })
77        } else {
78            None
79        }
80    }
81}
82
83impl From<Result<Object, Object>> for FFIResult {
84    #[inline]
85    fn from(x: Result<Object, Object>) -> FFIResult {
86        let is_success = x.is_ok();
87        FFIResult {
88            data: match x {
89                Ok(y) | Err(y) => y,
90            },
91            is_success,
92        }
93    }
94}
95
96#[inline]
97pub fn wrap<T>(x: T) -> Object
98where
99    T: Send + Sync + 'static,
100{
101    Some(Arc::new(x) as Arc<dyn Any + Send + Sync + 'static>).into()
102}
103
104#[inline]
105pub fn wrapres<T, E>(x: Result<T, E>) -> FFIResult
106where
107    T: Send + Sync + 'static,
108    E: Send + Sync + 'static,
109{
110    x.map(wrap::<T>).map_err(wrap::<E>).into()
111}