wasmi/table/
element.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use crate::{
    collections::arena::ArenaIndex,
    core::{UntypedVal, ValType},
    module,
    store::Stored,
    AsContext,
    AsContextMut,
    Func,
    FuncRef,
    Global,
    Val,
};
use std::boxed::Box;

/// A raw index to a element segment entity.
#[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)
    }
}

/// A Wasm data segment reference.
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct ElementSegment(Stored<ElementSegmentIdx>);

impl ElementSegment {
    /// Creates a new linear memory reference.
    pub fn from_inner(stored: Stored<ElementSegmentIdx>) -> Self {
        Self(stored)
    }

    /// Returns the underlying stored representation.
    pub fn as_inner(&self) -> &Stored<ElementSegmentIdx> {
        &self.0
    }

    /// Allocates a new [`ElementSegment`] on the store.
    ///
    /// # Errors
    ///
    /// If more than [`u32::MAX`] much linear memory is allocated.
    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)
    }

    /// Returns the number of items in the [`ElementSegment`].
    pub fn size(&self, ctx: impl AsContext) -> u32 {
        ctx.as_context()
            .store
            .inner
            .resolve_element_segment(self)
            .size()
    }
}

/// An instantiated [`ElementSegmentEntity`].
///
/// # Note
///
/// With the `bulk-memory` Wasm proposal it is possible to interact
/// with element segments at runtime. Therefore Wasm instances now have
/// a need to have an instantiated representation of data segments.
#[derive(Debug)]
pub struct ElementSegmentEntity {
    /// The [`ValType`] of elements of this [`ElementSegmentEntity`].
    ty: ValType,
    /// Pre-resolved untyped items of the Wasm element segment.
    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: Some(elem.items_cloned()),
                    items,
                }
            }
            module::ElementSegmentKind::Declared => Self::empty(ty),
        }
    }

    /// Create an empty [`ElementSegmentEntity`] representing dropped element segments.
    fn empty(ty: ValType) -> Self {
        Self {
            ty,
            items: [].into(),
        }
    }

    /// Returns the [`ValType`] of elements in the [`ElementSegmentEntity`].
    pub fn ty(&self) -> ValType {
        self.ty
    }

    /// Returns the number of items in the [`ElementSegment`].
    pub fn size(&self) -> u32 {
        self.items().len() as u32
    }

    /// Returns the items of the [`ElementSegmentEntity`].
    pub fn items(&self) -> &[UntypedVal] {
        &self.items[..]
    }

    /// Drops the items of the [`ElementSegmentEntity`].
    pub fn drop_items(&mut self) {
        self.items = [].into();
    }
}