use crate::limits::LimitsError;
#[cfg(doc)]
use crate::{ElementSegment, Func, Global, InstanceEntity, Memory, Table, memory::DataSegment};
#[derive(Debug, Copy, Clone)]
pub struct InstanceLayout {
end_memories: u32,
end_globals: u32,
end_tables: u32,
end_funcs: u32,
end_elems: u32,
end_datas: u32,
}
macro_rules! define_addr_types {
(
$( pub struct $name:ident(u32) = $ty:ty );* $(;)?
) => {
$(
#[doc = concat!("The 32-bit address of a [`", stringify!($ty), "`] within the [`InstanceEntity::handles`] buffer.")]
#[derive(Debug, Copy, Clone)]
pub struct $name(u32);
impl From<u32> for $name {
#[inline]
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<$name> for u32 {
#[inline]
fn from(addr: $name) -> Self {
addr.0
}
}
)*
};
}
define_addr_types! {
pub struct GlobalAddr(u32) = Global;
pub struct MemoryAddr(u32) = Memory;
pub struct TableAddr(u32) = Table;
pub struct FuncAddr(u32) = Func;
pub struct DataAddr(u32) = DataSegment;
pub struct ElemAddr(u32) = ElementSegment;
}
impl InstanceLayout {
pub(crate) fn build() -> InstanceLayoutBuilder {
InstanceLayoutBuilder::default()
}
pub(crate) fn uninit() -> Self {
Self {
end_globals: 0,
end_memories: 0,
end_tables: 0,
end_funcs: 0,
end_elems: 0,
end_datas: 0,
}
}
#[inline]
fn len_memories(&self) -> u32 {
self.end_memories
}
#[inline]
fn len_globals(&self) -> u32 {
self.end_globals - self.end_memories
}
#[inline]
fn len_tables(&self) -> u32 {
self.end_tables - self.end_globals
}
#[inline]
fn len_funcs(&self) -> u32 {
self.end_funcs - self.end_tables
}
#[inline]
fn len_elems(&self) -> u32 {
self.end_elems - self.end_funcs
}
#[inline]
fn len_datas(&self) -> u32 {
self.end_datas - self.end_elems
}
#[inline]
pub fn memory_addr(&self, index: u32) -> Option<MemoryAddr> {
if index >= self.len_memories() {
return None;
}
Some(MemoryAddr(index))
}
#[inline]
pub fn global_addr(&self, index: u32) -> Option<GlobalAddr> {
if index >= self.len_globals() {
return None;
}
Some(GlobalAddr(self.end_memories + index))
}
#[inline]
pub fn table_addr(&self, index: u32) -> Option<TableAddr> {
if index >= self.len_tables() {
return None;
}
Some(TableAddr(self.end_globals + index))
}
#[inline]
pub fn func_addr(&self, index: u32) -> Option<FuncAddr> {
if index >= self.len_funcs() {
return None;
}
Some(FuncAddr(self.end_tables + index))
}
#[inline]
pub fn elem_addr(&self, index: u32) -> Option<ElemAddr> {
if index >= self.len_elems() {
return None;
}
Some(ElemAddr(self.end_funcs + index))
}
#[inline]
pub fn data_addr(&self, index: u32) -> Option<DataAddr> {
if index >= self.len_datas() {
return None;
}
Some(DataAddr(self.end_elems + index))
}
}
#[derive(Debug, Default)]
pub struct InstanceLayoutBuilder {
memories: Option<u32>,
globals: Option<u32>,
tables: Option<u32>,
datas: Option<u32>,
elems: Option<u32>,
funcs: Option<u32>,
}
macro_rules! impl_builder {
(
$( pub fn $name:ident(&mut self, $len:ident: usize) -> Result<&mut Self, LimitsError> = ($ty:ident, $check_limit:expr));*
$(;)?
) => {
$(
#[doc = concat!("Initializes the number of [`", stringify!($ty), "`] handles in `self`.")]
pub fn $name(&mut self, $len: usize) -> Result<&mut Self, LimitsError> {
assert!(self.$name.is_none());
$check_limit($len)?;
let $name = $len as u32;
self.$name = Some($name);
Ok(self)
}
)*
};
}
impl InstanceLayoutBuilder {
impl_builder! {
pub fn memories(&mut self, len_memories: usize) -> Result<&mut Self, LimitsError> = (Memory, LimitsError::max_memory_count);
pub fn globals(&mut self, len_globals: usize) -> Result<&mut Self, LimitsError> = (Global, LimitsError::max_global_count);
pub fn tables(&mut self, len_tables: usize) -> Result<&mut Self, LimitsError> = (Table, LimitsError::max_table_count);
pub fn datas(&mut self, len_datas: usize) -> Result<&mut Self, LimitsError> = (DataSegment, LimitsError::max_data_count);
pub fn elems(&mut self, len_elems: usize) -> Result<&mut Self, LimitsError> = (ElementSegment, LimitsError::max_elem_count);
pub fn funcs(&mut self, len_funcs: usize) -> Result<&mut Self, LimitsError> = (Func, LimitsError::max_func_count);
}
pub fn finish(self) -> Result<InstanceLayout, LimitsError> {
let err = LimitsError::TooManyInstanceHandles;
let len_memories = self.memories.unwrap_or(0);
let len_globals = self.globals.unwrap_or(0);
let len_tables = self.tables.unwrap_or(0);
let len_datas = self.datas.unwrap_or(0);
let len_elems = self.elems.unwrap_or(0);
let len_funcs = self.funcs.unwrap_or(0);
let end_memories = len_memories;
let end_globals = end_memories.checked_add(len_globals).ok_or(err)?;
let end_tables = end_globals.checked_add(len_tables).ok_or(err)?;
let end_funcs = end_tables.checked_add(len_funcs).ok_or(err)?;
let end_elems = end_funcs.checked_add(len_elems).ok_or(err)?;
let end_datas = end_elems.checked_add(len_datas).ok_or(err)?;
Ok(InstanceLayout {
end_memories,
end_globals,
end_tables,
end_funcs,
end_elems,
end_datas,
})
}
}