use std::alloc::Layout;
use std::ffi::c_void;
use crate::foreign::*;
use crate::r#impl::alloc;
impl<T> FreeForeign for [T]
where
T: FixedAlloc,
{
type Foreign = T::Foreign;
unsafe fn free_foreign(ptr: *mut Self::Foreign) {
libc::free(ptr.cast::<c_void>());
}
}
impl<T> CloneToForeign for [T]
where
T: FixedAlloc,
{
fn clone_to_foreign(&self) -> OwnedPointer<Self> {
let len = if self.is_empty() { 1 } else { self.len() };
let len = len
.checked_mul(T::FOREIGN_LEN)
.expect("slice is too large to convert to a C array");
let layout = Layout::array::<Self::Foreign>(len)
.expect("slice is too large to convert to a C array");
unsafe {
let p = alloc::<Self::Foreign>(layout);
T::clone_from_native_slice(p, self);
OwnedPointer::new(p)
}
}
}
impl<T> BorrowForeign for [T]
where
T: FixedAlloc + FreeForeign<Foreign = T> + BorrowForeign,
{
type Storage<'a>
= &'a Self
where
Self: 'a;
fn borrow_foreign(&self) -> BorrowedPointer<Self, Self::Storage<'_>> {
unsafe { BorrowedPointer::new_borrowed(self, |raw| raw.cast::<T>()) }
}
}
impl<T> BorrowForeignMut for [T]
where
T: FixedAlloc + FreeForeign<Foreign = T> + BorrowForeignMut,
{
type Storage<'a>
= BorrowedStorage<'a, Self>
where
Self: 'a;
fn borrow_foreign_mut(&mut self) -> BorrowedMutPointer<Self, Self::Storage<'_>> {
unsafe { BorrowedMutPointer::new_borrowed(self, |raw| raw.cast::<T>()) }
}
}
impl<T, const N: usize> FreeForeign for [T; N]
where
T: FixedAlloc,
{
type Foreign = T::Foreign;
unsafe fn free_foreign(ptr: *mut Self::Foreign) {
libc::free(ptr.cast::<c_void>());
}
}
impl<T, const N: usize> CloneToForeign for [T; N]
where
T: FixedAlloc,
{
fn clone_to_foreign(&self) -> OwnedPointer<Self> {
self[..].clone_to_foreign().into()
}
}
impl<T, const N: usize> FromForeign for [T; N]
where
T: FixedAllocFrom,
{
unsafe fn cloned_from_foreign(src: *const Self::Foreign) -> Self {
T::clone_array_from_foreign(src)
}
}
impl<T, const N: usize> BorrowForeign for [T; N]
where
T: FixedAlloc + FreeForeign<Foreign = T> + BorrowForeign,
{
type Storage<'a>
= &'a [T; N]
where
Self: 'a;
fn borrow_foreign(&self) -> BorrowedPointer<Self, Self::Storage<'_>> {
unsafe { BorrowedPointer::new_borrowed(self, |raw| raw.cast::<T>()) }
}
}
impl<T, const N: usize> BorrowForeignMut for [T; N]
where
T: FixedAlloc + FreeForeign<Foreign = T> + BorrowForeignMut,
{
type Storage<'a>
= BorrowedStorage<'a, Self>
where
Self: 'a;
fn borrow_foreign_mut(&mut self) -> BorrowedMutPointer<Self, Self::Storage<'_>> {
unsafe { BorrowedMutPointer::new_borrowed(self, |raw| raw.cast::<T>()) }
}
}
unsafe impl<T, const N: usize> FixedAlloc for [T; N]
where
T: FixedAlloc,
{
const FOREIGN_LEN: usize = N * T::FOREIGN_LEN;
unsafe fn clone_into_foreign(dest: *mut Self::Foreign, src: &Self) {
T::clone_from_native_slice(dest, &src[..]);
}
}
#[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_slice_convert() {
let a = [123i8, 45i8, 67i8];
let i = &a[0..=1];
let p = i.clone_to_foreign();
unsafe {
assert_eq!(
libc::memcmp(
i.as_ptr().cast::<c_void>(),
p.as_ptr().cast::<c_void>(),
i.len()
),
0
);
assert_eq!(i, <[i8; 2]>::cloned_from_foreign(p.as_ptr()));
}
let p = i.clone_to_foreign();
unsafe {
assert_eq!(i, <[i8; 2]>::from_foreign(p.into_inner()));
}
}
#[test]
fn test_slice_borrow() {
let i = [123i8, 45i8];
let borrowed = i.borrow_foreign();
unsafe {
assert_eq!(
libc::memcmp(
i.as_ptr().cast::<c_void>(),
borrowed.as_ptr().cast::<c_void>(),
i.len()
),
0
);
let cloned = <[i8; 2]>::cloned_from_foreign(borrowed.as_ptr());
assert_eq!(i, cloned);
}
}
#[test]
fn test_slice_borrow_mut() {
let expected = [123u8, 45u8];
let mut i = expected;
let mut borrowed = i.borrow_foreign_mut();
unsafe {
assert_eq!(
libc::memcmp(
expected.as_ptr().cast::<c_void>(),
borrowed.as_ptr().cast::<c_void>(),
expected.len()
),
0
);
ptr::write(borrowed.as_mut_ptr().offset(1), 234);
let cloned = <[u8; 2]>::cloned_from_foreign(borrowed.as_ptr());
assert_eq!(i[1], 234);
assert_eq!(i, cloned);
}
}
#[test]
fn test_empty_slice_convert() {
let empty: [i8; 0] = [];
let p = empty.clone_to_foreign();
assert_ne!(p.as_ptr(), ptr::null());
let v: Vec<i8> = Vec::new();
let p = v.clone_to_foreign();
assert_ne!(p.as_ptr(), ptr::null());
let p = empty[..].clone_to_foreign();
assert_ne!(p.as_ptr(), ptr::null());
}
#[test]
fn test_nested_array_convert() {
let a: [[u8; 3]; 4] = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]];
let p = a.clone_to_foreign();
unsafe {
let flat = std::slice::from_raw_parts(p.as_ptr(), 12);
assert_eq!(flat, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
assert_eq!(<[[u8; 3]; 4]>::cloned_from_foreign(p.as_ptr()), a);
}
let v: Vec<[u8; 3]> = a.to_vec();
let p = v.clone_to_foreign();
unsafe {
let flat = std::slice::from_raw_parts(p.as_ptr(), 12);
assert_eq!(flat, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
}
}
#[test]
fn test_borrowed_element_clone_to_foreign() {
let n = 7u8;
let a = [
PrimitiveWithLifetime::new(&n),
PrimitiveWithLifetime::new(&n),
];
let p = a.clone_to_foreign();
unsafe {
assert_eq!((*p.as_ptr()).0, 7);
assert_eq!((*p.as_ptr().add(1)).0, 7);
}
}
#[test]
fn test_array_convert() {
let i = [123i8, 45i8];
let p = i.clone_to_foreign();
unsafe {
assert_eq!(
libc::memcmp(
i.as_ptr().cast::<c_void>(),
p.as_ptr().cast::<c_void>(),
i.len()
),
0
);
assert_eq!(i, <[i8; 2]>::cloned_from_foreign(p.as_ptr()));
}
let p = i.clone_to_foreign();
unsafe {
assert_eq!(i, <[i8; 2]>::from_foreign(p.into_inner()));
}
}
}