ffi_convert/
types.rs

1//! This module contains definitions of utility types that implement the [`CReprOf`], [`AsRust`], and [`CDrop`] traits.
2//!
3
4use ffi_convert_derive::RawPointerConverter;
5
6use std::any::TypeId;
7use std::ffi::{CStr, CString};
8use std::ops::Range;
9use std::ptr;
10
11use crate as ffi_convert;
12use crate::conversions::*;
13
14/// A utility type to represent arrays of string
15/// # Example
16///
17/// ```
18/// use ffi_convert::{CReprOf, CStringArray};
19/// let pizza_names = vec!["Diavola".to_string(), "Margarita".to_string(), "Regina".to_string()];
20/// let c_pizza_names = CStringArray::c_repr_of(pizza_names).expect("could not convert !");
21///
22/// ```
23#[repr(C)]
24#[derive(Debug, RawPointerConverter)]
25pub struct CStringArray {
26    /// Pointer to the first element of the array
27    pub data: *const *const libc::c_char,
28    /// Number of elements in the array
29    pub size: usize,
30}
31
32unsafe impl Sync for CStringArray {}
33
34impl AsRust<Vec<String>> for CStringArray {
35    fn as_rust(&self) -> Result<Vec<String>, AsRustError> {
36        let mut result = vec![];
37
38        let strings = unsafe {
39            std::slice::from_raw_parts_mut(self.data as *mut *mut libc::c_char, self.size)
40        };
41
42        for s in strings {
43            result.push(unsafe { CStr::raw_borrow(*s) }?.as_rust()?)
44        }
45
46        Ok(result)
47    }
48}
49
50impl CReprOf<Vec<String>> for CStringArray {
51    fn c_repr_of(input: Vec<String>) -> Result<Self, CReprOfError> {
52        Ok(Self {
53            size: input.len(),
54            data: Box::into_raw(
55                input
56                    .into_iter()
57                    .map::<Result<*const libc::c_char, CReprOfError>, _>(|s| {
58                        Ok(CString::c_repr_of(s)?.into_raw_pointer())
59                    })
60                    .collect::<Result<Vec<_>, _>>()?
61                    .into_boxed_slice(),
62            ) as *const *const libc::c_char,
63        })
64    }
65}
66
67impl CDrop for CStringArray {
68    fn do_drop(&mut self) -> Result<(), CDropError> {
69        unsafe {
70            let y = Box::from_raw(std::slice::from_raw_parts_mut(
71                self.data as *mut *mut libc::c_char,
72                self.size,
73            ));
74            for p in y.iter() {
75                let _ = CString::from_raw_pointer(*p)?; // let's not panic if we fail here
76            }
77        }
78        Ok(())
79    }
80}
81
82impl Drop for CStringArray {
83    fn drop(&mut self) {
84        let _ = self.do_drop();
85    }
86}
87
88/// A utility type to represent arrays of the parametrized type.
89/// Note that the parametrized type should have a C-compatible representation.
90///
91/// # Example
92///
93/// ```
94/// use ffi_convert::{CReprOf, AsRust, CDrop, CArray};
95/// use libc::c_char;
96///
97/// pub struct PizzaTopping {
98///     pub ingredient: String,
99/// }
100///
101/// #[derive(CDrop, CReprOf, AsRust)]
102/// #[target_type(PizzaTopping)]
103/// pub struct CPizzaTopping {
104///     pub ingredient: *const c_char
105/// }
106///
107/// let toppings = vec![
108///         PizzaTopping { ingredient: "Cheese".to_string() },
109///         PizzaTopping { ingredient: "Ham".to_string() } ];
110///
111/// let ctoppings = CArray::<CPizzaTopping>::c_repr_of(toppings);
112///
113/// ```
114#[repr(C)]
115#[derive(Debug)]
116pub struct CArray<T> {
117    /// Pointer to the first element of the array
118    pub data_ptr: *const T,
119    /// Number of elements in the array
120    pub size: usize,
121}
122
123impl<U: AsRust<V> + 'static, V> AsRust<Vec<V>> for CArray<U> {
124    fn as_rust(&self) -> Result<Vec<V>, AsRustError> {
125        let mut vec = Vec::with_capacity(self.size);
126
127        if self.size > 0 {
128            let values =
129                unsafe { std::slice::from_raw_parts_mut(self.data_ptr as *mut U, self.size) };
130
131            if is_primitive(TypeId::of::<U>()) {
132                unsafe {
133                    ptr::copy(values.as_ptr() as *const V, vec.as_mut_ptr(), self.size);
134                    vec.set_len(self.size);
135                }
136            } else {
137                for value in values {
138                    vec.push(value.as_rust()?);
139                }
140            }
141        }
142        Ok(vec)
143    }
144}
145
146impl<U: CReprOf<V> + CDrop, V: 'static> CReprOf<Vec<V>> for CArray<U> {
147    fn c_repr_of(input: Vec<V>) -> Result<Self, CReprOfError> {
148        let input_size = input.len();
149        let mut output: CArray<U> = CArray {
150            data_ptr: ptr::null(),
151            size: input_size,
152        };
153
154        if input_size > 0 {
155            if is_primitive(TypeId::of::<V>()) {
156                output.data_ptr = Box::into_raw(input.into_boxed_slice()) as *const U;
157            } else {
158                output.data_ptr = Box::into_raw(
159                    input
160                        .into_iter()
161                        .map(U::c_repr_of)
162                        .collect::<Result<Vec<_>, CReprOfError>>()
163                        .expect("Could not convert to C representation")
164                        .into_boxed_slice(),
165                ) as *const U;
166            }
167        } else {
168            output.data_ptr = ptr::null();
169        }
170        Ok(output)
171    }
172}
173
174impl<T> CDrop for CArray<T> {
175    fn do_drop(&mut self) -> Result<(), CDropError> {
176        if !self.data_ptr.is_null() {
177            let _ = unsafe {
178                Box::from_raw(std::slice::from_raw_parts_mut(
179                    self.data_ptr as *mut T,
180                    self.size,
181                ))
182            };
183        }
184        Ok(())
185    }
186}
187
188impl<T> Drop for CArray<T> {
189    fn drop(&mut self) {
190        let _ = self.do_drop();
191    }
192}
193
194impl<T> RawPointerConverter<CArray<T>> for CArray<T> {
195    fn into_raw_pointer(self) -> *const CArray<T> {
196        convert_into_raw_pointer(self)
197    }
198
199    fn into_raw_pointer_mut(self) -> *mut CArray<T> {
200        convert_into_raw_pointer_mut(self)
201    }
202
203    unsafe fn from_raw_pointer(
204        input: *const CArray<T>,
205    ) -> Result<Self, UnexpectedNullPointerError> {
206        take_back_from_raw_pointer(input)
207    }
208
209    unsafe fn from_raw_pointer_mut(
210        input: *mut CArray<T>,
211    ) -> Result<Self, UnexpectedNullPointerError> {
212        take_back_from_raw_pointer_mut(input)
213    }
214}
215
216fn is_primitive(id: TypeId) -> bool {
217    id == TypeId::of::<u8>()
218        || id == TypeId::of::<i8>()
219        || id == TypeId::of::<u16>()
220        || id == TypeId::of::<i16>()
221        || id == TypeId::of::<u32>()
222        || id == TypeId::of::<i32>()
223        || id == TypeId::of::<f32>()
224        || id == TypeId::of::<f64>()
225}
226
227/// A utility type to represent range.
228/// Note that the parametrized type T should have have `CReprOf` and `AsRust` trait implementated.
229///
230/// # Example
231///
232/// ```
233/// use ffi_convert::{CReprOf, AsRust, CDrop, CRange};
234/// use std::ops::Range;
235///
236/// #[derive(Clone, Debug, PartialEq)]
237/// pub struct Foo {
238///     pub range: Range<i32>
239/// }
240///
241/// #[derive(AsRust, CDrop, CReprOf, Debug, PartialEq)]
242/// #[target_type(Foo)]
243/// pub struct CFoo {
244///     pub range: CRange<i32>
245/// }
246///
247/// let foo = Foo {
248///     range: Range {
249///         start: 20,
250///         end: 30,
251///     }
252/// };
253///
254/// let c_foo = CFoo {
255///     range: CRange {
256///         start: 20,
257///         end: 30,
258///     }
259/// };
260///
261/// let c_foo_converted = CFoo::c_repr_of(foo.clone()).unwrap();
262/// assert_eq!(c_foo, c_foo_converted);
263///
264/// let foo_converted = c_foo.as_rust().unwrap();
265/// assert_eq!(foo_converted, foo);
266/// ```
267#[repr(C)]
268#[derive(Clone, Debug, PartialEq, Eq)]
269pub struct CRange<T> {
270    pub start: T,
271    pub end: T,
272}
273
274impl<U: AsRust<V>, V: PartialOrd + PartialEq> AsRust<Range<V>> for CRange<U> {
275    fn as_rust(&self) -> Result<Range<V>, AsRustError> {
276        Ok(Range {
277            start: self.start.as_rust()?,
278            end: self.end.as_rust()?,
279        })
280    }
281}
282
283impl<U: CReprOf<V> + CDrop, V: PartialOrd + PartialEq> CReprOf<Range<V>> for CRange<U> {
284    fn c_repr_of(input: Range<V>) -> Result<Self, CReprOfError> {
285        Ok(Self {
286            start: U::c_repr_of(input.start)?,
287            end: U::c_repr_of(input.end)?,
288        })
289    }
290}
291
292impl<T> CDrop for CRange<T> {
293    fn do_drop(&mut self) -> Result<(), CDropError> {
294        Ok(())
295    }
296}
297
298impl<T> Drop for CRange<T> {
299    fn drop(&mut self) {
300        let _ = self.do_drop();
301    }
302}