foreign 0.4.0

Conversion between foreign and Rust types
Documentation
use std::alloc::Layout;
use std::ffi::c_void;
use std::ptr;

use crate::foreign::*;
use crate::r#impl::alloc;

macro_rules! foreign_copy_type {
    ($rust_type:ty, $foreign_type:ty) => {
        impl FreeForeign for $rust_type {
            type Foreign = $foreign_type;

            unsafe fn free_foreign(ptr: *mut Self::Foreign) {
                libc::free(ptr.cast::<c_void>());
            }
        }

        impl CloneToForeign for $rust_type {
            fn clone_to_foreign(&self) -> OwnedPointer<Self> {
                let layout = Layout::new::<Self::Foreign>();
                // SAFETY: we are copying into a freshly-allocated block
                unsafe {
                    let p = alloc::<Self::Foreign>(layout);
                    *p = *self as Self::Foreign;
                    OwnedPointer::new(p)
                }
            }
        }

        impl FromForeign for $rust_type {
            unsafe fn cloned_from_foreign(p: *const Self::Foreign) -> Self {
                *p
            }
        }

        impl BorrowForeign for $rust_type {
            type Storage<'a> = &'a Self;

            fn borrow_foreign(&self) -> BorrowedPointer<Self, Self::Storage<'_>> {
                // SAFETY: data behind a shared reference cannot move
                // as long as the reference is alive
                unsafe { BorrowedPointer::new_borrowed(self, |raw| raw) }
            }
        }

        impl BorrowForeignMut for $rust_type {
            type Storage<'a> = BorrowedStorage<'a, Self>;

            fn borrow_foreign_mut(&mut self) -> BorrowedMutPointer<Self, Self::Storage<'_>> {
                // SAFETY: the C representation of a primitive is itself
                unsafe { BorrowedMutPointer::new_borrowed(self, |raw| raw) }
            }
        }

        #[allow(clippy::undocumented_unsafe_blocks)]
        unsafe impl FixedAlloc for $rust_type {
            unsafe fn clone_into_foreign(dest: *mut Self::Foreign, src: &Self) {
                ptr::write(dest, *src)
            }

            unsafe fn clone_from_native_slice(dest: *mut Self::Foreign, src: &[Self]) {
                unsafe {
                    ptr::copy_nonoverlapping(src.as_ptr().cast::<Self::Foreign>(), dest, src.len());
                }
            }
        }
    };
}
foreign_copy_type!(bool, bool);
foreign_copy_type!(i8, i8);
foreign_copy_type!(u8, u8);
foreign_copy_type!(i16, i16);
foreign_copy_type!(u16, u16);
foreign_copy_type!(i32, i32);
foreign_copy_type!(u32, u32);
foreign_copy_type!(i64, i64);
foreign_copy_type!(u64, u64);
foreign_copy_type!(isize, libc::ptrdiff_t);
foreign_copy_type!(usize, libc::size_t);
foreign_copy_type!(f32, f32);
foreign_copy_type!(f64, f64);

#[allow(clippy::undocumented_unsafe_blocks)]
#[cfg(test)]
mod tests {
    use std::ptr;

    use crate::foreign::*;

    #[test]
    fn test_foreign_int_convert() {
        let i = 123i8;
        let p = i.clone_to_foreign();
        unsafe {
            assert_eq!(i, *p.as_ptr());
            assert_eq!(i, i8::cloned_from_foreign(p.as_ptr()));
        }
        assert_eq!(i, p.into_native());

        let p = i.clone_to_foreign();
        unsafe {
            assert_eq!(i, i8::from_foreign(p.into_inner()));
        }
    }

    #[test]
    fn test_foreign_int_borrow() {
        let i = 123i8;
        unsafe {
            assert_eq!(i, *i.borrow_foreign().as_ptr());
        }
        assert_eq!(i, 123i8);
    }

    #[test]
    fn test_foreign_int_borrow_clone_to_foreign() {
        let i = 123i8;
        let cloned = i.borrow_foreign().clone_to_foreign();
        assert_ne!(cloned.as_ptr(), ptr::addr_of!(i));
        unsafe { assert_eq!(*cloned.as_ptr(), 123i8) };
    }

    #[test]
    fn test_foreign_int_borrow_mut_clone_to_foreign() {
        let mut j = 123i8;
        let mut borrowed = j.borrow_foreign_mut();
        unsafe { *borrowed.as_mut_ptr() = 45i8 };
        let cloned = borrowed.clone_to_foreign();
        unsafe { assert_eq!(*cloned.as_ptr(), 45i8) };
    }

    #[test]
    fn test_foreign_int_borrow_mut() {
        let mut i = 123i8;
        let mut borrowed = i.borrow_foreign_mut();
        unsafe {
            assert_eq!(*borrowed.as_ptr(), 123i8);
            *borrowed.as_mut_ptr() = 45i8;
        }
        let borrowed = i.borrow_foreign_mut();
        unsafe {
            assert_eq!(*borrowed.as_ptr(), 45i8);
        }
        assert_eq!(i, 45i8);
    }
}