#![cfg(feature = "zero-copy")]
use bincode_next::relative_ptr::NativeEndian;
use bincode_next::relative_ptr::RelativePtr;
use bincode_next::relative_ptr::Validator;
use bincode_next::relative_ptr::ZeroArray;
use bincode_next::relative_ptr::ZeroString;
#[repr(align(8))]
struct AlignedBuffer<const N: usize>(pub [u8; N]);
#[test]
fn test_relative_ptr_valid() {
let mut buffer = AlignedBuffer([0; 12]);
let buffer = &mut buffer.0;
let offset: i32 = 8;
buffer[0..4].copy_from_slice(&offset.to_ne_bytes());
let value: u32 = 42;
buffer[8..12].copy_from_slice(&value.to_ne_bytes());
let ptr = unsafe { &*(buffer.as_ptr() as *const RelativePtr<u32, 4>) };
assert!(ptr.is_valid(&buffer[..]));
let resolved = ptr.get(&buffer[..]).unwrap();
assert_eq!(*resolved, 42);
}
#[test]
fn test_relative_ptr_negative_offset() {
let mut buffer = AlignedBuffer([0; 12]);
let buffer = &mut buffer.0;
let value: u32 = 42;
buffer[0..4].copy_from_slice(&value.to_ne_bytes());
let offset: i32 = -8;
buffer[8..12].copy_from_slice(&offset.to_ne_bytes());
let ptr = unsafe { &*(buffer[8..].as_ptr() as *const RelativePtr<u32, 4>) };
assert!(ptr.is_valid(&buffer[..]));
let resolved = ptr.get(&buffer[..]).unwrap();
assert_eq!(*resolved, 42);
}
#[test]
fn test_relative_ptr_out_of_bounds() {
let mut buffer = AlignedBuffer([0; 8]);
let buffer = &mut buffer.0;
let offset: i32 = 12;
buffer[0..4].copy_from_slice(&offset.to_ne_bytes());
let ptr = unsafe { &*(buffer.as_ptr() as *const RelativePtr<u32, 4>) };
assert!(!ptr.is_valid(&buffer[..]));
assert!(ptr.get(&buffer[..]).is_none());
}
#[test]
fn test_relative_ptr_negative_out_of_bounds() {
let mut buffer = AlignedBuffer([0; 8]);
let buffer = &mut buffer.0;
let offset: i32 = -4;
buffer[4..8].copy_from_slice(&offset.to_ne_bytes());
let ptr = unsafe { &*(buffer[4..].as_ptr() as *const RelativePtr<u32, 4>) };
let resolved = ptr.get(&buffer[..]).unwrap();
assert_eq!(*resolved, 0);
let offset2: i32 = -8;
buffer[4..8].copy_from_slice(&offset2.to_ne_bytes());
let ptr2 = unsafe { &*(buffer[4..].as_ptr() as *const RelativePtr<u32, 4>) };
assert!(ptr2.get(&buffer[..]).is_none());
}
#[test]
fn test_relative_ptr_bad_alignment() {
let mut buffer = AlignedBuffer([0; 16]);
let buffer = &mut buffer.0;
let offset: i32 = 5;
buffer[0..4].copy_from_slice(&offset.to_ne_bytes());
let ptr = unsafe { &*(buffer.as_ptr() as *const RelativePtr<u32, 4>) };
assert!(!ptr.is_valid(&buffer[..]));
assert!(ptr.get(&buffer[..]).is_none());
}
#[test]
fn test_zero_array() {
let mut buffer = AlignedBuffer([0; 16]);
let buffer = &mut buffer.0;
let vals: [u32; 2] = [10, 20];
let vals_bytes = unsafe { core::slice::from_raw_parts(vals.as_ptr() as *const u8, 8) };
buffer[8..16].copy_from_slice(vals_bytes);
let offset: i32 = 8;
buffer[0..4].copy_from_slice(&offset.to_ne_bytes());
let arr = unsafe { &*(buffer.as_ptr() as *const ZeroArray<u32, 2, 4>) };
assert!(arr.is_valid(&buffer[..]));
let resolved: &[u32; 2] = arr.get(&buffer[..]).unwrap();
assert_eq!(resolved[0], 10);
assert_eq!(resolved[1], 20);
}
#[test]
#[cfg(feature = "alloc")]
fn test_zero_string() {
use bincode_next::relative_ptr::FixedString;
use bincode_next::relative_ptr::ZeroBuilder;
use bincode_next::relative_ptr::ZeroCopyBuilder;
let mut builder = ZeroBuilder::new();
let text = "hello".to_string();
let z_builder: FixedString<5> = FixedString(text);
<FixedString<5> as ZeroCopyBuilder<NativeEndian, 0>>::build(z_builder, &mut builder);
let buffer = builder.finish();
let z_str = unsafe { &*(buffer.as_ptr() as *const ZeroString<5, NativeEndian>) };
assert!(z_str.is_valid(&buffer[..]));
let resolved = z_str.get().unwrap();
assert_eq!(resolved, "hello");
}
use bincode_next::relative_ptr::ZeroSlice;
use bincode_next::relative_ptr::ZeroStr;
#[test]
fn test_zero_slice() {
let mut buffer = AlignedBuffer([0; 24]);
let buffer = &mut buffer.0;
let len: u32 = 3;
buffer[0..4].copy_from_slice(&len.to_ne_bytes());
let offset: i32 = 8;
buffer[4..8].copy_from_slice(&offset.to_ne_bytes());
let vals: [u32; 3] = [100, 200, 300];
let vals_bytes = unsafe { core::slice::from_raw_parts(vals.as_ptr() as *const u8, 12) };
buffer[12..24].copy_from_slice(vals_bytes);
let slice = unsafe { &*(buffer.as_ptr() as *const ZeroSlice<u32, 4>) };
assert!(slice.is_valid(buffer));
let resolved = slice.get(buffer).unwrap();
assert_eq!(resolved.len(), 3);
assert_eq!(resolved[0], 100);
assert_eq!(resolved[1], 200);
assert_eq!(resolved[2], 300);
}
#[test]
fn test_zero_str() {
let mut buffer = AlignedBuffer([0; 16]);
let buffer = &mut buffer.0;
let text = b"bincode";
let len: u32 = 7;
buffer[0..4].copy_from_slice(&len.to_ne_bytes());
let offset: i32 = 4;
buffer[4..8].copy_from_slice(&offset.to_ne_bytes());
buffer[8..15].copy_from_slice(text);
let z_str = unsafe { &*(buffer.as_ptr() as *const ZeroStr) };
assert!(z_str.is_valid(buffer));
let resolved = z_str.get(buffer).unwrap();
assert_eq!(resolved, "bincode");
}
#[test]
fn test_nested_slices() {
let mut buffer = AlignedBuffer([0; 64]);
let buffer = &mut buffer.0;
let outer_len: u32 = 2;
buffer[0..4].copy_from_slice(&outer_len.to_ne_bytes());
let outer_offset: i32 = 4; buffer[4..8].copy_from_slice(&outer_offset.to_ne_bytes());
let inner_1_len: u32 = 1;
buffer[8..12].copy_from_slice(&inner_1_len.to_ne_bytes());
let _inner_1_offset: i32 = 16; buffer[12..16].copy_from_slice(&20i32.to_ne_bytes());
let vals1: u32 = 111;
buffer[32..36].copy_from_slice(&vals1.to_ne_bytes());
let inner_2_len: u32 = 2;
buffer[16..20].copy_from_slice(&inner_2_len.to_ne_bytes());
buffer[20..24].copy_from_slice(&20i32.to_ne_bytes());
let vals2: [u32; 2] = [222, 333];
let vals2_bytes = unsafe { core::slice::from_raw_parts(vals2.as_ptr() as *const u8, 8) };
buffer[40..48].copy_from_slice(vals2_bytes);
type InnerSlice = ZeroSlice<u32, 4>;
let slice = unsafe { &*(buffer.as_ptr() as *const ZeroSlice<InnerSlice, 4>) };
assert!(slice.is_valid(buffer));
let resolved = slice.get(buffer).unwrap();
assert_eq!(resolved.len(), 2);
let inner_1 = resolved[0].get(buffer).unwrap();
assert_eq!(inner_1[0], 111);
let inner_2 = resolved[1].get(buffer).unwrap();
assert_eq!(inner_2.len(), 2);
assert_eq!(inner_2[0], 222);
assert_eq!(inner_2[1], 333);
}