use crate::store::{StoreId, StoreOpaque};
use crate::StoreContextMut;
use anyhow::{bail, Result};
use std::ptr::NonNull;
use wasmtime_environ::component::StringEncoding;
use wasmtime_runtime::{VMCallerCheckedFuncRef, VMMemoryDefinition};
#[derive(Copy, Clone)]
pub struct Options {
store_id: StoreId,
memory: Option<NonNull<VMMemoryDefinition>>,
realloc: Option<NonNull<VMCallerCheckedFuncRef>>,
string_encoding: StringEncoding,
}
unsafe impl Send for Options {}
unsafe impl Sync for Options {}
impl Options {
pub unsafe fn new(
store_id: StoreId,
memory: Option<NonNull<VMMemoryDefinition>>,
realloc: Option<NonNull<VMCallerCheckedFuncRef>>,
string_encoding: StringEncoding,
) -> Options {
Options {
store_id,
memory,
realloc,
string_encoding,
}
}
fn realloc<'a, T>(
&self,
store: &'a mut StoreContextMut<'_, T>,
old: usize,
old_size: usize,
old_align: u32,
new_size: usize,
) -> Result<(&'a mut [u8], usize)> {
self.store_id.assert_belongs_to(store.0.id());
let realloc = self.realloc.unwrap();
let result = unsafe {
crate::TypedFunc::<(u32, u32, u32, u32), u32>::call_raw(
store,
realloc,
(
u32::try_from(old)?,
u32::try_from(old_size)?,
old_align,
u32::try_from(new_size)?,
),
)?
};
if result % old_align != 0 {
bail!("realloc return: result not aligned");
}
let result = usize::try_from(result)?;
let memory = self.memory_mut(store.0);
let result_slice = match memory.get_mut(result..).and_then(|s| s.get_mut(..new_size)) {
Some(end) => end,
None => bail!("realloc return: beyond end of memory"),
};
Ok((result_slice, result))
}
pub fn memory<'a>(&self, store: &'a StoreOpaque) -> &'a [u8] {
self.store_id.assert_belongs_to(store.id());
unsafe {
let memory = self.memory.unwrap().as_ref();
std::slice::from_raw_parts(memory.base, memory.current_length())
}
}
pub fn memory_mut<'a>(&self, store: &'a mut StoreOpaque) -> &'a mut [u8] {
self.store_id.assert_belongs_to(store.id());
unsafe {
let memory = self.memory.unwrap().as_ref();
std::slice::from_raw_parts_mut(memory.base, memory.current_length())
}
}
pub fn string_encoding(&self) -> StringEncoding {
self.string_encoding
}
}
pub struct MemoryMut<'a, T> {
store: StoreContextMut<'a, T>,
options: &'a Options,
}
#[doc(hidden)]
impl<'a, T> MemoryMut<'a, T> {
pub fn new(store: StoreContextMut<'a, T>, options: &'a Options) -> MemoryMut<'a, T> {
MemoryMut { options, store }
}
pub fn string_encoding(&self) -> StringEncoding {
self.options.string_encoding()
}
pub fn as_slice_mut(&mut self) -> &mut [u8] {
self.options.memory_mut(self.store.0)
}
pub fn realloc(
&mut self,
old: usize,
old_size: usize,
old_align: u32,
new_size: usize,
) -> Result<usize> {
self.options
.realloc(&mut self.store, old, old_size, old_align, new_size)
.map(|(_, ptr)| ptr)
}
pub fn get<const N: usize>(&mut self, offset: usize) -> &mut [u8; N] {
(&mut self.as_slice_mut()[offset..][..N])
.try_into()
.unwrap()
}
}
pub struct Memory<'a> {
pub(crate) store: &'a StoreOpaque,
options: &'a Options,
}
#[doc(hidden)]
impl<'a> Memory<'a> {
pub fn new(store: &'a StoreOpaque, options: &'a Options) -> Memory<'a> {
Memory { store, options }
}
pub fn as_slice(&self) -> &'a [u8] {
self.options.memory(self.store)
}
pub fn string_encoding(&self) -> StringEncoding {
self.options.string_encoding()
}
pub fn options(&self) -> &Options {
self.options
}
}