foreign 0.4.0

Conversion between foreign and Rust types
Documentation
use crate::foreign::*;

impl<T> FreeForeign for Vec<T>
where
    [T]: FreeForeign,
{
    type Foreign = <[T] as FreeForeign>::Foreign;

    unsafe fn free_foreign(x: *mut Self::Foreign) {
        <[T]>::free_foreign(x)
    }
}

impl<T> CloneToForeign for Vec<T>
where
    [T]: CloneToForeign,
{
    fn clone_to_foreign(&self) -> OwnedPointer<Self> {
        (**self).clone_to_foreign().into()
    }
}

impl<T> BorrowForeign for Vec<T>
where
    [T]: BorrowForeign,
{
    type Storage<'a>
        = <[T] as BorrowForeign>::Storage<'a>
    where
        Self: 'a;

    fn borrow_foreign(&self) -> BorrowedPointer<Self, Self::Storage<'_>> {
        (**self).borrow_foreign().into()
    }
}

impl<T> IntoForeign for Vec<T>
where
    [T]: BorrowForeignMut,
{
    type Storage = Self;

    fn into_foreign(mut self) -> BorrowedMutPointer<Self, Self> {
        let p = self.borrow_foreign_mut().as_mut_ptr();
        // SAFETY: The pointer remains valid because the Vec always dereferences
        // to the same value
        unsafe { BorrowedMutPointer::new(p, self) }
    }
}

impl<T> BorrowForeignMut for Vec<T>
where
    [T]: BorrowForeignMut,
{
    type Storage<'a>
        = <[T] as BorrowForeignMut>::Storage<'a>
    where
        Self: 'a;

    fn borrow_foreign_mut(&mut self) -> BorrowedMutPointer<Self, Self::Storage<'_>> {
        (**self).borrow_foreign_mut().into()
    }
}

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

    use crate::foreign::*;
    use crate::r#impl::tests::PrimitiveWithLifetime;

    #[test]
    fn test_vec() {
        // A vec can be produced if a slice type for the elements has the capability.
        let v: Vec<u8> = vec![1, 2, 3];
        let bstr = b"\x01\x02\x03";
        let cloned = v.clone_to_foreign();
        unsafe {
            assert_eq!(
                libc::memcmp(
                    cloned.as_ptr().cast::<c_void>(),
                    bstr.as_ptr().cast::<c_void>(),
                    bstr.len()
                ),
                0
            );
        }
    }

    #[test]
    fn test_vec_borrow() {
        // A vec can be produced if a slice type for the elements has the capability.
        let v: Vec<u8> = vec![0x31, 0x41, 0x59];
        let bstr = b"\x31\x41\x59";
        let borrowed = v.borrow_foreign();
        unsafe {
            assert_eq!(
                libc::memcmp(
                    borrowed.as_ptr().cast::<c_void>(),
                    bstr.as_ptr().cast::<c_void>(),
                    bstr.len()
                ),
                0
            );
        }
    }

    #[test]
    fn test_vec_borrow_clone_to_foreign() {
        // A Vec's borrow stores &[T], not &Vec<T>, so it is only reachable
        // because the implementation is blanket over any storage that has a
        // C representation.
        let v: Vec<u8> = vec![1, 2, 3];
        let p = v.borrow_foreign().clone_to_foreign_ptr();
        unsafe {
            assert_eq!(
                libc::memcmp(p.cast::<c_void>(), v.as_ptr().cast::<c_void>(), 3),
                0
            );
            assert_ne!(p.cast_const(), v.as_ptr());
            libc::free(p.cast::<c_void>());
        }
    }

    #[test]
    fn test_vec_borrow_mut_write() {
        // The sequence that a &mut Self storage could not survive: borrow
        // exclusively, write through the pointer, then read the storage.
        // Two raw pointers from the same borrow do not invalidate each
        // other, so this is fine under stacked borrows.
        let mut v: Vec<u8> = vec![1, 2, 3];
        let mut borrowed = v.borrow_foreign_mut();
        unsafe {
            ptr::write(borrowed.as_mut_ptr().offset(1), 0xFF);
            assert_eq!(*(borrowed.as_ptr().offset(1)), 0xFF);
        }
        let cloned = borrowed.clone_to_foreign();
        unsafe {
            assert_eq!(*cloned.as_ptr(), 1);
            assert_eq!(*cloned.as_ptr().offset(1), 0xFF);
            assert_eq!(*cloned.as_ptr().offset(2), 3);
        }
    }

    #[test]
    fn test_vec_into_foreign_write() {
        // into_foreign() hands back a *mutable* pointer, so writing through
        // it is the point; the storage has to survive that.  A Vec in the
        // storage does, unlike a Box -- see BoxStorage.
        let v: Vec<u8> = vec![1, 2, 3];
        let mut consumed = v.into_foreign();
        unsafe {
            ptr::write(consumed.as_mut_ptr().offset(1), 0xFF);
            assert_eq!(*consumed.as_ptr().offset(1), 0xFF);
        }
        // and then read the storage
        let cloned = consumed.clone_to_foreign();
        unsafe { assert_eq!(*cloned.as_ptr().offset(1), 0xFF) };
    }

    #[test]
    fn test_vec_into_foreign() {
        // A vec can be produced if a slice type for the elements can be borrowed.
        let v: Vec<u8> = vec![0x21, 0x78, 0x28];
        let bstr = b"\x21\x78\x28";
        let consumed = v.into_foreign();
        unsafe {
            assert_eq!(
                libc::memcmp(
                    consumed.as_ptr().cast::<c_void>(),
                    bstr.as_ptr().cast::<c_void>(),
                    bstr.len()
                ),
                0
            );
        }
    }

    #[test]
    fn test_vec_into_foreign_with_lifetime() {
        let n = 7u8;
        let v: Vec<PrimitiveWithLifetime> = vec![PrimitiveWithLifetime::new(&n)];
        let consumed = v.into_foreign();
        unsafe { assert_eq!((*consumed.as_ptr()).0, 7) };
    }

    #[test]
    fn test_vec_into_foreign_clone_to_foreign() {
        let v: Vec<u8> = vec![1, 2, 3];
        let consumed = v.into_foreign();
        let cloned = consumed.clone_to_foreign();
        assert_ne!(cloned.as_ptr(), consumed.as_ptr());
        unsafe {
            assert_eq!(
                libc::memcmp(
                    cloned.as_ptr().cast::<c_void>(),
                    consumed.as_ptr().cast::<c_void>(),
                    3
                ),
                0
            );
        }
    }

    #[test]
    fn test_vec_borrow_mut() {
        // A vec can be produced if a slice type for the elements has the capability.
        let mut v: Vec<u8> = vec![0x57, 0x72, 0x15];
        let bstr1 = b"\x57\x72\x15";
        let mut borrowed = v.borrow_foreign_mut();
        unsafe {
            assert_eq!(
                libc::memcmp(
                    borrowed.as_ptr().cast::<c_void>(),
                    bstr1.as_ptr().cast::<c_void>(),
                    bstr1.len()
                ),
                0
            );
            ptr::write(borrowed.as_mut_ptr().offset(1), 0xFF);
        }
        assert_eq!(v[1], 0xFF);
    }

    #[test]
    fn test_vec_borrow_foreign_mut_clone_to_foreign() {
        let mut v: Vec<u8> = vec![1, 2, 3];
        let borrowed = v.borrow_foreign_mut();
        let cloned = borrowed.clone_to_foreign();
        assert_ne!(cloned.as_ptr(), borrowed.as_ptr());
        unsafe {
            assert_eq!(
                libc::memcmp(
                    cloned.as_ptr().cast::<c_void>(),
                    borrowed.as_ptr().cast::<c_void>(),
                    3
                ),
                0
            );
        }
    }
}