ffi_convert/
conversions.rs1use std::ffi::NulError;
2use std::mem::MaybeUninit;
3use std::str::Utf8Error;
4
5use thiserror::Error;
6
7#[derive(Error, Debug)]
9pub enum CReprOfError {
10 #[error("A string contains a nul bit")]
13 StringContainsNullBit(#[from] NulError),
14 #[error("An error occurred during conversion to C repr; {}", .0)]
16 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
17}
18
19pub trait CReprOf<T>: Sized + CDrop {
29 fn c_repr_of(input: T) -> Result<Self, CReprOfError>;
31}
32
33#[derive(Error, Debug)]
35pub enum CDropError {
36 #[error("unexpected null pointer")]
38 NullPointer(#[from] UnexpectedNullPointerError),
39 #[error("An error occurred while dropping C struct: {}", .0)]
41 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
42}
43
44pub trait CDrop {
57 fn do_drop(&mut self) -> Result<(), CDropError>;
61}
62
63#[derive(Error, Debug)]
65pub enum AsRustError {
66 #[error("unexpected null pointer")]
68 NullPointer(#[from] UnexpectedNullPointerError),
69 #[error("could not convert string as it is not UTF-8: {}", .0)]
71 Utf8Error(#[from] Utf8Error),
72 #[error("An error occurred during conversion to Rust: {}", .0)]
74 Other(#[from] Box<dyn std::error::Error + Send + Sync>),
75}
76
77pub trait AsRust<T> {
88 fn as_rust(&self) -> Result<T, AsRustError>;
90}
91
92#[derive(Error, Debug)]
94#[error("Could not use raw pointer: unexpected null pointer")]
95pub struct UnexpectedNullPointerError;
96
97pub trait RawPointerConverter<T>: Sized {
112 fn into_raw_pointer(self) -> *const T;
115 fn into_raw_pointer_mut(self) -> *mut T;
119 unsafe fn from_raw_pointer(input: *const T) -> Result<Self, UnexpectedNullPointerError>;
127 unsafe fn from_raw_pointer_mut(input: *mut T) -> Result<Self, UnexpectedNullPointerError>;
135
136 unsafe fn drop_raw_pointer(input: *const T) -> Result<(), UnexpectedNullPointerError> {
141 unsafe { Self::from_raw_pointer(input) }.map(|_| ())
142 }
143
144 unsafe fn drop_raw_pointer_mut(input: *mut T) -> Result<(), UnexpectedNullPointerError> {
149 unsafe { Self::from_raw_pointer_mut(input) }.map(|_| ())
150 }
151}
152
153#[doc(hidden)]
154pub fn convert_into_raw_pointer<T>(pointee: T) -> *const T {
155 Box::into_raw(Box::new(pointee)) as _
156}
157
158#[doc(hidden)]
159pub fn convert_into_raw_pointer_mut<T>(pointee: T) -> *mut T {
160 Box::into_raw(Box::new(pointee))
161}
162
163#[doc(hidden)]
164pub unsafe fn take_back_from_raw_pointer<T>(
165 input: *const T,
166) -> Result<T, UnexpectedNullPointerError> {
167 unsafe { take_back_from_raw_pointer_mut(input as _) }
168}
169
170#[doc(hidden)]
171pub unsafe fn take_back_from_raw_pointer_mut<T>(
172 input: *mut T,
173) -> Result<T, UnexpectedNullPointerError> {
174 if input.is_null() {
175 Err(UnexpectedNullPointerError)
176 } else {
177 Ok(*unsafe { Box::from_raw(input) })
178 }
179}
180
181pub trait RawBorrow<T> {
189 unsafe fn raw_borrow<'a>(input: *const T) -> Result<&'a Self, UnexpectedNullPointerError>;
197}
198
199pub trait RawBorrowMut<T> {
201 unsafe fn raw_borrow_mut<'a>(input: *mut T)
207 -> Result<&'a mut Self, UnexpectedNullPointerError>;
208}
209
210impl<T> RawBorrow<T> for T {
211 unsafe fn raw_borrow<'a>(input: *const T) -> Result<&'a Self, UnexpectedNullPointerError> {
212 unsafe { input.as_ref() }.ok_or(UnexpectedNullPointerError)
213 }
214}
215
216impl<T> RawBorrowMut<T> for T {
217 unsafe fn raw_borrow_mut<'a>(
218 input: *mut T,
219 ) -> Result<&'a mut Self, UnexpectedNullPointerError> {
220 unsafe { input.as_mut() }.ok_or(UnexpectedNullPointerError)
221 }
222}
223
224impl RawPointerConverter<std::ffi::c_void> for std::ffi::CString {
225 fn into_raw_pointer(self) -> *const std::ffi::c_void {
226 self.into_raw() as _
227 }
228
229 fn into_raw_pointer_mut(self) -> *mut std::ffi::c_void {
230 self.into_raw() as _
231 }
232
233 unsafe fn from_raw_pointer(
234 input: *const std::ffi::c_void,
235 ) -> Result<Self, UnexpectedNullPointerError> {
236 unsafe { Self::from_raw_pointer_mut(input as *mut std::ffi::c_void) }
237 }
238
239 unsafe fn from_raw_pointer_mut(
240 input: *mut std::ffi::c_void,
241 ) -> Result<Self, UnexpectedNullPointerError> {
242 if input.is_null() {
243 Err(UnexpectedNullPointerError)
244 } else {
245 Ok(unsafe { std::ffi::CString::from_raw(input as *mut std::ffi::c_char) })
246 }
247 }
248}
249
250impl RawPointerConverter<std::ffi::c_char> for std::ffi::CString {
251 fn into_raw_pointer(self) -> *const std::ffi::c_char {
252 self.into_raw() as _
253 }
254
255 fn into_raw_pointer_mut(self) -> *mut std::ffi::c_char {
256 self.into_raw()
257 }
258
259 unsafe fn from_raw_pointer(
260 input: *const std::ffi::c_char,
261 ) -> Result<Self, UnexpectedNullPointerError> {
262 unsafe { Self::from_raw_pointer_mut(input as *mut std::ffi::c_char) }
263 }
264
265 unsafe fn from_raw_pointer_mut(
266 input: *mut std::ffi::c_char,
267 ) -> Result<Self, UnexpectedNullPointerError> {
268 if input.is_null() {
269 Err(UnexpectedNullPointerError)
270 } else {
271 Ok(unsafe { std::ffi::CString::from_raw(input as *mut std::ffi::c_char) })
272 }
273 }
274}
275
276impl RawBorrow<std::ffi::c_char> for std::ffi::CStr {
277 unsafe fn raw_borrow<'a>(
278 input: *const std::ffi::c_char,
279 ) -> Result<&'a Self, UnexpectedNullPointerError> {
280 if input.is_null() {
281 Err(UnexpectedNullPointerError)
282 } else {
283 Ok(unsafe { Self::from_ptr(input) })
284 }
285 }
286}
287
288macro_rules! impl_noop_c_drop_for {
289 ($typ:ty) => {
290 impl CDrop for $typ {
291 fn do_drop(&mut self) -> Result<(), CDropError> {
292 Ok(())
293 }
294 }
295 };
296}
297
298impl_noop_c_drop_for!(usize);
299impl_noop_c_drop_for!(i8);
300impl_noop_c_drop_for!(u8);
301impl_noop_c_drop_for!(i16);
302impl_noop_c_drop_for!(u16);
303impl_noop_c_drop_for!(i32);
304impl_noop_c_drop_for!(u32);
305impl_noop_c_drop_for!(i64);
306impl_noop_c_drop_for!(u64);
307impl_noop_c_drop_for!(f32);
308impl_noop_c_drop_for!(f64);
309impl_noop_c_drop_for!(bool);
310impl_noop_c_drop_for!(std::ffi::CString);
311
312macro_rules! impl_c_repr_of_for {
313 ($typ:ty) => {
314 impl CReprOf<$typ> for $typ {
315 fn c_repr_of(input: $typ) -> Result<$typ, CReprOfError> {
316 Ok(input)
317 }
318 }
319 };
320
321 ($from_typ:ty, $to_typ:ty) => {
322 impl CReprOf<$from_typ> for $to_typ {
323 fn c_repr_of(input: $from_typ) -> Result<$to_typ, CReprOfError> {
324 Ok(input as $to_typ)
325 }
326 }
327 };
328}
329
330impl_c_repr_of_for!(usize);
331impl_c_repr_of_for!(i8);
332impl_c_repr_of_for!(u8);
333impl_c_repr_of_for!(i16);
334impl_c_repr_of_for!(u16);
335impl_c_repr_of_for!(i32);
336impl_c_repr_of_for!(u32);
337impl_c_repr_of_for!(i64);
338impl_c_repr_of_for!(u64);
339impl_c_repr_of_for!(f32);
340impl_c_repr_of_for!(f64);
341impl_c_repr_of_for!(bool);
342
343impl_c_repr_of_for!(usize, i32);
344
345impl CReprOf<String> for std::ffi::CString {
346 fn c_repr_of(input: String) -> Result<Self, CReprOfError> {
347 Ok(std::ffi::CString::new(input)?)
348 }
349}
350
351macro_rules! impl_as_rust_for {
352 ($typ:ty) => {
353 impl AsRust<$typ> for $typ {
354 fn as_rust(&self) -> Result<$typ, AsRustError> {
355 Ok(*self)
356 }
357 }
358 };
359
360 ($from_typ:ty, $to_typ:ty) => {
361 impl AsRust<$to_typ> for $from_typ {
362 fn as_rust(&self) -> Result<$to_typ, AsRustError> {
363 Ok(*self as $to_typ)
364 }
365 }
366 };
367}
368
369impl_as_rust_for!(usize);
370impl_as_rust_for!(i8);
371impl_as_rust_for!(u8);
372impl_as_rust_for!(i16);
373impl_as_rust_for!(u16);
374impl_as_rust_for!(i32);
375impl_as_rust_for!(u32);
376impl_as_rust_for!(i64);
377impl_as_rust_for!(u64);
378impl_as_rust_for!(f32);
379impl_as_rust_for!(f64);
380impl_as_rust_for!(bool);
381
382impl_as_rust_for!(i32, usize);
383
384impl AsRust<String> for std::ffi::CStr {
385 fn as_rust(&self) -> Result<String, AsRustError> {
386 self.to_str().map(|s| s.to_owned()).map_err(|e| e.into())
387 }
388}
389
390macro_rules! impl_rawpointerconverter_for {
391 ($typ:ty) => {
392 impl RawPointerConverter<$typ> for $typ {
393 fn into_raw_pointer(self) -> *const $typ {
394 convert_into_raw_pointer(self)
395 }
396 fn into_raw_pointer_mut(self) -> *mut $typ {
397 convert_into_raw_pointer_mut(self)
398 }
399 unsafe fn from_raw_pointer(
400 input: *const $typ,
401 ) -> Result<Self, UnexpectedNullPointerError> {
402 unsafe { take_back_from_raw_pointer(input) }
403 }
404 unsafe fn from_raw_pointer_mut(
405 input: *mut $typ,
406 ) -> Result<Self, UnexpectedNullPointerError> {
407 unsafe { take_back_from_raw_pointer_mut(input) }
408 }
409 }
410 };
411}
412
413impl_rawpointerconverter_for!(usize);
414impl_rawpointerconverter_for!(i16);
415impl_rawpointerconverter_for!(u16);
416impl_rawpointerconverter_for!(i32);
417impl_rawpointerconverter_for!(u32);
418impl_rawpointerconverter_for!(i64);
419impl_rawpointerconverter_for!(u64);
420impl_rawpointerconverter_for!(f32);
421impl_rawpointerconverter_for!(f64);
422impl_rawpointerconverter_for!(bool);
423
424impl<U, T: CReprOf<U>, const N: usize> CReprOf<[U; N]> for [T; N]
425where
426 [T; N]: CDrop,
427{
428 fn c_repr_of(values: [U; N]) -> Result<[T; N], CReprOfError> {
429 let mut array: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
430
431 for (n, value) in values.into_iter().enumerate() {
432 let item = &mut array[n];
433
434 match T::c_repr_of(value) {
435 Ok(value) => {
436 item.write(value);
437 }
438 Err(err) => {
439 for item in &mut array[0..n] {
441 unsafe {
443 let _ = item.assume_init_mut().do_drop();
444 }
445 }
446
447 return Err(err);
448 }
449 }
450 }
451
452 let array = unsafe {
454 (&raw const array).cast::<[T; N]>().read()
456 };
457 Ok(array)
458 }
459}
460
461impl<T: CDrop, const N: usize> CDrop for [T; N] {
462 fn do_drop(&mut self) -> Result<(), CDropError> {
463 let mut result = Ok(());
464
465 for value in self {
466 if let Err(err) = value.do_drop()
467 && result.is_ok()
468 {
469 result = Err(err);
470 }
471 }
472
473 result
474 }
475}
476
477impl<U: AsRust<T>, T, const N: usize> AsRust<[T; N]> for [U; N] {
478 fn as_rust(&self) -> Result<[T; N], AsRustError> {
479 let mut array: [MaybeUninit<T>; N] = [const { MaybeUninit::uninit() }; N];
480
481 for (n, value) in self.iter().enumerate() {
482 let item = &mut array[n];
483
484 match value.as_rust() {
485 Ok(value) => {
486 item.write(value);
487 }
488 Err(err) => {
489 for item in &mut array[0..n] {
491 unsafe {
493 item.assume_init_drop();
494 }
495 }
496
497 return Err(err);
498 }
499 }
500 }
501
502 let array = unsafe {
504 (&raw const array).cast::<[T; N]>().read()
506 };
507 Ok(array)
508 }
509}