use core::mem::offset_of;
use alloc::borrow::ToOwned;
use crate::*;
#[cfg(feature = "alloc")]
#[test]
fn str_test() {
let str = "thisisatest";
let layout = Layout::for_value(str);
let boxed: Box<str> = unsafe {
Box::new_dst(str.len(), layout, |ptr| {
str.clone_to_uninit(ptr.cast().as_ptr());
})
};
assert_eq!(boxed.len(), str.len());
assert_eq!(boxed.as_ref(), str);
}
#[cfg(feature = "alloc")]
#[test]
fn zst_test() {
let arr: [(); 0] = [];
let layout = Layout::for_value(&arr);
let boxed: Box<[()]> = unsafe {
Box::new_dst(arr.len(), layout, |ptr| {
arr.clone_to_uninit(ptr.cast().as_ptr());
})
};
assert_eq!(boxed.len(), arr.len());
assert_eq!(boxed.as_ref(), arr);
}
#[repr(C)]
struct Type {
data1: i16,
data2: usize,
data3: u32,
slice: [i128],
}
unsafe impl Dst for Type {
#[inline]
fn len(&self) -> usize {
self.slice.len()
}
fn layout(len: usize) -> Result<Layout, LayoutError> {
let (layout, _) = Self::__dst_impl_layout_offsets(len)?;
Ok(layout)
}
fn retype(ptr: NonNull<u8>, len: usize) -> NonNull<Self> {
unsafe {
#[allow(
clippy::cast_ptr_alignment,
reason = "the responsibility to provide a pointer with the correct alignment is on the caller"
)]
NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(ptr.as_ptr(), len) as *mut Self)
}
}
}
impl Type {
fn __dst_impl_layout_offsets(len: usize) -> Result<(Layout, [usize; 4]), LayoutError> {
let layouts = [
Layout::new::<i16>(),
Layout::new::<usize>(),
Layout::new::<u32>(),
<[i128]>::layout(len)?,
];
let mut offsets = [0; 4];
let layout = Layout::from_size_align(0, 1)?;
let (layout, offset) = layout.extend(layouts[0])?;
offsets[0] = offset;
let (layout, offset) = layout.extend(layouts[1])?;
offsets[1] = offset;
let (layout, offset) = layout.extend(layouts[2])?;
offsets[2] = offset;
let (layout, offset) = layout.extend(layouts[3])?;
offsets[3] = offset;
Ok((layout.pad_to_align(), offsets))
}
unsafe fn new_unchecked<A: AllocDst<Self>>(
data1: i16,
data2: usize,
data3: u32,
slice: &[i128],
) -> Result<A, LayoutError> {
let (layout, offsets) = Self::__dst_impl_layout_offsets(slice.len())?;
Ok(unsafe {
A::new_dst(slice.len(), layout, |ptr| {
let dest = ptr.cast::<u8>();
slice.clone_to_uninit(dest.add(offsets[3]).as_ptr());
dest.add(offsets[0]).cast().write(data1);
dest.add(offsets[1]).cast().write(data2);
dest.add(offsets[2]).cast().write(data3);
})
})
}
}
unsafe impl CloneToUninit for Type {
#[allow(
clippy::clone_on_copy,
reason = "matching the output of the derive macro"
)]
#[allow(
clippy::cast_ptr_alignment,
reason = "the responsibility to provide a pointer with the correct alignment is on the caller"
)]
unsafe fn clone_to_uninit(&self, dest: *mut u8) {
let last_offset = unsafe { (&raw const self.slice).byte_offset_from_unsigned(self) };
let data1 = self.data1.clone();
let data2 = self.data2.clone();
let data3 = self.data3.clone();
unsafe {
self.slice.clone_to_uninit(dest.add(last_offset));
dest.add(offset_of!(Self, data1)).cast::<i16>().write(data1);
dest.add(offset_of!(Self, data2))
.cast::<usize>()
.write(data2);
dest.add(offset_of!(Self, data3)).cast::<u32>().write(data3);
}
}
}
impl ToOwned for Type {
type Owned = Box<Type>;
fn to_owned(&self) -> Self::Owned {
let layout = Layout::for_value(self);
unsafe {
Self::Owned::new_dst(self.len(), layout, |ptr| {
let dest = ptr.cast::<u8>();
self.clone_to_uninit(dest.as_ptr());
})
}
}
}
#[cfg(feature = "alloc")]
#[test]
fn complex_test() {
let v: Box<_> = unsafe { Type::new_unchecked(-12, 65537, 50, &[-2, 5, 20]) }.unwrap();
assert_eq!(v.data1, -12);
assert_eq!(v.data2, 65537);
assert_eq!(v.data3, 50);
assert_eq!(v.slice.first(), Some(&-2));
assert_eq!(v.slice.get(1), Some(&5));
assert_eq!(v.slice.get(2), Some(&20));
assert_eq!(v.len(), 3);
assert_eq!(v.len(), v.slice.len());
}
#[cfg(feature = "alloc")]
#[test]
fn clone_test() {
let v1: Box<_> = unsafe { Type::new_unchecked(-12, 65537, 50, &[-2, 5, 20]) }.unwrap();
let v2 = v1.to_owned();
assert_eq!(v2.data1, v1.data1);
assert_eq!(v2.data2, v1.data2);
assert_eq!(v2.data3, v1.data3);
assert_eq!(v2.slice.first(), v1.slice.first());
assert_eq!(v2.slice.get(1), v1.slice.get(1));
assert_eq!(v2.slice.get(2), v1.slice.get(2));
assert_eq!(v2.len(), v1.len());
}
#[cfg(feature = "alloc")]
#[derive(Dst, CloneToUninit, ToOwned)]
#[dst(simple_dst_path = crate)]
#[to_owned(alloc_path = alloc)]
#[repr(C)]
struct DeriveType {
data1: i16,
data2: usize,
data3: u32,
slice: [i128],
}
#[cfg(feature = "alloc")]
#[test]
fn derive_complex_test() {
let v: Box<_> = unsafe { DeriveType::new_unchecked(-12, 65537, 50, &[-2, 5, 20]) }.unwrap();
assert_eq!(v.data1, -12);
assert_eq!(v.data2, 65537);
assert_eq!(v.data3, 50);
assert_eq!(v.slice.first(), Some(&-2));
assert_eq!(v.slice.get(1), Some(&5));
assert_eq!(v.slice.get(2), Some(&20));
assert_eq!(v.len(), 3);
assert_eq!(v.len(), v.slice.len());
}
#[cfg(feature = "alloc")]
#[test]
fn derive_clone_test() {
let v1: Box<_> = unsafe { DeriveType::new_unchecked(-12, 65537, 50, &[-2, 5, 20]) }.unwrap();
let v2 = v1.to_owned();
assert_eq!(v2.data1, v1.data1);
assert_eq!(v2.data2, v1.data2);
assert_eq!(v2.data3, v1.data3);
assert_eq!(v2.slice.first(), v1.slice.first());
assert_eq!(v2.slice.get(1), v1.slice.get(1));
assert_eq!(v2.slice.get(2), v1.slice.get(2));
assert_eq!(v2.len(), v1.len());
}