ffi_convert/
conversions.rs1use std::ffi::NulError;
2use std::str::Utf8Error;
3
4use thiserror::Error;
5
6macro_rules! impl_c_repr_of_for {
7 ($typ:ty) => {
8 impl CReprOf<$typ> for $typ {
9 fn c_repr_of(input: $typ) -> Result<$typ, CReprOfError> {
10 Ok(input)
11 }
12 }
13 };
14
15 ($from_typ:ty, $to_typ:ty) => {
16 impl CReprOf<$from_typ> for $to_typ {
17 fn c_repr_of(input: $from_typ) -> Result<$to_typ, CReprOfError> {
18 Ok(input as $to_typ)
19 }
20 }
21 };
22}
23
24macro_rules! impl_c_drop_for {
26 ($typ:ty) => {
27 impl CDrop for $typ {
28 fn do_drop(&mut self) -> Result<(), CDropError> {
29 Ok(())
30 }
31 }
32 };
33}
34
35macro_rules! impl_as_rust_for {
36 ($typ:ty) => {
37 impl AsRust<$typ> for $typ {
38 fn as_rust(&self) -> Result<$typ, AsRustError> {
39 Ok(*self)
40 }
41 }
42 };
43
44 ($from_typ:ty, $to_typ:ty) => {
45 impl AsRust<$to_typ> for $from_typ {
46 fn as_rust(&self) -> Result<$to_typ, AsRustError> {
47 Ok(*self as $to_typ)
48 }
49 }
50 };
51}
52
53macro_rules! impl_rawpointerconverter_for {
54 ($typ:ty) => {
55 impl RawPointerConverter<$typ> for $typ {
56 fn into_raw_pointer(self) -> *const $typ {
57 convert_into_raw_pointer(self)
58 }
59 fn into_raw_pointer_mut(self) -> *mut $typ {
60 convert_into_raw_pointer_mut(self)
61 }
62 unsafe fn from_raw_pointer(
63 input: *const $typ,
64 ) -> Result<Self, UnexpectedNullPointerError> {
65 take_back_from_raw_pointer(input)
66 }
67 unsafe fn from_raw_pointer_mut(
68 input: *mut $typ,
69 ) -> Result<Self, UnexpectedNullPointerError> {
70 take_back_from_raw_pointer_mut(input)
71 }
72 }
73 };
74}
75
76#[derive(Error, Debug)]
77pub enum CReprOfError {
78 #[error("A string contains a nul bit")]
79 StringContainsNullBit(#[from] NulError),
80 #[error("An error occurred during conversion to C repr; {}", .0)]
81 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
82}
83
84pub trait CReprOf<T>: Sized + CDrop {
87 fn c_repr_of(input: T) -> Result<Self, CReprOfError>;
88}
89
90#[derive(Error, Debug)]
91pub enum CDropError {
92 #[error("unexpected null pointer")]
93 NullPointer(#[from] UnexpectedNullPointerError),
94 #[error("An error occurred while dropping C struct: {}", .0)]
95 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
96}
97
98pub trait CDrop {
101 fn do_drop(&mut self) -> Result<(), CDropError>;
102}
103
104#[derive(Error, Debug)]
105pub enum AsRustError {
106 #[error("unexpected null pointer")]
107 NullPointer(#[from] UnexpectedNullPointerError),
108
109 #[error("could not convert string as it is not UTF-8: {}", .0)]
110 Utf8Error(#[from] Utf8Error),
111 #[error("An error occurred during conversion to Rust: {}", .0)]
112 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
113}
114
115pub trait AsRust<T> {
118 fn as_rust(&self) -> Result<T, AsRustError>;
119}
120
121#[derive(Error, Debug)]
122#[error("Could not use raw pointer: unexpected null pointer")]
123pub struct UnexpectedNullPointerError;
124
125pub trait RawPointerConverter<T>: Sized {
134 fn into_raw_pointer(self) -> *const T;
137 fn into_raw_pointer_mut(self) -> *mut T;
141 unsafe fn from_raw_pointer(input: *const T) -> Result<Self, UnexpectedNullPointerError>;
147 unsafe fn from_raw_pointer_mut(input: *mut T) -> Result<Self, UnexpectedNullPointerError>;
153
154 unsafe fn drop_raw_pointer(input: *const T) -> Result<(), UnexpectedNullPointerError> {
158 Self::from_raw_pointer(input).map(|_| ())
159 }
160
161 unsafe fn drop_raw_pointer_mut(input: *mut T) -> Result<(), UnexpectedNullPointerError> {
165 Self::from_raw_pointer_mut(input).map(|_| ())
166 }
167}
168
169#[doc(hidden)]
170pub fn convert_into_raw_pointer<T>(pointee: T) -> *const T {
171 Box::into_raw(Box::new(pointee)) as _
172}
173
174#[doc(hidden)]
175pub fn convert_into_raw_pointer_mut<T>(pointee: T) -> *mut T {
176 Box::into_raw(Box::new(pointee))
177}
178
179#[doc(hidden)]
180pub unsafe fn take_back_from_raw_pointer<T>(
181 input: *const T,
182) -> Result<T, UnexpectedNullPointerError> {
183 take_back_from_raw_pointer_mut(input as _)
184}
185
186#[doc(hidden)]
187pub unsafe fn take_back_from_raw_pointer_mut<T>(
188 input: *mut T,
189) -> Result<T, UnexpectedNullPointerError> {
190 if input.is_null() {
191 Err(UnexpectedNullPointerError)
192 } else {
193 Ok(*Box::from_raw(input))
194 }
195}
196
197pub trait RawBorrow<T> {
200 unsafe fn raw_borrow<'a>(input: *const T) -> Result<&'a Self, UnexpectedNullPointerError>;
204}
205
206pub trait RawBorrowMut<T> {
209 unsafe fn raw_borrow_mut<'a>(input: *mut T)
214 -> Result<&'a mut Self, UnexpectedNullPointerError>;
215}
216
217impl<T> RawBorrow<T> for T {
219 unsafe fn raw_borrow<'a>(input: *const T) -> Result<&'a Self, UnexpectedNullPointerError> {
220 input.as_ref().ok_or(UnexpectedNullPointerError)
221 }
222}
223
224impl<T> RawBorrowMut<T> for T {
226 unsafe fn raw_borrow_mut<'a>(
227 input: *mut T,
228 ) -> Result<&'a mut Self, UnexpectedNullPointerError> {
229 input.as_mut().ok_or(UnexpectedNullPointerError)
230 }
231}
232
233impl RawPointerConverter<libc::c_void> for std::ffi::CString {
234 fn into_raw_pointer(self) -> *const libc::c_void {
235 self.into_raw() as _
236 }
237
238 fn into_raw_pointer_mut(self) -> *mut libc::c_void {
239 self.into_raw() as _
240 }
241
242 unsafe fn from_raw_pointer(
243 input: *const libc::c_void,
244 ) -> Result<Self, UnexpectedNullPointerError> {
245 Self::from_raw_pointer_mut(input as *mut libc::c_void)
246 }
247
248 unsafe fn from_raw_pointer_mut(
249 input: *mut libc::c_void,
250 ) -> Result<Self, UnexpectedNullPointerError> {
251 if input.is_null() {
252 Err(UnexpectedNullPointerError)
253 } else {
254 Ok(std::ffi::CString::from_raw(input as *mut libc::c_char))
255 }
256 }
257}
258
259impl RawPointerConverter<libc::c_char> for std::ffi::CString {
260 fn into_raw_pointer(self) -> *const libc::c_char {
261 self.into_raw() as _
262 }
263
264 fn into_raw_pointer_mut(self) -> *mut libc::c_char {
265 self.into_raw()
266 }
267
268 unsafe fn from_raw_pointer(
269 input: *const libc::c_char,
270 ) -> Result<Self, UnexpectedNullPointerError> {
271 Self::from_raw_pointer_mut(input as *mut libc::c_char)
272 }
273
274 unsafe fn from_raw_pointer_mut(
275 input: *mut libc::c_char,
276 ) -> Result<Self, UnexpectedNullPointerError> {
277 if input.is_null() {
278 Err(UnexpectedNullPointerError)
279 } else {
280 Ok(std::ffi::CString::from_raw(input as *mut libc::c_char))
281 }
282 }
283}
284
285impl RawBorrow<libc::c_char> for std::ffi::CStr {
286 unsafe fn raw_borrow<'a>(
287 input: *const libc::c_char,
288 ) -> Result<&'a Self, UnexpectedNullPointerError> {
289 if input.is_null() {
290 Err(UnexpectedNullPointerError)
291 } else {
292 Ok(Self::from_ptr(input))
293 }
294 }
295}
296
297impl_c_drop_for!(usize);
298impl_c_drop_for!(i8);
299impl_c_drop_for!(u8);
300impl_c_drop_for!(i16);
301impl_c_drop_for!(u16);
302impl_c_drop_for!(i32);
303impl_c_drop_for!(u32);
304impl_c_drop_for!(i64);
305impl_c_drop_for!(u64);
306impl_c_drop_for!(f32);
307impl_c_drop_for!(f64);
308impl_c_drop_for!(bool);
309impl_c_drop_for!(std::ffi::CString);
310
311impl_c_repr_of_for!(usize);
312impl_c_repr_of_for!(i8);
313impl_c_repr_of_for!(u8);
314impl_c_repr_of_for!(i16);
315impl_c_repr_of_for!(u16);
316impl_c_repr_of_for!(i32);
317impl_c_repr_of_for!(u32);
318impl_c_repr_of_for!(i64);
319impl_c_repr_of_for!(u64);
320impl_c_repr_of_for!(f32);
321impl_c_repr_of_for!(f64);
322impl_c_repr_of_for!(bool);
323
324impl_c_repr_of_for!(usize, i32);
325
326impl CReprOf<String> for std::ffi::CString {
327 fn c_repr_of(input: String) -> Result<Self, CReprOfError> {
328 Ok(std::ffi::CString::new(input)?)
329 }
330}
331
332impl_as_rust_for!(usize);
333impl_as_rust_for!(i8);
334impl_as_rust_for!(u8);
335impl_as_rust_for!(i16);
336impl_as_rust_for!(u16);
337impl_as_rust_for!(i32);
338impl_as_rust_for!(u32);
339impl_as_rust_for!(i64);
340impl_as_rust_for!(u64);
341impl_as_rust_for!(f32);
342impl_as_rust_for!(f64);
343impl_as_rust_for!(bool);
344
345impl_as_rust_for!(i32, usize);
346
347impl AsRust<String> for std::ffi::CStr {
348 fn as_rust(&self) -> Result<String, AsRustError> {
349 self.to_str().map(|s| s.to_owned()).map_err(|e| e.into())
350 }
351}
352
353impl_rawpointerconverter_for!(usize);
354impl_rawpointerconverter_for!(i16);
355impl_rawpointerconverter_for!(u16);
356impl_rawpointerconverter_for!(i32);
357impl_rawpointerconverter_for!(u32);
358impl_rawpointerconverter_for!(i64);
359impl_rawpointerconverter_for!(u64);
360impl_rawpointerconverter_for!(f32);
361impl_rawpointerconverter_for!(f64);
362impl_rawpointerconverter_for!(bool);
363
364impl<U, T: CReprOf<U>, const N: usize> CReprOf<[U; N]> for [T; N]
365where
366 [T; N]: CDrop,
367{
368 fn c_repr_of(input: [U; N]) -> Result<[T; N], CReprOfError> {
369 let result_vec: Result<Vec<T>, CReprOfError> =
374 input.into_iter().map(T::c_repr_of).collect();
375 let vec = result_vec?;
376
377 assert_eq!(vec.len(), N);
378
379 let mut result: [T; N] = unsafe { std::mem::zeroed() }; for (i, t) in vec.into_iter().enumerate() {
382 result[i] = t;
383 }
384
385 Ok(result)
386 }
387}
388
389impl<T: CDrop, const N: usize> CDrop for [T; N] {
390 fn do_drop(&mut self) -> Result<(), CDropError> {
391 let result: Result<Vec<()>, CDropError> = self.iter_mut().map(T::do_drop).collect();
392 result?;
393 Ok(())
394 }
395}
396
397impl<U: AsRust<T>, T, const N: usize> AsRust<[T; N]> for [U; N] {
398 fn as_rust(&self) -> Result<[T; N], AsRustError> {
399 let result_vec: Result<Vec<T>, AsRustError> = self.iter().map(U::as_rust).collect();
404 let vec = result_vec?;
405
406 assert_eq!(vec.len(), N);
407
408 let mut result: [T; N] = unsafe { std::mem::zeroed() }; for (i, t) in vec.into_iter().enumerate() {
411 result[i] = t;
412 }
413
414 Ok(result)
415 }
416}