use std::{marker::PhantomData, mem::MaybeUninit, ops::Range};
use super::{Memory, MemoryBuffer};
use crate::{AsStoreRef, MemoryAccessError};
use rusty_jsc::JSObject;
use wasmer_types::{Bytes, Pages};
#[derive(Debug)]
pub struct MemoryView<'a> {
pub(crate) buffer: MemoryBuffer<'a>,
}
impl<'a> MemoryView<'a> {
pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self {
Self::new_raw(&memory.handle.memory, store)
}
pub(crate) fn new_raw(memory: &JSObject, store: &'a (impl AsStoreRef + ?Sized)) -> Self {
let store_ref = store.as_store_ref();
let engine = store_ref.engine();
let context = engine.as_jsc().context();
let buffer = memory
.get_property(context, "buffer".to_string())
.to_object(context)
.unwrap();
let typed_buffer = JSObject::create_typed_array_from_buffer(context, buffer).unwrap();
let mut buffer_data = typed_buffer.get_typed_array_buffer(context).unwrap();
Self {
buffer: MemoryBuffer {
base: buffer_data.as_mut_ptr(),
len: buffer_data.len(),
marker: PhantomData,
},
}
}
#[doc(hidden)]
pub fn data_ptr(&self) -> *mut u8 {
self.buffer.base
}
pub fn data_size(&self) -> u64 {
self.buffer.len.try_into().unwrap()
}
#[doc(hidden)]
pub unsafe fn data_unchecked(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.buffer.base, self.buffer.len) }
}
#[allow(clippy::mut_from_ref)]
#[doc(hidden)]
pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.buffer.base, self.buffer.len) }
}
pub fn size(&self) -> Pages {
Bytes(self.buffer.len).try_into().unwrap()
}
#[inline]
pub(crate) fn buffer(&'a self) -> MemoryBuffer<'a> {
self.buffer
}
pub fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> {
self.buffer.read(offset, buf)
}
pub fn read_u8(&self, offset: u64) -> Result<u8, MemoryAccessError> {
let mut buf = [0u8; 1];
self.read(offset, &mut buf)?;
Ok(buf[0])
}
pub fn read_uninit<'b>(
&self,
offset: u64,
buf: &'b mut [MaybeUninit<u8>],
) -> Result<&'b mut [u8], MemoryAccessError> {
self.buffer.read_uninit(offset, buf)
}
pub fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> {
self.buffer.write(offset, data)
}
pub fn write_u8(&self, offset: u64, val: u8) -> Result<(), MemoryAccessError> {
let buf = [val];
self.write(offset, &buf)?;
Ok(())
}
#[allow(unused)]
pub fn copy_to_vec(&self) -> Result<Vec<u8>, MemoryAccessError> {
self.copy_range_to_vec(0..self.data_size())
}
#[allow(unused)]
pub fn copy_range_to_vec(&self, range: Range<u64>) -> Result<Vec<u8>, MemoryAccessError> {
let mut new_memory = Vec::new();
let mut offset = range.start;
let end = range.end.min(self.data_size());
let mut chunk = [0u8; 40960];
while offset < end {
let remaining = end - offset;
let sublen = remaining.min(chunk.len() as u64) as usize;
self.read(offset, &mut chunk[..sublen])?;
new_memory.extend_from_slice(&chunk[..sublen]);
offset += sublen as u64;
}
Ok(new_memory)
}
#[allow(unused)]
pub fn copy_to_memory(&self, amount: u64, new_memory: &Self) -> Result<(), MemoryAccessError> {
let mut offset = 0;
let mut chunk = [0u8; 40960];
while offset < amount {
let remaining = amount - offset;
let sublen = remaining.min(chunk.len() as u64) as usize;
self.read(offset, &mut chunk[..sublen])?;
new_memory.write(offset, &chunk[..sublen])?;
offset += sublen as u64;
}
Ok(())
}
}