1#![allow(clippy::len_without_is_empty)]
2extern crate radix_wasmi_arena as wasmi_arena;
3
4use super::{AsContext, AsContextMut, Func, Stored};
5use alloc::vec::Vec;
6use core::{fmt, fmt::Display};
7use wasmi_arena::ArenaIndex;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
11pub struct TableIdx(u32);
12
13impl ArenaIndex for TableIdx {
14 fn into_usize(self) -> usize {
15 self.0 as usize
16 }
17
18 fn from_usize(value: usize) -> Self {
19 let value = value.try_into().unwrap_or_else(|error| {
20 panic!("index {value} is out of bounds as table index: {error}")
21 });
22 Self(value)
23 }
24}
25
26#[derive(Debug)]
28#[non_exhaustive]
29pub enum TableError {
30 GrowOutOfBounds {
32 maximum: u32,
34 current: u32,
36 delta: u32,
38 },
39 AccessOutOfBounds {
41 current: u32,
43 offset: u32,
45 },
46 UnsatisfyingTableType {
48 unsatisfying: TableType,
50 required: TableType,
52 },
53}
54
55impl Display for TableError {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 match self {
58 Self::GrowOutOfBounds {
59 maximum,
60 current,
61 delta,
62 } => {
63 write!(
64 f,
65 "tried to grow table with size of {current} and maximum of \
66 {maximum} by {delta} out of bounds",
67 )
68 }
69 Self::AccessOutOfBounds { current, offset } => {
70 write!(
71 f,
72 "out of bounds access of table element {offset} \
73 of table with size {current}",
74 )
75 }
76 Self::UnsatisfyingTableType {
77 unsatisfying,
78 required,
79 } => {
80 write!(
81 f,
82 "table type {unsatisfying:?} does not satisfy requirements \
83 of {required:?}",
84 )
85 }
86 }
87 }
88}
89
90#[derive(Debug, Copy, Clone, PartialEq, Eq)]
92pub struct TableType {
93 min: u32,
95 max: Option<u32>,
99}
100
101impl TableType {
102 pub fn new(min: u32, max: Option<u32>) -> Self {
108 if let Some(max) = max {
109 assert!(min <= max);
110 }
111 Self { min, max }
112 }
113
114 pub fn minimum(self) -> u32 {
116 self.min
117 }
118
119 pub fn maximum(self) -> Option<u32> {
123 self.max
124 }
125
126 pub(crate) fn satisfies(&self, required: &TableType) -> Result<(), TableError> {
133 if required.minimum() > self.minimum() {
134 return Err(TableError::UnsatisfyingTableType {
135 unsatisfying: *self,
136 required: *required,
137 });
138 }
139 match (required.maximum(), self.maximum()) {
140 (None, _) => (),
141 (Some(max_required), Some(max)) if max_required >= max => (),
142 _ => {
143 return Err(TableError::UnsatisfyingTableType {
144 unsatisfying: *self,
145 required: *required,
146 });
147 }
148 }
149 Ok(())
150 }
151}
152
153#[derive(Debug, Clone)]
155pub struct TableEntity {
156 ty: TableType,
157 elements: Vec<Option<Func>>,
158}
159
160impl TableEntity {
161 pub fn new(ty: TableType) -> Self {
163 Self {
164 elements: vec![None; ty.minimum() as usize],
165 ty,
166 }
167 }
168
169 pub fn ty(&self) -> TableType {
171 self.ty
172 }
173
174 pub fn size(&self) -> u32 {
176 self.elements.len() as u32
177 }
178
179 pub fn grow(&mut self, delta: u32) -> Result<(), TableError> {
189 let maximum = self.ty.maximum().unwrap_or(u32::MAX);
190 let current = self.size();
191 let new_len = current
192 .checked_add(delta)
193 .filter(|&new_len| new_len <= maximum)
194 .ok_or(TableError::GrowOutOfBounds {
195 maximum,
196 current,
197 delta,
198 })? as usize;
199 self.elements.resize(new_len, None);
200 Ok(())
201 }
202
203 pub fn get(&self, index: u32) -> Result<Option<Func>, TableError> {
209 let element = self.elements.get(index as usize).copied().ok_or_else(|| {
210 TableError::AccessOutOfBounds {
211 current: self.size(),
212 offset: index,
213 }
214 })?;
215 Ok(element)
216 }
217
218 pub fn set(&mut self, index: u32, value: Option<Func>) -> Result<(), TableError> {
224 let current = self.size();
225 let element =
226 self.elements
227 .get_mut(index as usize)
228 .ok_or(TableError::AccessOutOfBounds {
229 current,
230 offset: index,
231 })?;
232 *element = value;
233 Ok(())
234 }
235}
236
237#[derive(Debug, Copy, Clone)]
239#[repr(transparent)]
240pub struct Table(Stored<TableIdx>);
241
242impl Table {
243 pub(super) fn from_inner(stored: Stored<TableIdx>) -> Self {
245 Self(stored)
246 }
247
248 pub(super) fn into_inner(self) -> Stored<TableIdx> {
250 self.0
251 }
252
253 pub fn new(mut ctx: impl AsContextMut, ty: TableType) -> Self {
255 ctx.as_context_mut().store.alloc_table(TableEntity::new(ty))
256 }
257
258 pub fn ty(&self, ctx: impl AsContext) -> TableType {
264 ctx.as_context().store.resolve_table(*self).ty()
265 }
266
267 pub fn size(&self, ctx: impl AsContext) -> u32 {
273 ctx.as_context().store.resolve_table(*self).size()
274 }
275
276 pub fn grow(&self, mut ctx: impl AsContextMut, delta: u32) -> Result<(), TableError> {
290 ctx.as_context_mut()
291 .store
292 .resolve_table_mut(*self)
293 .grow(delta)
294 }
295
296 pub fn get(&self, ctx: impl AsContext, index: u32) -> Result<Option<Func>, TableError> {
306 ctx.as_context().store.resolve_table(*self).get(index)
307 }
308
309 pub fn set(
319 &self,
320 mut ctx: impl AsContextMut,
321 index: u32,
322 value: Option<Func>,
323 ) -> Result<(), TableError> {
324 ctx.as_context_mut()
325 .store
326 .resolve_table_mut(*self)
327 .set(index, value)
328 }
329}