ferment_interfaces/
lib.rs1pub 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
10pub type OpaqueContext = *const std::os::raw::c_void;
13
14pub type OpaqueContextMut = *mut std::os::raw::c_void;
15
16pub trait FFIConversion<T> {
19 unsafe fn ffi_from_const(ffi: *const Self) -> T;
21 unsafe fn ffi_to_const(obj: T) -> *const Self;
23 unsafe fn ffi_from(ffi: *mut Self) -> T {
25 Self::ffi_from_const(ffi)
26 }
27 unsafe fn ffi_to(obj: T) -> *mut Self {
29 Self::ffi_to_const(obj) as *mut _
30 }
31 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 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 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
111pub unsafe fn unbox_any<T: ?Sized>(any: *mut T) -> Box<T> {
113 Box::from_raw(any)
114}
115
116pub unsafe fn unbox_string(data: *mut c_char) {
118 let _ = CString::from_raw(data);
119}
120
121pub unsafe fn unbox_vec<T>(vec: Vec<*mut T>) -> Vec<Box<T>> {
123 vec.iter().map(|&x| unbox_any(x)).collect()
124}
125
126pub unsafe fn unbox_any_vec<T>(vec: Vec<*mut T>) {
128 for &x in vec.iter() {
129 unbox_any(x);
130 }
131}
132
133pub unsafe fn unbox_any_vec_ptr<T>(ptr: *mut *mut T, count: usize) {
135 unbox_any_vec(unbox_vec_ptr(ptr, count));
136}
137
138pub 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 unsafe fn decode(&self) -> Self::Value;
147 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
172pub 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
177pub 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
184pub 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
190pub 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
198pub 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
217pub 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
225pub 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}