ferment_interfaces/
lib.rs

1pub mod fermented;
2
3use std::collections::{BTreeMap, HashMap};
4use std::ffi::{CStr, CString};
5use std::hash::Hash;
6use std::mem;
7use std::os::raw::c_char;
8use std::ptr::NonNull;
9
10/// We pass here main context of parent program
11
12pub type OpaqueContext = *const std::os::raw::c_void;
13
14pub type OpaqueContextMut = *mut std::os::raw::c_void;
15
16// No Drop implementation for them
17
18pub trait FFIConversion<T> {
19    /// # Safety
20    unsafe fn ffi_from_const(ffi: *const Self) -> T;
21    /// # Safety
22    unsafe fn ffi_to_const(obj: T) -> *const Self;
23    /// # Safety
24    unsafe fn ffi_from(ffi: *mut Self) -> T {
25        Self::ffi_from_const(ffi)
26    }
27    /// # Safety
28    unsafe fn ffi_to(obj: T) -> *mut Self {
29        Self::ffi_to_const(obj) as *mut _
30    }
31    /// # Safety
32    unsafe fn ffi_from_opt(ffi: *mut Self) -> Option<T> {
33        (!ffi.is_null()).then_some(<Self as FFIConversion<T>>::ffi_from(ffi))
34    }
35    /// # Safety
36    unsafe fn ffi_to_opt(obj: Option<T>) -> *mut Self where Self: Sized {
37        obj.map_or(NonNull::<Self>::dangling().as_ptr(), |o| <Self as FFIConversion<T>>::ffi_to(o))
38    }
39    /// # Safety
40    unsafe fn destroy(ffi: *mut Self) {
41        if ffi.is_null() {
42            return;
43        }
44        unbox_any(ffi);
45    }
46}
47
48impl FFIConversion<String> for c_char {
49    unsafe fn ffi_from_const(ffi: *const Self) -> String {
50        CStr::from_ptr(ffi).to_str().unwrap().to_string()
51    }
52
53    unsafe fn ffi_to_const(obj: String) -> *const Self {
54        let s = CString::new(obj).unwrap();
55        s.as_ptr()
56    }
57
58    unsafe fn ffi_from(ffi: *mut Self) -> String {
59        Self::ffi_from_const(ffi as *const _)
60    }
61
62    unsafe fn ffi_to(obj: String) -> *mut Self {
63        CString::new(obj).unwrap().into_raw()
64    }
65
66    unsafe fn destroy(ffi: *mut Self) {
67        if ffi.is_null() {
68            return;
69        }
70        unbox_string(ffi);
71    }
72}
73
74impl FFIConversion<&str> for c_char {
75    unsafe fn ffi_from_const(ffi: *const Self) -> &'static str {
76        CStr::from_ptr(ffi).to_str().unwrap()
77    }
78
79    unsafe fn ffi_to_const(obj: &str) -> *const Self {
80        let s = CString::new(obj).unwrap();
81        s.as_ptr()
82    }
83
84    unsafe fn ffi_from(ffi: *mut Self) -> &'static str {
85        Self::ffi_from_const(ffi)
86    }
87
88    unsafe fn ffi_to(obj: &str) -> *mut Self {
89        CString::new(obj).unwrap().into_raw()
90    }
91
92    unsafe fn destroy(ffi: *mut Self) {
93        if ffi.is_null() {
94            return;
95        }
96        unbox_string(ffi);
97    }
98}
99
100pub fn boxed<T>(obj: T) -> *mut T {
101    Box::into_raw(Box::new(obj))
102}
103
104pub fn boxed_vec<T>(vec: Vec<T>) -> *mut T {
105    let mut slice = vec.into_boxed_slice();
106    let ptr = slice.as_mut_ptr();
107    mem::forget(slice);
108    ptr
109}
110
111/// # Safety
112pub unsafe fn unbox_any<T: ?Sized>(any: *mut T) -> Box<T> {
113    Box::from_raw(any)
114}
115
116/// # Safety
117pub unsafe fn unbox_string(data: *mut c_char) {
118    let _ = CString::from_raw(data);
119}
120
121/// # Safety
122pub unsafe fn unbox_vec<T>(vec: Vec<*mut T>) -> Vec<Box<T>> {
123    vec.iter().map(|&x| unbox_any(x)).collect()
124}
125
126/// # Safety
127pub unsafe fn unbox_any_vec<T>(vec: Vec<*mut T>) {
128    for &x in vec.iter() {
129        unbox_any(x);
130    }
131}
132
133/// # Safety
134pub unsafe fn unbox_any_vec_ptr<T>(ptr: *mut *mut T, count: usize) {
135    unbox_any_vec(unbox_vec_ptr(ptr, count));
136}
137
138/// # Safety
139pub unsafe fn unbox_vec_ptr<T>(ptr: *mut T, count: usize) -> Vec<T> {
140    Vec::from_raw_parts(ptr, count, count)
141}
142
143pub trait FFIVecConversion {
144    type Value: IntoIterator;
145    /// # Safety
146    unsafe fn decode(&self) -> Self::Value;
147    /// # Safety
148    unsafe fn encode(obj: Self::Value) -> *mut Self;
149}
150
151pub trait FFIMapConversion {
152    type Key;
153    type Value;
154    fn new() -> Self;
155    fn insert(&mut self, key: Self::Key, value: Self::Value);
156}
157
158impl<K: Ord, V> FFIMapConversion for BTreeMap<K, V> {
159    type Key = K;
160    type Value = V;
161    fn new() -> Self { BTreeMap::new() }
162    fn insert(&mut self, key: K, value: V) { BTreeMap::insert(self, key, value); }
163}
164
165impl<K: Hash + Eq, V> FFIMapConversion for HashMap<K, V> {
166    type Key = K;
167    type Value = V;
168    fn new() -> Self { HashMap::new() }
169    fn insert(&mut self, key: K, value: V) { HashMap::insert(self, key, value); }
170}
171
172/// # Safety
173pub unsafe fn from_primitive_vec<T: Clone>(vec: *mut T, count: usize) -> Vec<T> {
174    std::slice::from_raw_parts(vec, count).to_vec()
175}
176
177/// # Safety
178pub unsafe fn from_complex_vec<V, V2: FFIConversion<V>>(vec: *mut *mut V2, count: usize) -> Vec<V> {
179    (0..count)
180        .map(|i| FFIConversion::ffi_from(*vec.add(i)))
181        .collect()
182}
183
184/// # Safety
185pub unsafe fn to_complex_vec<T, U>(iter: impl Iterator<Item=T>) -> *mut *mut U
186    where U: FFIConversion<T> {
187    boxed_vec(iter.map(|o| <U as FFIConversion<T>>::ffi_to(o)).collect())
188}
189
190/// # Safety
191pub unsafe fn to_primitive_vec<T, U>(iter: impl Iterator<Item=T>) -> *mut U
192    where Vec<U>: FromIterator<T> {
193    boxed_vec(iter.collect())
194}
195
196
197
198/// # Safety
199pub unsafe fn fold_to_map<M, K, V, K2, V2>(
200    count: usize,
201    keys: *mut K,
202    values: *mut V,
203    key_converter: impl Fn(K) -> K2,
204    value_converter: impl Fn(V) -> V2) -> M
205    where
206        M: FFIMapConversion<Key=K2, Value=V2>,
207        K: Copy,
208        V: Copy {
209    (0..count).fold(M::new(), |mut acc, i| {
210        let key = key_converter(*keys.add(i));
211        let value = value_converter(*values.add(i));
212        acc.insert(key, value);
213        acc
214    })
215}
216
217/// # Safety
218pub unsafe fn fold_to_vec<M, V: Copy, V2>(count: usize, values: *mut V, value_converter: impl Fn(V) -> V2) -> Vec<V2> {
219    (0..count)
220        .map(|i| value_converter(*values.add(i)))
221        .collect()
222
223}
224
225/// # Safety
226pub unsafe fn fold_to_result<T, E, T2, E2>(
227    ok: *mut T,
228    error: *mut E,
229    key_converter: impl Fn(*mut T) -> T2,
230    value_converter: impl Fn(*mut E) -> E2) -> Result<T2, E2> {
231    if error.is_null() {
232        Ok(key_converter(ok))
233    } else {
234        Err(value_converter(error))
235    }
236}
237
238
239#[macro_export]
240macro_rules! impl_custom_conversion {
241    ($RustType:ty, $FFIType:ty, $from:expr, $to:expr) => {
242        impl From<&$FFIType> for $RustType {
243            fn from(value: &$FFIType) -> Self {
244                $from(value)
245            }
246        }
247        impl From<&$RustType> for $FFIType {
248            fn from(value: &$RustType) -> Self {
249                $to(value)
250            }
251        }
252        impl ferment_interfaces::FFIConversion<$RustType> for $FFIType {
253            unsafe fn ffi_from_const(ffi: *const Self) -> $RustType {
254                <$RustType>::from(&*ffi)
255            }
256            unsafe fn ffi_to_const(obj: $RustType) -> *const Self {
257                ferment_interfaces::boxed(<$FFIType>::from(&obj))
258            }
259        }
260    };
261}