use crate::error::{Error, Result};
use crate::fast::BeveTypedSlice;
use crate::header::*;
use crate::size::{read_size, size_encoded_len, write_size};
#[cfg(target_endian = "little")]
use core::ptr;
const ALIGNED_DISCRIMINATOR: u8 = 2;
#[inline]
fn aligned_marker_header() -> u8 {
make_header(
TYPE_TYPED_ARRAY,
ARRAY_BOOL_OR_STRING,
ALIGNED_DISCRIMINATOR,
)
}
#[inline]
fn padding_for(padding_length_offset: usize, align: usize) -> usize {
let offset_after_padding_length = padding_length_offset + 1;
(align - (offset_after_padding_length % align)) % align
}
pub fn write_aligned_typed_slice<T: BeveTypedSlice>(out: &mut Vec<u8>, slice: &[T]) {
write_aligned_typed_slice_at(out, slice, out.len());
}
pub fn write_aligned_typed_slice_at<T: BeveTypedSlice>(
out: &mut Vec<u8>,
slice: &[T],
base_offset: usize,
) {
let start = out.len();
let align = core::mem::align_of::<T>();
let payload = core::mem::size_of_val(slice);
out.reserve(2 + 9 + 1 + align + payload);
out.push(aligned_marker_header());
out.push(make_header(TYPE_TYPED_ARRAY, T::CLASS, T::BYTE_CODE));
write_size(slice.len() as u64, out);
let padding_length_offset = base_offset.wrapping_add(out.len() - start);
let padding = padding_for(padding_length_offset, align);
out.push(padding as u8);
out.resize(out.len() + padding, 0);
if slice.is_empty() {
return;
}
#[cfg(target_endian = "little")]
{
let bytes = unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, payload) };
out.extend_from_slice(bytes);
}
#[cfg(not(target_endian = "little"))]
{
for v in slice {
T::write_one_le(v, out);
}
}
}
pub fn to_vec_aligned_typed_slice<T: BeveTypedSlice>(slice: &[T]) -> Vec<u8> {
let mut out = Vec::new();
write_aligned_typed_slice(&mut out, slice);
out
}
pub fn aligned_typed_slice_size<T: BeveTypedSlice>(slice: &[T], start_offset: usize) -> usize {
let align = core::mem::align_of::<T>();
let size_width = size_encoded_len(slice.len() as u64);
let padding_length_offset = start_offset.wrapping_add(2 + size_width);
let padding = padding_for(padding_length_offset, align);
2 + size_width + 1 + padding + core::mem::size_of_val(slice)
}
fn parse_aligned_header<T: BeveTypedSlice>(input: &[u8]) -> Result<(&[u8], usize)> {
let mut pos = 0usize;
let marker = *input.get(pos).ok_or(Error::Eof)?;
pos += 1;
if parse_type(marker) != TYPE_TYPED_ARRAY
|| parse_subtype(marker) != ARRAY_BOOL_OR_STRING
|| parse_byte_count_code(marker) != ALIGNED_DISCRIMINATOR
{
return Err(Error::InvalidType("not an aligned typed array"));
}
let numeric = *input.get(pos).ok_or(Error::Eof)?;
pos += 1;
if parse_type(numeric) != TYPE_TYPED_ARRAY {
return Err(Error::InvalidType("aligned array numeric header malformed"));
}
if parse_subtype(numeric) != T::CLASS || parse_byte_count_code(numeric) != T::BYTE_CODE {
return Err(Error::Mismatch(
"aligned array element type does not match T",
));
}
let len = read_size(input, &mut pos)? as usize;
let padding = *input.get(pos).ok_or(Error::Eof)? as usize;
pos += 1;
pos = pos.checked_add(padding).ok_or(Error::InvalidSize)?;
if pos > input.len() {
return Err(Error::Eof);
}
let payload = len.checked_mul(T::ELEM_SIZE).ok_or(Error::InvalidSize)?;
if input.len() - pos < payload {
return Err(Error::Eof);
}
Ok((&input[pos..pos + payload], len))
}
pub fn read_aligned_typed_slice<T: BeveTypedSlice>(input: &[u8]) -> Result<Vec<T>> {
let (data, len) = parse_aligned_header::<T>(input)?;
let mut out: Vec<T> = Vec::with_capacity(len);
if len != 0 {
let payload = data.len();
#[cfg(target_endian = "little")]
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), out.as_mut_ptr() as *mut u8, payload);
out.set_len(len);
}
#[cfg(not(target_endian = "little"))]
unsafe {
let dst = out.as_mut_ptr() as *mut u8;
core::ptr::copy_nonoverlapping(data.as_ptr(), dst, payload);
let bytes = core::slice::from_raw_parts_mut(dst, payload);
for elem in bytes.chunks_exact_mut(T::ELEM_SIZE) {
elem.reverse();
}
out.set_len(len);
}
}
Ok(out)
}
pub fn read_aligned_typed_slice_ref<T: BeveTypedSlice>(input: &[u8]) -> Result<&[T]> {
let (data, len) = parse_aligned_header::<T>(input)?;
#[cfg(not(target_endian = "little"))]
{
let _ = (data, len);
return Err(Error::Unsupported(
"zero-copy aligned borrow requires a little-endian target",
));
}
#[cfg(target_endian = "little")]
{
if !(data.as_ptr() as usize).is_multiple_of(core::mem::align_of::<T>()) {
return Err(Error::Unsupported(
"aligned typed array payload is not aligned in this buffer; the buffer base must be aligned to align_of::<T>() for a zero-copy borrow",
));
}
Ok(unsafe { core::slice::from_raw_parts(data.as_ptr() as *const T, len) })
}
}
#[cfg(test)]
mod tests {
use super::*;
struct AlignedBytes {
backing: Vec<u128>,
len: usize,
}
impl AlignedBytes {
fn with(src: &[u8], offset: usize) -> Self {
let len = offset + src.len();
let backing: Vec<u128> = vec![0u128; len / 16 + 1];
let mut ab = AlignedBytes { backing, len };
let view = unsafe {
core::slice::from_raw_parts_mut(
ab.backing.as_mut_ptr() as *mut u8,
ab.backing.len() * 16,
)
};
view[offset..offset + src.len()].copy_from_slice(src);
ab
}
fn bytes(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.backing.as_ptr() as *const u8, self.len) }
}
}
#[test]
fn roundtrip_owned_offset0() {
let data: Vec<f64> = (0..100).map(|i| i as f64 * 0.5).collect();
let bytes = to_vec_aligned_typed_slice(&data);
assert_eq!(bytes[0], 0x5C, "marker header");
let back = read_aligned_typed_slice::<f64>(&bytes).unwrap();
assert_eq!(back, data);
}
#[test]
fn size_matches_written_length_across_offsets_and_types() {
macro_rules! check {
($ty:ty, $mk:expr) => {
let data: Vec<$ty> = (0..37).map($mk).collect();
for start in 0..40usize {
let mut buf = vec![0xAAu8; start];
write_aligned_typed_slice(&mut buf, &data);
let written = buf.len() - start;
assert_eq!(
written,
aligned_typed_slice_size(&data, start),
"size mismatch for {} at offset {}",
stringify!($ty),
start
);
}
};
}
check!(f64, |i| i as f64);
check!(f32, |i| i as f32);
check!(i64, |i| i as i64);
check!(u16, |i| i as u16);
check!(u8, |i| i as u8);
check!(i128, |i| i as i128);
}
#[test]
fn payload_is_aligned_within_buffer_for_every_prefix() {
let data: Vec<f64> = (0..16).map(|i| i as f64).collect();
for prefix in 0..32usize {
let mut buf = vec![0u8; prefix];
write_aligned_typed_slice(&mut buf, &data);
let (data_slice, _) = parse_aligned_header::<f64>(&buf[prefix..]).unwrap();
let data_off = data_slice.as_ptr() as usize - buf.as_ptr() as usize;
assert!(
data_off.is_multiple_of(8),
"DATA not 8-aligned at prefix {prefix}"
);
}
}
#[cfg(target_endian = "little")]
#[test]
fn zero_copy_borrow_in_aligned_buffer() {
let data: Vec<f64> = (0..50).map(|i| (i as f64).sqrt()).collect();
let mut framed = vec![0u8; 16];
write_aligned_typed_slice(&mut framed, &data);
let ab = AlignedBytes::with(&framed, 0);
let buf = ab.bytes();
assert!(
(buf.as_ptr() as usize).is_multiple_of(16),
"aligned backing"
);
let view: &[f64] = read_aligned_typed_slice_ref::<f64>(&buf[16..]).unwrap();
assert_eq!(view, data.as_slice());
let base = buf.as_ptr() as usize;
let vptr = view.as_ptr() as usize;
assert!(
vptr >= base && vptr < base + buf.len(),
"view borrows from buf"
);
}
#[test]
fn write_at_with_buffer_len_matches_plain_writer() {
macro_rules! check {
($ty:ty, $mk:expr) => {
let data: Vec<$ty> = (0..29).map($mk).collect();
for prefix in 0..20usize {
let mut a = vec![0x11u8; prefix];
let mut b = vec![0x11u8; prefix];
write_aligned_typed_slice(&mut a, &data);
let off = b.len();
write_aligned_typed_slice_at(&mut b, &data, off);
assert_eq!(a, b, "{} at prefix {}", stringify!($ty), prefix);
}
};
}
check!(f64, |i| i as f64);
check!(i32, |i| i - 14);
check!(u8, |i| i as u8);
}
#[test]
fn write_at_size_matches_aligned_typed_slice_size() {
let data: Vec<f32> = (0..23).map(|i| i as f32 * 0.5).collect();
for base in 0..40usize {
let mut body = Vec::new();
write_aligned_typed_slice_at(&mut body, &data, base);
assert_eq!(
body.len(),
aligned_typed_slice_size(&data, base),
"size mismatch at base {base}"
);
}
}
#[cfg(target_endian = "little")] #[test]
fn write_at_standalone_body_borrows_at_frame_offset() {
let data: Vec<f64> = (0..40).map(|i| i as f64 * 1.5).collect();
for base_offset in [8usize, 16, 48, 54, 55, 63, 100] {
let mut body = Vec::new();
write_aligned_typed_slice_at(&mut body, &data, base_offset);
assert_eq!(body[0], 0x5C, "marker header at base {base_offset}");
let ab = AlignedBytes::with(&body, base_offset);
let frame = ab.bytes();
let borrowed =
read_aligned_typed_slice_ref::<f64>(&frame[base_offset..]).expect("borrow");
assert_eq!(borrowed, data.as_slice(), "base_offset {base_offset}");
}
}
#[test]
fn write_at_empty_slice_matches_sizer_and_roundtrips() {
let data: Vec<f64> = Vec::new();
for base in [0usize, 7, 48, 54] {
let mut body = Vec::new();
write_aligned_typed_slice_at(&mut body, &data, base);
assert_eq!(
body.len(),
aligned_typed_slice_size(&data, base),
"base {base}"
);
assert!(read_aligned_typed_slice::<f64>(&body).unwrap().is_empty());
}
}
#[cfg(target_endian = "little")] #[test]
fn write_at_borrows_for_align_gt_8_element() {
let data: Vec<i128> = (0..12).map(|i| ((i as i128) << 64) | (i as i128)).collect();
for base_offset in [16usize, 32, 48, 50, 63, 100] {
let mut body = Vec::new();
write_aligned_typed_slice_at(&mut body, &data, base_offset);
assert_eq!(body.len(), aligned_typed_slice_size(&data, base_offset));
let ab = AlignedBytes::with(&body, base_offset);
let frame = ab.bytes();
let borrowed =
read_aligned_typed_slice_ref::<i128>(&frame[base_offset..]).expect("borrow");
assert_eq!(borrowed, data.as_slice(), "base_offset {base_offset}");
}
}
#[cfg(target_endian = "little")] #[test]
fn write_at_with_prefilled_out_and_independent_base_offset() {
let data: Vec<f64> = (0..20).map(|i| i as f64 * 2.0).collect();
let base_offset = 54usize;
let mut out = vec![0xEEu8; 13]; let start = out.len();
write_aligned_typed_slice_at(&mut out, &data, base_offset);
let body = &out[start..];
assert_eq!(read_aligned_typed_slice::<f64>(body).unwrap(), data);
let ab = AlignedBytes::with(body, base_offset);
let frame = ab.bytes();
let borrowed = read_aligned_typed_slice_ref::<f64>(&frame[base_offset..]).expect("borrow");
assert_eq!(borrowed, data.as_slice());
}
#[test]
fn borrow_refuses_unaligned_buffer() {
let data: Vec<f64> = (0..8).map(|i| i as f64).collect();
let framed = to_vec_aligned_typed_slice(&data);
let ab = AlignedBytes::with(&framed, 1);
let sub = &ab.bytes()[1..];
assert_eq!(read_aligned_typed_slice::<f64>(sub).unwrap(), data);
assert!(read_aligned_typed_slice_ref::<f64>(sub).is_err());
}
#[test]
fn rejects_regular_typed_array_and_wrong_type() {
let data: Vec<f64> = vec![1.0, 2.0, 3.0];
let regular = crate::to_vec_typed_slice(&data);
assert!(read_aligned_typed_slice::<f64>(®ular).is_err());
let aligned = to_vec_aligned_typed_slice(&data);
assert!(read_aligned_typed_slice::<f32>(&aligned).is_err());
assert!(read_aligned_typed_slice::<i64>(&aligned).is_err());
}
#[test]
fn empty_slice_roundtrips() {
let data: Vec<f64> = Vec::new();
let bytes = to_vec_aligned_typed_slice(&data);
assert!(read_aligned_typed_slice::<f64>(&bytes).unwrap().is_empty());
}
#[test]
fn padding_bytes_are_ignored_on_read() {
const PREFIX: usize = 3;
let data: Vec<f64> = (0..5).map(|i| i as f64).collect();
let mut buf = vec![0u8; PREFIX];
write_aligned_typed_slice(&mut buf, &data);
let size_w = size_encoded_len(data.len() as u64);
let pl_offset = PREFIX + 2 + size_w;
let pad = padding_for(pl_offset, core::mem::align_of::<f64>());
assert!(pad > 0, "test needs a non-zero padding run");
for b in &mut buf[pl_offset + 1..pl_offset + 1 + pad] {
*b = 0xFF; }
assert_eq!(
read_aligned_typed_slice::<f64>(&buf[PREFIX..]).unwrap(),
data
);
}
#[test]
fn rejects_truncated_payload() {
let data: Vec<f64> = (0..6).map(|i| i as f64).collect();
let full = to_vec_aligned_typed_slice(&data);
for cut in 1..=8 {
let truncated = &full[..full.len() - cut];
assert!(
read_aligned_typed_slice::<f64>(truncated).is_err(),
"truncation by {cut} must be rejected, not read past the buffer"
);
assert!(read_aligned_typed_slice_ref::<f64>(truncated).is_err());
}
for keep in 0..4 {
assert!(read_aligned_typed_slice::<f64>(&full[..keep]).is_err());
}
}
#[test]
fn rejects_padding_length_past_buffer() {
let data: Vec<f64> = (0..4).map(|i| i as f64).collect();
let mut buf = to_vec_aligned_typed_slice(&data);
let size_w = size_encoded_len(data.len() as u64);
let pl_offset = 2 + size_w;
buf[pl_offset] = 0xFF;
assert!(read_aligned_typed_slice::<f64>(&buf).is_err());
assert!(read_aligned_typed_slice_ref::<f64>(&buf).is_err());
}
#[cfg(target_endian = "little")] #[test]
fn zero_copy_borrow_non_f64_alignments() {
let i: Vec<i128> = (0..20).map(|n| ((n as i128) << 80) | (n as i128)).collect();
let mut framed = vec![0u8; 16];
write_aligned_typed_slice(&mut framed, &i);
let ab = AlignedBytes::with(&framed, 0);
let view: &[i128] = read_aligned_typed_slice_ref::<i128>(&ab.bytes()[16..]).unwrap();
assert_eq!(view, i.as_slice());
assert!((view.as_ptr() as usize).is_multiple_of(16));
let b: Vec<u8> = (0..37u8).collect();
let framed_b = to_vec_aligned_typed_slice(&b);
let ab_b = AlignedBytes::with(&framed_b, 0);
let view_b: &[u8] = read_aligned_typed_slice_ref::<u8>(ab_b.bytes()).unwrap();
assert_eq!(view_b, b.as_slice());
}
}