extern crate alloc;
use alloc::vec::Vec;
use bytemuck::{AnyBitPattern, Pod, bytes_of, zeroed};
use crate::{VmError, VmImpl, VmIo, VmResult, vm_read_slice};
pub unsafe fn vm_load_any<T>(ptr: *const T, len: usize) -> VmResult<Vec<T>> {
let mut buf = Vec::with_capacity(len);
vm_read_slice(ptr, &mut buf.spare_capacity_mut()[..len])?;
unsafe { buf.set_len(len) }
Ok(buf)
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn vm_load<T: AnyBitPattern>(ptr: *const T, len: usize) -> VmResult<Vec<T>> {
unsafe { vm_load_any(ptr, len) }
}
#[inline]
fn is_zero<T: Pod>(value: &T) -> bool {
bytes_of(value) == bytes_of(&zeroed::<T>())
}
const MAX_BYTES: usize = 131072;
pub fn vm_load_until_nul<T: Pod>(ptr: *const T) -> VmResult<Vec<T>> {
if !ptr.is_aligned() {
return Err(VmError::BadAddress);
}
let size = size_of::<T>();
let mut result = Vec::new();
let mut vm = VmImpl::new();
loop {
const CHUNK_SIZE: usize = 32;
let start = ptr.addr() + result.len() * size;
let end = (start + 1).next_multiple_of(CHUNK_SIZE);
let len = (end - start) / size;
result.reserve(len);
let buf = &mut result.spare_capacity_mut()[..len];
vm.read(start, buf.as_bytes_mut())?;
let buf = unsafe { buf.assume_init_ref() };
let pos = buf.iter().position(is_zero);
unsafe { result.set_len(result.len() + pos.unwrap_or(len)) };
if result.len() >= MAX_BYTES / size {
return Err(VmError::TooLong);
}
if pos.is_some() {
break;
}
}
Ok(result)
}