use crate::{
collections::arena::ArenaIndex,
core::{UntypedVal, ValType},
module,
store::Stored,
AsContext,
AsContextMut,
Func,
FuncRef,
Global,
Val,
};
use std::boxed::Box;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct ElementSegmentIdx(u32);
impl ArenaIndex for ElementSegmentIdx {
fn into_usize(self) -> usize {
self.0 as usize
}
fn from_usize(value: usize) -> Self {
let value = value.try_into().unwrap_or_else(|error| {
panic!("index {value} is out of bounds as element segment index: {error}")
});
Self(value)
}
}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct ElementSegment(Stored<ElementSegmentIdx>);
impl ElementSegment {
pub fn from_inner(stored: Stored<ElementSegmentIdx>) -> Self {
Self(stored)
}
pub fn as_inner(&self) -> &Stored<ElementSegmentIdx> {
&self.0
}
pub fn new(
mut ctx: impl AsContextMut,
elem: &module::ElementSegment,
get_func: impl Fn(u32) -> Func,
get_global: impl Fn(u32) -> Global,
) -> Self {
let get_func = |index| get_func(index).into();
let get_global = |index| get_global(index).get(&ctx);
let entity = ElementSegmentEntity::new(elem, get_func, get_global);
ctx.as_context_mut()
.store
.inner
.alloc_element_segment(entity)
}
pub fn size(&self, ctx: impl AsContext) -> u32 {
ctx.as_context()
.store
.inner
.resolve_element_segment(self)
.size()
}
}
#[derive(Debug)]
pub struct ElementSegmentEntity {
ty: ValType,
items: Box<[UntypedVal]>,
}
impl ElementSegmentEntity {
pub fn new(
elem: &'_ module::ElementSegment,
get_func: impl Fn(u32) -> FuncRef,
get_global: impl Fn(u32) -> Val,
) -> Self {
let ty = elem.ty();
match elem.kind() {
module::ElementSegmentKind::Passive | module::ElementSegmentKind::Active(_) => {
let items = elem
.items()
.iter()
.map(|const_expr| {
const_expr.eval_with_context(&get_global, &get_func).unwrap_or_else(|| {
panic!("unexpected failed initialization of constant expression: {const_expr:?}")
})
}).collect::<Box<[_]>>();
Self {
ty,
items,
}
}
module::ElementSegmentKind::Declared => Self::empty(ty),
}
}
fn empty(ty: ValType) -> Self {
Self {
ty,
items: [].into(),
}
}
pub fn ty(&self) -> ValType {
self.ty
}
pub fn size(&self) -> u32 {
self.items().len() as u32
}
pub fn items(&self) -> &[UntypedVal] {
&self.items[..]
}
pub fn drop_items(&mut self) {
self.items = [].into();
}
}