ferment/
lib.rs

1pub mod fermented;
2
3use std::collections::{BTreeMap, HashMap};
4use std::ffi::CString;
5use std::hash::Hash;
6use std::mem;
7use std::os::raw::c_char;
8
9/// We pass here main context of parent program
10///
11pub trait FFIConversionFrom<T> {
12    /// # Safety
13    unsafe fn ffi_from_const(ffi: *const Self) -> T;
14    /// # Safety
15    unsafe fn ffi_from(ffi: *mut Self) -> T {
16        Self::ffi_from_const(ffi.cast_const())
17    }
18    /// # Safety
19    unsafe fn ffi_from_opt(ffi: *mut Self) -> Option<T> {
20        (!ffi.is_null())
21            .then(|| Self::ffi_from(ffi))
22    }
23}
24
25pub trait FFIConversionTo<T> {
26    /// # Safety
27    unsafe fn ffi_to_const(obj: T) -> *const Self;
28    /// # Safety
29    unsafe fn ffi_to(obj: T) -> *mut Self {
30        Self::ffi_to_const(obj)
31            .cast_mut()
32    }
33    /// # Safety
34    unsafe fn ffi_to_opt(obj: Option<T>) -> *mut Self where Self: Sized {
35        if let Some(o) = obj {
36            Self::ffi_to(o)
37        } else {
38            std::ptr::null_mut()
39        }
40    }
41}
42pub fn black_hole<T>(_obj: T) {}
43pub fn bypass<T>(obj: T) -> T { obj }
44
45pub fn boxed<T>(obj: T) -> *mut T {
46    Box::into_raw(Box::new(obj))
47}
48pub fn boxed_vec<T>(vec: Vec<T>) -> *mut T {
49    let mut slice = vec.into_boxed_slice();
50    let ptr = slice.as_mut_ptr();
51    mem::forget(slice);
52    ptr
53}
54pub fn boxed_arr<const N: usize, T: Clone>(arr: [T; N]) -> *mut T {
55    boxed_vec(arr.to_vec())
56}
57pub fn boxed_slice<T: Clone>(slice: &[T]) -> *mut T {
58    boxed_vec(slice.to_vec())
59}
60
61/// # Safety
62pub unsafe fn unbox_any<T: ?Sized>(any: *mut T) {
63    if !any.is_null() {
64        let _ = Box::from_raw(any);
65    }
66}
67/// # Safety
68pub unsafe fn unbox_any_opt<T: ?Sized>(any: *mut T) {
69    if !any.is_null() {
70        let _ = Box::from_raw(any);
71    }
72}
73
74/// # Safety
75pub unsafe fn unbox_string(data: *mut c_char) {
76    if data.is_null() {
77        return;
78    }
79    let _ = CString::from_raw(data);
80}
81
82/// # Safety
83pub unsafe fn unbox_any_vec<T>(vec: Vec<*mut T>) {
84    // TODO: that's wrong, need to make unbox_any composable of arbitrary type -> unbox_any_vec_composer
85    if vec.is_empty() {
86        return;
87    }
88    for &x in vec.iter() {
89        unbox_any(x);
90    }
91}
92/// # Safety
93pub unsafe fn unbox_any_vec_composer<T, U: Fn(*mut T)>(vec: Vec<*mut T>, composer: U) {
94    if vec.is_empty() {
95        return;
96    }
97    for &x in vec.iter() {
98        composer(x);
99    }
100}
101
102/// # Safety
103pub unsafe fn unbox_any_vec_ptr<T>(ptr: *mut *mut T, count: usize) {
104    unbox_group(ptr, count, unbox_any);
105}
106
107/// # Safety
108pub unsafe fn unbox_vec_ptr<T>(ptr: *mut T, count: usize) -> Vec<T> {
109    Vec::from_raw_parts(ptr, count, count)
110}
111
112/// # Safety
113/// Generalized function to free FFI-style arrays of either values or pointers.
114/// You control how each element is freed via `item_destructor`.
115pub unsafe fn unbox_group<T>(ptr: *mut T, count: usize, item_destructor: unsafe fn(T)) {
116    if ptr.is_null() || count == 0 {
117        return;
118    }
119    // SAFETY: We take ownership of the memory
120    let vec_of_ptr = unbox_vec_ptr(ptr, count);
121    if vec_of_ptr.is_empty() {
122        return;
123    }
124    for item in vec_of_ptr {
125        item_destructor(item);
126    }
127}
128
129
130/// # Safety
131pub unsafe fn from_opt_primitive<T: Copy>(ptr: *mut T) -> Option<T> {
132    (!ptr.is_null()).then(|| *ptr)
133}
134
135/// # Safety
136pub unsafe fn to_opt_primitive<T>(obj: Option<T>) -> *mut T {
137    obj.map_or(std::ptr::null_mut(), |o| boxed(o))
138}
139
140/// # Safety
141pub unsafe fn from_opt_opaque<T>(ptr: *mut T) -> Option<T> {
142    (!ptr.is_null()).then(|| std::ptr::read(ptr))
143}
144
145/// # Safety
146pub unsafe fn to_opt_opaque<T>(obj: Option<T>) -> *mut T {
147    obj.map_or(std::ptr::null_mut(), |o| boxed(o))
148}
149
150/// # Safety
151pub unsafe fn destroy_opt_primitive<T: Copy>(ptr: *mut T) {
152    if !ptr.is_null() {
153        unbox_any(ptr);
154    }
155}
156
157pub trait FFIMapConversion {
158    type Key;
159    type Value;
160    fn new() -> Self;
161    fn insert(&mut self, key: Self::Key, value: Self::Value);
162    fn count(&self) -> usize;
163}
164
165impl<K: Ord, V> FFIMapConversion for BTreeMap<K, V> {
166    type Key = K;
167    type Value = V;
168    fn new() -> Self { BTreeMap::new() }
169    fn insert(&mut self, key: K, value: V) { BTreeMap::insert(self, key, value); }
170
171    fn count(&self) -> usize {
172        self.len()
173    }
174}
175
176impl<K: Hash + Eq, V> FFIMapConversion for HashMap<K, V> {
177    type Key = K;
178    type Value = V;
179    fn new() -> Self { HashMap::new() }
180    fn insert(&mut self, key: K, value: V) { HashMap::insert(self, key, value); }
181
182    fn count(&self) -> usize {
183        self.len()
184    }
185}
186
187impl<K: Hash + Eq, V> FFIMapConversion for indexmap::IndexMap<K, V> {
188    type Key = K;
189    type Value = V;
190    fn new() -> Self { indexmap::IndexMap::new() }
191    fn insert(&mut self, key: K, value: V) { indexmap::IndexMap::insert(self, key, value); }
192
193    fn count(&self) -> usize {
194        self.len()
195    }
196}
197
198impl FFIMapConversion for serde_json::Map<String, serde_json::Value> {
199    type Key = String;
200    type Value = serde_json::Value;
201
202    fn new() -> Self {
203        serde_json::Map::new()
204    }
205
206    fn insert(&mut self, key: Self::Key, value: Self::Value) {
207        serde_json::Map::insert(self, key, value);
208    }
209
210    fn count(&self) -> usize {
211        self.len()
212    }
213}
214
215/// # Safety
216pub unsafe fn from_group<Iter, FFIType, TargetType>(
217    count: usize,
218    ptr: *mut FFIType,
219    mut converter: impl FnMut(*mut FFIType) -> TargetType,
220) -> Iter
221where Iter: FromIterator<TargetType> {
222    (0..count)
223        .map(|i| converter(ptr.add(i)))
224        .collect()
225}
226
227/// # Safety
228pub unsafe fn from_primitive_group<Iter, T: Copy>(ptr: *mut T, count: usize) -> Iter
229where Iter: FromIterator<T> {
230    from_group(count, ptr, |p| *p)
231}
232/// # Safety
233pub unsafe fn from_opt_primitive_group<Iter, T: Copy>(ptr: *mut *mut T, count: usize) -> Iter
234where Iter: FromIterator<Option<T>> {
235    from_group(count, ptr, |p| {
236        let inner = *p;
237        (!inner.is_null()).then(|| *inner)
238    })
239}
240
241/// # Safety
242pub unsafe fn from_opt_opaque_group<Iter, T>(ptr: *mut *mut T, count: usize) -> Iter
243where Iter: FromIterator<Option<T>> {
244    from_group(count, ptr, |p| {
245        let inner = *p;
246        (!inner.is_null()).then(|| std::ptr::read(inner))
247    })
248}
249/// # Safety
250pub unsafe fn from_opaque_group<Iter, T>(ptr: *mut *mut T, count: usize) -> Iter
251where Iter: FromIterator<T> {
252    from_group(count, ptr, |p| std::ptr::read(*p))
253}
254
255/// # Safety
256pub unsafe fn from_complex_group<Iter, T, FFI>(ptr: *mut *mut FFI, count: usize) -> Iter
257where Iter: FromIterator<T>,
258      FFI: FFIConversionFrom<T> {
259    from_group(count, ptr, |p| FFIConversionFrom::ffi_from(*p))
260}
261
262/// # Safety
263pub unsafe fn from_opt_complex_group<Iter, T, FFI>(ptr: *mut *mut FFI, count: usize) -> Iter
264where
265    Iter: FromIterator<Option<T>>,
266    FFI: FFIConversionFrom<T>,
267{
268    from_group(count, ptr, |p| FFIConversionFrom::ffi_from_opt(*p))
269}
270
271/// # Safety
272pub unsafe fn to_group<Iter, TargetType, FFIType>(iter: Iter, converter: fn(TargetType) -> FFIType) -> *mut FFIType
273    where Iter: Iterator<Item=TargetType> {
274    boxed_vec(iter.map(converter).collect())
275}
276
277/// # Safety
278pub unsafe fn to_complex_group<Iter, TargetType, FFIType>(iter: Iter) -> *mut *mut FFIType
279    where Iter: Iterator<Item=TargetType>,
280          FFIType: FFIConversionTo<TargetType> {
281    to_group(iter, |o| <FFIType as FFIConversionTo<TargetType>>::ffi_to(o))
282}
283/// # Safety
284pub unsafe fn to_opt_complex_group<Iter, TargetType, FFIType>(iter: Iter) -> *mut *mut FFIType
285    where Iter: Iterator<Item=Option<TargetType>>,
286          FFIType: FFIConversionTo<TargetType> {
287    to_group(iter, |o| <FFIType as FFIConversionTo<TargetType>>::ffi_to_opt(o))
288}
289
290/// # Safety
291pub unsafe fn to_primitive_group<Iter, TargetType>(iter: Iter) -> *mut TargetType
292    where Iter: Iterator<Item=TargetType>,
293          TargetType: Copy {
294    to_group(iter, |o| o)
295}
296/// # Safety
297pub unsafe fn to_opt_primitive_group<Iter, TargetType>(iter: Iter) -> *mut *mut TargetType
298    where Iter: Iterator<Item=Option<TargetType>>,
299          Vec<*mut TargetType>: FromIterator<*mut TargetType> {
300    to_group(iter, |o| o.map_or(std::ptr::null_mut(), |o| boxed(o)))
301}
302/// # Safety
303pub unsafe fn to_opt_opaque_group<Iter, TargetType>(iter: Iter) -> *mut *mut TargetType
304    where Iter: Iterator<Item=Option<TargetType>>,
305          Vec<*mut TargetType>: FromIterator<*mut TargetType> {
306    to_group(iter, |o| o.map_or(std::ptr::null_mut(), |o| boxed(o)))
307}
308/// # Safety
309pub unsafe fn to_opaque_group<Iter, TargetType>(iter: Iter) -> *mut *mut TargetType
310    where Iter: Iterator<Item=TargetType>,
311          Vec<*mut TargetType>: FromIterator<*mut TargetType> {
312    to_group(iter, |o| boxed(o))
313}
314
315
316pub fn to_map<TargetKey, TargetValue, FFIKey, FFIValue, Map, ToKey, ToValue>(obj: Map, key_converter: ToKey, value_converter: ToValue) -> (usize, *mut FFIKey, *mut FFIValue)
317where Map: FFIMapConversion<Key=TargetKey, Value=TargetValue> + IntoIterator<Item= (TargetKey, TargetValue)>,
318      ToKey: Fn(TargetKey) -> FFIKey,
319      ToValue: Fn(TargetValue) -> FFIValue {
320    let count = obj.count();
321    let (keys, values) = obj.into_iter().map(|(key, value)| (key_converter(key), value_converter(value))).unzip();
322    (count, boxed_vec(keys), boxed_vec(values))
323}
324
325/// # Safety
326pub unsafe fn fold_to_map<M, K, V, K2, V2>(
327    count: usize,
328    keys: *mut K,
329    values: *mut V,
330    key_converter: impl Fn(K) -> K2,
331    value_converter: impl Fn(V) -> V2) -> M
332    where
333        M: FFIMapConversion<Key=K2, Value=V2>,
334        K: Copy,
335        V: Copy {
336    (0..count).fold(M::new(), |mut acc, i| {
337        let key = key_converter(*keys.add(i));
338        let value = value_converter(*values.add(i));
339        acc.insert(key, value);
340        acc
341    })
342}
343
344/// # Safety
345pub unsafe fn fold_to_vec<M, V: Copy, V2>(count: usize, values: *mut V, value_converter: impl Fn(V) -> V2) -> Vec<V2> {
346    (0..count)
347        .map(|i| value_converter(*values.add(i)))
348        .collect()
349}
350
351/// # Safety
352/// # Safety
353/// Convert a pair of optional ok/error pointers into a `Result` using provided converters.
354///
355/// When both pointers are null, this prefers interpreting the value as `Err(error_converter(null))`.
356/// This supports encodings like `Result<T, Option<E>>` where `Err(None)` is represented by both
357/// pointers being null. If you need to prefer `Ok` on both-null (e.g. `Result<Option<T>, E>`),
358/// use `fold_to_result_prefer_ok` instead.
359pub unsafe fn fold_to_result<T, E, T2, E2>(
360    ok: *mut T,
361    ok_converter: impl Fn(*mut T) -> T2,
362    error: *mut E,
363    error_converter: impl Fn(*mut E) -> E2,
364) -> Result<T2, E2> {
365    if !error.is_null() {
366        Err(error_converter(error))
367    } else if !ok.is_null() {
368        Ok(ok_converter(ok))
369    } else {
370        Err(error_converter(error))
371    }
372}
373
374/// # Safety
375/// Variant that prefers `Ok` when both pointers are null. Useful for
376/// `Result<Option<T>, E>` encodings where `Ok(None)` is represented by a null ok pointer.
377pub unsafe fn fold_to_result_prefer_ok<T, E, T2, E2>(
378    ok: *mut T,
379    ok_converter: impl Fn(*mut T) -> T2,
380    error: *mut E,
381    error_converter: impl Fn(*mut E) -> E2,
382) -> Result<T2, E2> {
383    if error.is_null() {
384        Ok(ok_converter(ok))
385    } else {
386        Err(error_converter(error))
387    }
388}
389/// # Safety
390pub unsafe fn to_result<T, E, T2, E2>(
391    result: Result<T2, E2>,
392    ok_converter: impl Fn(T2) -> *mut T,
393    error_converter: impl Fn(E2) -> *mut E,
394) -> (*mut T, *mut E) {
395    match result {
396        Ok(o) => (ok_converter(o), std::ptr::null_mut()),
397        Err(o) => (std::ptr::null_mut(), error_converter(o))
398    }
399}
400
401// /// # Safety
402// pub unsafe fn ffi_from_cow<'a, T, E, T2, E2>(
403//     value: *mut T, converter: impl Fn(*mut T) -> T2,
404//     error: *mut E, error_converter: impl Fn(*mut E) -> E2) -> Cow<'a, E2> {
405//     if error.is_null() {
406//         Ok(ok_converter(ok))
407//     } else {
408//         Err(error_converter(error))
409//     }
410// }
411// /// # Safety
412// pub unsafe fn ffi_to_cow<T, E, T2, E2>(
413//     result: Result<T2, E2>,
414//     ok_converter: impl Fn(T2) -> *mut T,
415//     error_converter: impl Fn(E2) -> *mut E,
416// ) -> (*mut T, *mut E) {
417//     match result {
418//         Ok(o) => (ok_converter(o), std::ptr::null_mut()),
419//         Err(o) => (std::ptr::null_mut(), error_converter(o))
420//     }
421// }
422
423#[macro_export]
424macro_rules! impl_custom_conversion {
425    ($RustType:ty, $FFIType:ty, $from:expr, $to:expr) => {
426        impl From<&$FFIType> for $RustType {
427            fn from(value: &$FFIType) -> Self {
428                $from(value)
429            }
430        }
431        impl From<&$RustType> for $FFIType {
432            fn from(value: &$RustType) -> Self {
433                $to(value)
434            }
435        }
436
437        impl ferment::FFIConversionFrom<$RustType> for $FFIType {
438            unsafe fn ffi_from_const(ffi: *const Self) -> $RustType {
439                <$RustType>::from(&*ffi)
440            }
441        }
442        impl ferment::FFIConversionTo<$RustType> for $FFIType {
443            unsafe fn ffi_to_const(obj: $RustType) -> *const Self {
444                ferment::boxed(<$FFIType>::from(&obj))
445            }
446        }
447    };
448}
449
450#[macro_export]
451macro_rules! impl_custom_conversion2 {
452    ($RustType:ty, $FFIType:ident { $($field_name:ident: $field_type:ty),* $(,)? }, $from:expr, $to:expr) => {
453        #[allow(non_camel_case_types)]
454        #[ferment_macro::register($RustType)]
455        pub struct $FFIType {
456            $(pub $field_name: $field_type),*
457        }
458        impl From<&$FFIType> for $RustType {
459            fn from(value: &$FFIType) -> Self {
460                $from(value)
461            }
462        }
463        impl From<&$RustType> for $FFIType {
464            fn from(value: &$RustType) -> Self {
465                $to(value)
466            }
467        }
468        impl ferment::FFIConversionFrom<$RustType> for $FFIType {
469            unsafe fn ffi_from_const(ffi: *const Self) -> $RustType {
470                <$RustType>::from(&*ffi)
471            }
472        }
473        impl ferment::FFIConversionTo<$RustType> for $FFIType {
474            unsafe fn ffi_to_const(obj: $RustType) -> *const Self {
475                ferment::boxed(<$FFIType>::from(&obj))
476            }
477        }
478    };
479}
480#[macro_export]
481macro_rules! impl_cloneable_ferment {
482    ($ty:path, $ffitype:ident) => {
483        impl ferment::FFIConversionFrom<$ty> for $ffitype {
484            unsafe fn ffi_from_const(ffi: *const Self) -> $ty {
485                let ffi = &*ffi;
486                let raw = &*ffi.0;
487                raw.clone()
488            }
489        }
490        impl ferment::FFIConversionTo<$ty> for $ffitype {
491            unsafe fn ffi_to_const(obj: $ty) -> *const Self {
492                ferment::boxed(Self(ferment::boxed(obj)))
493            }
494        }
495        impl Drop for $ffitype {
496            fn drop(&mut self) {
497                unsafe {
498                    ferment::unbox_any(self.0);
499                }
500            }
501        }
502    };
503}
504
505/// # Safety
506pub unsafe fn to_arc<T: ?Sized>(obj: std::sync::Arc<T>) -> *mut T {
507    std::sync::Arc::into_raw(obj).cast_mut()
508}
509/// # Safety
510pub unsafe fn from_arc<T: ?Sized>(obj: *const T) -> std::sync::Arc<T> {
511    std::sync::Arc::from_raw(obj)
512}