use super::{InitExpr, TableIdx};
use crate::{errors::ModuleError, module::utils::WasmiValueType};
use alloc::sync::Arc;
use wasmi_core::ValueType;
#[derive(Debug)]
pub struct ElementSegment {
kind: ElementSegmentKind,
ty: ValueType,
items: ElementSegmentItems,
}
#[derive(Debug, Clone)]
pub struct ElementSegmentItems {
exprs: Arc<[InitExpr]>,
}
impl ElementSegmentItems {
fn new(items: &wasmparser::ElementItems) -> Self {
let exprs = items
.get_items_reader()
.unwrap_or_else(|error| panic!("failed to parse element items: {error}"))
.into_iter()
.map(|item| {
let item = item.as_ref().unwrap_or_else(|error| {
panic!("failed to parse element item {item:?}: {error}")
});
match item {
wasmparser::ElementItem::Func(func_index) => InitExpr::new_funcref(*func_index),
wasmparser::ElementItem::Expr(expr) => InitExpr::new(*expr),
}
})
.collect::<Arc<[_]>>();
Self { exprs }
}
pub fn items(&self) -> &[InitExpr] {
&self.exprs
}
}
#[derive(Debug)]
pub enum ElementSegmentKind {
Passive,
Active(ActiveElementSegment),
Declared,
}
#[derive(Debug)]
pub struct ActiveElementSegment {
table_index: TableIdx,
offset: InitExpr,
}
impl ActiveElementSegment {
pub fn table_index(&self) -> TableIdx {
self.table_index
}
pub fn offset(&self) -> &InitExpr {
&self.offset
}
}
impl TryFrom<wasmparser::ElementKind<'_>> for ElementSegmentKind {
type Error = ModuleError;
fn try_from(element_kind: wasmparser::ElementKind<'_>) -> Result<Self, Self::Error> {
match element_kind {
wasmparser::ElementKind::Active {
table_index,
offset_expr,
} => {
let table_index = TableIdx(table_index);
let offset = InitExpr::new(offset_expr);
Ok(Self::Active(ActiveElementSegment {
table_index,
offset,
}))
}
wasmparser::ElementKind::Passive => Ok(Self::Passive),
wasmparser::ElementKind::Declared => Ok(Self::Declared),
}
}
}
impl TryFrom<wasmparser::Element<'_>> for ElementSegment {
type Error = ModuleError;
fn try_from(element: wasmparser::Element<'_>) -> Result<Self, Self::Error> {
assert!(
element.ty.is_reference_type(),
"only reftypes are allowed as element types but found: {:?}",
element.ty
);
let kind = ElementSegmentKind::try_from(element.kind)?;
let ty = WasmiValueType::from(element.ty).into_inner();
let items = ElementSegmentItems::new(&element.items);
Ok(ElementSegment { kind, ty, items })
}
}
impl ElementSegment {
pub fn kind(&self) -> &ElementSegmentKind {
&self.kind
}
pub fn ty(&self) -> ValueType {
self.ty
}
pub fn items_cloned(&self) -> ElementSegmentItems {
self.items.clone()
}
}