#![allow(clippy::assertions_on_constants)]
use core::array;
use anyhow::Result;
use crate::mem::PackedMaybeUninit;
use crate::{Ref, ZeroCopy};
use super::{OwnedBuf, SliceMut};
#[derive(Debug, PartialEq, ZeroCopy)]
#[zero_copy(crate)]
#[repr(C)]
struct Inner {
first: u8,
second: u64,
}
#[test]
fn allocate_array_needing_padding() -> Result<()> {
#[derive(Debug, PartialEq, ZeroCopy)]
#[zero_copy(crate)]
#[repr(C)]
struct Element {
first: u8,
second: u32,
third: [Inner; 2],
}
const _: () = assert!(Element::PADDED);
let mut buf = OwnedBuf::new();
let array = buf.store_uninit::<[Element; 10]>()?;
let values = array::from_fn(|index| Element {
first: index as u8,
second: 0x01020304u32,
third: [
Inner {
first: index as u8,
second: 0x05060708090a0b0cu64,
},
Inner {
first: index as u8,
second: 0x05060708090a0b0cu64,
},
],
});
buf.load_uninit_mut(array)?.write(&values);
let array = array.assume_init();
assert_eq!(buf.load(array)?, &values);
Ok(())
}
#[test]
fn allocate_array_not_needing_padding() -> Result<()> {
#[derive(Debug, PartialEq, ZeroCopy)]
#[zero_copy(crate)]
#[repr(C)]
struct Element {
first: u32,
second: u32,
third: u32,
}
const _: () = assert!(!Element::PADDED);
let mut buf = OwnedBuf::new();
let array = buf.store_uninit::<[Element; 10]>()?;
let values = array::from_fn(|index| Element {
first: index as u32,
second: 0x01020304u32,
third: 0x05060708u32,
});
buf.load_uninit_mut(array)?.write(&values);
let array = array.assume_init();
assert_eq!(buf.load(array)?, &values);
Ok(())
}
#[test]
fn test_unaligned_write() -> Result<()> {
#[derive(ZeroCopy)]
#[repr(C)]
#[zero_copy(crate)]
struct Custom {
string: Ref<str>,
}
let mut buf = OwnedBuf::with_capacity_and_alignment::<u8>(128)?;
buf.extend_from_slice(&[1])?;
let reference: Ref<PackedMaybeUninit<Custom>> = buf.store_uninit::<Custom>()?;
let string = buf.store_unsized("Hello World!")?;
buf.load_uninit_mut(reference)?.write(&Custom { string });
let reference = reference.assume_init();
assert_eq!(reference.offset(), 4);
buf.align_in_place()?;
let custom = buf.load(reference)?;
assert_eq!(buf.load(custom.string)?, "Hello World!");
Ok(())
}
#[test]
fn inner_padding() -> Result<()> {
#[derive(Debug, PartialEq, Clone, Copy, ZeroCopy)]
#[repr(C, align(8))]
#[zero_copy(crate)]
struct Inner {
field: u8,
}
#[derive(Debug, PartialEq, Clone, Copy, ZeroCopy)]
#[repr(C, align(16))]
#[zero_copy(crate)]
struct Inner2 {
field: u32,
}
#[derive(ZeroCopy)]
#[repr(C)]
#[zero_copy(crate)]
struct Custom {
inner: Inner,
inner2: Inner2,
}
const _: () = assert!(Custom::PADDED);
const _: () = assert!(Inner::PADDED);
const _: () = assert!(Inner2::PADDED);
let inner = Inner { field: 10 };
let inner2 = Inner2 { field: 20 };
let custom = Custom { inner, inner2 };
let mut buf = OwnedBuf::with_capacity_and_alignment::<u8>(128)?;
buf.extend_from_slice(&[1])?;
let reference: Ref<PackedMaybeUninit<Custom>> = buf.store_uninit::<Custom>()?;
buf.load_uninit_mut(reference)?.write(&custom);
let reference = reference.assume_init();
assert_eq!(reference.offset(), 16);
buf.align_in_place()?;
let custom = buf.load(reference)?;
assert_eq!(&custom.inner, &inner);
assert_eq!(&custom.inner2, &inner2);
Ok(())
}
#[test]
fn test_packing() {
#[derive(ZeroCopy)]
#[repr(C, packed)]
#[zero_copy(crate)]
struct Packed {
inner: u8,
inner2: u32,
}
const _: () = assert!(!Packed::PADDED);
#[derive(ZeroCopy)]
#[repr(C, packed(1))]
#[zero_copy(crate)]
struct Packed1 {
inner: u8,
inner2: u32,
}
const _: () = assert!(!Packed1::PADDED);
}
#[test]
fn slice_mut_load_uninit_mut_rejects_value_past_end() {
let mut bytes = [0u8; 4];
let mut buf = SliceMut::new(&mut bytes);
let reference = Ref::<PackedMaybeUninit<u64>>::new(0u32);
assert!(buf.load_uninit_mut(reference).is_err());
}
#[test]
fn slice_mut_load_uninit_mut_rejects_foreign_ref() -> Result<()> {
let mut large = [0u8; 64];
let mut large = SliceMut::new(&mut large);
large.store(&0u32)?;
let foreign = large.store_uninit::<[u32; 2]>()?;
assert_eq!(foreign.offset(), 4);
let mut small = [0u8; 8];
let mut small = SliceMut::new(&mut small);
small.store(&0u32)?;
assert!(small.load_uninit_mut(foreign).is_err());
Ok(())
}
#[test]
fn slice_mut_load_uninit_mut_exact_fit() -> Result<()> {
let mut bytes = [0u8; 8];
{
let mut buf = SliceMut::new(&mut bytes);
let reference = buf.store_uninit::<u64>()?;
buf.load_uninit_mut(reference)?
.write(&0x0102030405060708u64);
}
assert_eq!(bytes, 0x0102030405060708u64.to_ne_bytes());
Ok(())
}