use alloc::vec::Vec;
use core::ops::Range;
use tinywasm_types::MemoryArch;
use super::memory_oob;
pub(crate) struct VecMemory {
data: Vec<u8>,
}
impl VecMemory {
pub(crate) fn try_new(_arch: MemoryArch, len: usize, _max_len: usize) -> Result<Self, crate::Trap> {
let mut data = Vec::new();
cold_err!(data.try_reserve(len)).map_err(|_| crate::Trap::OutOfMemory)?;
data.resize(len, 0);
Ok(Self { data })
}
#[inline(always)]
pub(crate) fn len(&self) -> usize {
self.data.len()
}
#[inline(always)]
pub(super) fn checked_range(&self, addr: usize, len: usize) -> Option<Range<usize>> {
let end = addr.checked_add(len)?;
(end <= self.data.len()).then_some(addr..end)
}
#[inline(always)]
pub(crate) fn grow_to(&mut self, new_len: usize) -> Result<(), crate::Trap> {
debug_assert!(new_len >= self.data.len(), "memory only grows");
cold_err!(self.data.try_reserve(new_len - self.data.len())).map_err(|_| crate::Trap::OutOfMemory)?;
self.data.resize(new_len, 0);
Ok(())
}
#[inline(always)]
pub(crate) fn read_fixed<const N: usize>(&self, addr: usize) -> Result<[u8; N], crate::Trap> {
if N > self.data.len() || addr > self.data.len() - N {
return cold!(Err(memory_oob(addr, N, self.data.len())));
}
let mut bytes = [0u8; N];
bytes.copy_from_slice(&self.data[addr..addr + N]);
Ok(bytes)
}
#[inline(always)]
pub(crate) fn write_fixed<const N: usize>(&mut self, addr: usize, bytes: &[u8; N]) -> Result<(), crate::Trap> {
if N > self.data.len() || addr > self.data.len() - N {
return cold!(Err(memory_oob(addr, N, self.data.len())));
}
self.data[addr..addr + N].copy_from_slice(bytes);
Ok(())
}
#[inline(always)]
pub(crate) fn read(&self, addr: usize, dst: &mut [u8]) -> usize {
if addr >= self.data.len() {
return 0;
}
let read_len = dst.len().min(self.data.len() - addr);
dst[..read_len].copy_from_slice(&self.data[addr..addr + read_len]);
read_len
}
#[inline(always)]
pub(crate) fn write(&mut self, addr: usize, src: &[u8]) -> usize {
if addr >= self.data.len() {
return 0;
}
let write_len = src.len().min(self.data.len() - addr);
self.data[addr..addr + write_len].copy_from_slice(&src[..write_len]);
write_len
}
#[inline(always)]
pub(crate) fn read_exact(&self, addr: usize, dst: &mut [u8]) -> Option<()> {
dst.copy_from_slice(&self.data[self.checked_range(addr, dst.len())?]);
Some(())
}
#[inline(always)]
pub(crate) fn read_vec(&self, addr: usize, len: usize) -> Option<Vec<u8>> {
Some(self.data[self.checked_range(addr, len)?].to_vec())
}
#[inline(always)]
pub(crate) fn write_all(&mut self, addr: usize, src: &[u8]) -> Option<()> {
let range = self.checked_range(addr, src.len())?;
self.data[range].copy_from_slice(src);
Some(())
}
#[inline(always)]
pub(crate) fn fill(&mut self, addr: usize, len: usize, val: u8) -> Option<()> {
let range = self.checked_range(addr, len)?;
self.data[range].fill(val);
Some(())
}
#[inline(always)]
pub(crate) fn copy_within(&mut self, dst: usize, src: usize, len: usize) -> Option<()> {
let src = self.checked_range(src, len)?;
self.checked_range(dst, len)?;
self.data.copy_within(src, dst);
Some(())
}
#[inline(always)]
pub(super) fn copy_from(
&mut self,
dst: usize,
src_memory: &Self,
src: usize,
len: usize,
) -> Result<(), crate::Trap> {
let src_range =
cold_err!(src_memory.checked_range(src, len).ok_or_else(|| memory_oob(src, len, src_memory.len())))?;
let dst_range = cold_err!(self.checked_range(dst, len).ok_or_else(|| memory_oob(dst, len, self.len())))?;
self.data[dst_range].copy_from_slice(&src_memory.data[src_range]);
Ok(())
}
}