1use {
2 crate::{
3 decode::{Decode, DecodeError, Decoder},
4 downcast::{DowncastMut, DowncastRef},
5 elem::{Elem, ElemEntity, ElemEntityT},
6 extern_ref::UnguardedExternRef,
7 func_ref::UnguardedFuncRef,
8 limits::Limits,
9 ref_::{Ref, RefType, UnguardedRef},
10 store::{Handle, HandlePair, Store, StoreId, UnguardedHandle},
11 trap::Trap,
12 },
13 std::{error::Error, fmt},
14};
15
16#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
18#[repr(transparent)]
19pub struct Table(pub(crate) Handle<TableEntity>);
20
21impl Table {
22 pub fn new(store: &mut Store, type_: TableType, val: Ref) -> Result<Self, TableError> {
35 assert!(type_.is_valid(), "invalid table type");
36 unsafe { Self::new_unguarded(store, type_, val.to_unguarded(store.id())) }
37 }
38
39 unsafe fn new_unguarded(
41 store: &mut Store,
42 type_: TableType,
43 val: UnguardedRef,
44 ) -> Result<Self, TableError> {
45 match (type_.elem, val) {
46 (RefType::FuncRef, UnguardedRef::FuncRef(val)) => Ok(Self(
47 store.insert_table(TableEntity::FuncRef(TableEntityT::new(type_.limits, val))),
48 )),
49 (RefType::ExternRef, UnguardedRef::ExternRef(val)) => Ok(Self(
50 store.insert_table(TableEntity::ExternRef(TableEntityT::new(type_.limits, val))),
51 )),
52 _ => Err(TableError::ElemTypeMismatch),
53 }
54 }
55
56 pub fn type_(self, store: &Store) -> TableType {
58 match self.0.as_ref(store) {
59 TableEntity::FuncRef(table) => TableType {
60 limits: table.limits(),
61 elem: RefType::FuncRef,
62 },
63 TableEntity::ExternRef(table) => TableType {
64 limits: table.limits(),
65 elem: RefType::ExternRef,
66 },
67 }
68 }
69
70 pub fn get(self, store: &Store, idx: u32) -> Option<Ref> {
76 self.get_unguarded(store, idx)
77 .map(|val| unsafe { Ref::from_unguarded(val, store.id()) })
78 }
79
80 fn get_unguarded(self, store: &Store, idx: u32) -> Option<UnguardedRef> {
82 match self.0.as_ref(store) {
83 TableEntity::FuncRef(table) => table.get(idx).map(UnguardedRef::FuncRef),
84 TableEntity::ExternRef(table) => table.get(idx).map(UnguardedRef::ExternRef),
85 }
86 }
87
88 pub fn set(self, store: &mut Store, idx: u32, val: Ref) -> Result<(), TableError> {
100 unsafe { self.set_unguarded(store, idx, val.to_unguarded(store.id())) }
101 }
102
103 unsafe fn set_unguarded(
105 self,
106 store: &mut Store,
107 idx: u32,
108 val: UnguardedRef,
109 ) -> Result<(), TableError> {
110 match (self.0.as_mut(store), val) {
111 (TableEntity::FuncRef(table), UnguardedRef::FuncRef(val)) => table.set(idx, val),
112 (TableEntity::ExternRef(table), UnguardedRef::ExternRef(val)) => table.set(idx, val),
113 _ => Err(TableError::ElemTypeMismatch),
114 }
115 }
116
117 pub fn size(&self, store: &Store) -> u32 {
119 match self.0.as_ref(store) {
120 TableEntity::FuncRef(table) => table.size(),
121 TableEntity::ExternRef(table) => table.size(),
122 }
123 }
124
125 pub fn grow(self, store: &mut Store, val: Ref, count: u32) -> Result<(), TableError> {
139 unsafe { self.grow_unguarded(store, val.to_unguarded(store.id()), count) }
140 }
141
142 unsafe fn grow_unguarded(
144 self,
145 store: &mut Store,
146 val: UnguardedRef,
147 count: u32,
148 ) -> Result<(), TableError> {
149 match (self.0.as_mut(store), val) {
150 (TableEntity::FuncRef(table), UnguardedRef::FuncRef(val)) => table.grow(val, count),
151 (TableEntity::ExternRef(table), UnguardedRef::ExternRef(val)) => table.grow(val, count),
152 _ => Err(TableError::ElemTypeMismatch),
153 }
154 .map(|_| ())
155 }
156
157 pub(crate) fn init(
158 self,
159 store: &mut Store,
160 dst_idx: u32,
161 src_elem: Elem,
162 src_idx: u32,
163 count: u32,
164 ) -> Result<(), Trap> {
165 let (dst_table, src_elem) = HandlePair(self.0, src_elem.0).as_mut_pair(store);
166 match (dst_table, src_elem) {
167 (TableEntity::FuncRef(table), ElemEntity::FuncRef(src_elem)) => {
168 table.init(dst_idx, src_elem, src_idx, count)
169 }
170 (TableEntity::ExternRef(table), ElemEntity::ExternRef(src_elem)) => {
171 table.init(dst_idx, src_elem, src_idx, count)
172 }
173 _ => panic!(),
174 }
175 }
176
177 pub(crate) unsafe fn from_unguarded(table: UnguardedTable, store_id: StoreId) -> Self {
183 Self(Handle::from_unguarded(table, store_id))
184 }
185
186 pub(crate) fn to_unguarded(self, store_id: StoreId) -> UnguardedTable {
192 self.0.to_unguarded(store_id)
193 }
194}
195
196pub(crate) type UnguardedTable = UnguardedHandle<TableEntity>;
198
199#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
201pub struct TableType {
202 pub limits: Limits,
204 pub elem: RefType,
206}
207
208impl TableType {
209 pub fn is_valid(self) -> bool {
213 if !self.limits.is_valid(u32::MAX) {
214 return false;
215 }
216 true
217 }
218
219 pub fn is_subtype_of(self, other: Self) -> bool {
224 if !self.limits.is_sublimit_of(other.limits) {
225 return false;
226 }
227 if self.elem != other.elem {
228 return false;
229 }
230 true
231 }
232}
233
234impl Decode for TableType {
235 fn decode(decoder: &mut Decoder<'_>) -> Result<Self, DecodeError> {
236 let elem = decoder.decode()?;
237 let limits = decoder.decode()?;
238 Ok(Self { limits, elem })
239 }
240}
241
242#[derive(Clone, Copy, Debug)]
244#[non_exhaustive]
245pub enum TableError {
246 AccessOutOfBounds,
247 ElemTypeMismatch,
248 FailedToGrow,
249}
250
251impl fmt::Display for TableError {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 match self {
254 Self::AccessOutOfBounds => write!(f, "table access out of bounds"),
255 Self::ElemTypeMismatch => write!(f, "table element type mismatch"),
256 Self::FailedToGrow => write!(f, "table failed to grow"),
257 }
258 }
259}
260
261impl Error for TableError {}
262
263#[derive(Debug)]
265pub(crate) enum TableEntity {
266 FuncRef(TableEntityT<UnguardedFuncRef>),
267 ExternRef(TableEntityT<UnguardedExternRef>),
268}
269
270impl TableEntity {
271 pub(crate) fn downcast_ref<T>(&self) -> Option<&TableEntityT<T>>
274 where
275 TableEntityT<T>: DowncastRef<Self>,
276 {
277 TableEntityT::downcast_ref(self)
278 }
279
280 pub(crate) fn downcast_mut<T>(&mut self) -> Option<&mut TableEntityT<T>>
283 where
284 TableEntityT<T>: DowncastMut<Self>,
285 {
286 TableEntityT::downcast_mut(self)
287 }
288}
289
290#[derive(Debug)]
292pub(crate) struct TableEntityT<T> {
293 max: Option<u32>,
294 elems: Vec<T>,
295}
296
297impl<T> TableEntityT<T>
298where
299 T: Copy,
300{
301 fn new(limits: Limits, val: T) -> Self {
303 let min = limits.min as usize;
304 Self {
305 max: limits.max,
306 elems: vec![val; min],
307 }
308 }
309
310 fn limits(&self) -> Limits {
312 Limits {
313 min: u32::try_from(self.elems.len()).unwrap(),
314 max: self.max,
315 }
316 }
317
318 pub(crate) fn get(&self, idx: u32) -> Option<T> {
324 let idx = idx as usize;
325 let elem = self.elems.get(idx)?;
326 Some(*elem)
327 }
328
329 pub(crate) fn set(&mut self, idx: u32, val: T) -> Result<(), TableError> {
335 let idx = idx as usize;
336 let elem = self
337 .elems
338 .get_mut(idx)
339 .ok_or(TableError::AccessOutOfBounds)?;
340 *elem = val;
341 Ok(())
342 }
343
344 pub(crate) fn size(&self) -> u32 {
346 self.elems.len() as u32
347 }
348
349 pub(crate) fn grow(&mut self, val: T, count: u32) -> Result<u32, TableError> {
358 if count > self.max.unwrap_or(u32::MAX) - self.size() {
359 return Err(TableError::FailedToGrow)?;
360 }
361 let count = count as usize;
362 let size = self.size();
363 self.elems.resize(self.elems.len() + count, val);
364 Ok(size)
365 }
366
367 pub(crate) fn fill(&mut self, idx: u32, val: T, count: u32) -> Result<(), Trap> {
368 let idx = idx as usize;
369 let count = count as usize;
370 let elems = self
371 .elems
372 .get_mut(idx..)
373 .and_then(|elems| elems.get_mut(..count))
374 .ok_or(Trap::TableAccessOutOfBounds)?;
375 elems.fill(val);
376 Ok(())
377 }
378
379 pub(crate) fn copy(
380 &mut self,
381 dst_idx: u32,
382 src_table: &TableEntityT<T>,
383 src_idx: u32,
384 count: u32,
385 ) -> Result<(), Trap> {
386 let dst_idx = dst_idx as usize;
387 let src_idx = src_idx as usize;
388 let count = count as usize;
389 let dst_elems = self
390 .elems
391 .get_mut(dst_idx..)
392 .and_then(|elems| elems.get_mut(..count))
393 .ok_or(Trap::TableAccessOutOfBounds)?;
394 let src_elems = src_table
395 .elems
396 .get(src_idx..)
397 .and_then(|elems| elems.get(..count))
398 .ok_or(Trap::TableAccessOutOfBounds)?;
399 dst_elems.copy_from_slice(src_elems);
400 Ok(())
401 }
402
403 pub(crate) fn copy_within(
404 &mut self,
405 dst_idx: u32,
406 src_idx: u32,
407 count: u32,
408 ) -> Result<(), Trap> {
409 let dst_idx = dst_idx as usize;
410 let src_idx = src_idx as usize;
411 let count = count as usize;
412 if count > self.elems.len()
413 || dst_idx > self.elems.len() - count
414 || src_idx > self.elems.len() - count
415 {
416 return Err(Trap::TableAccessOutOfBounds)?;
417 }
418 self.elems.copy_within(src_idx..src_idx + count, dst_idx);
419 Ok(())
420 }
421
422 pub(crate) fn init(
423 &mut self,
424 dst_idx: u32,
425 src_elem: &ElemEntityT<T>,
426 src_idx: u32,
427 count: u32,
428 ) -> Result<(), Trap> {
429 let dst_idx = dst_idx as usize;
430 let src_idx = src_idx as usize;
431 let count = count as usize;
432 let dst_elems = self
433 .elems
434 .get_mut(dst_idx..)
435 .and_then(|elems| elems.get_mut(..count))
436 .ok_or(Trap::TableAccessOutOfBounds)?;
437 let src_elems = src_elem
438 .elems()
439 .get(src_idx..)
440 .and_then(|elems| elems.get(..count))
441 .ok_or(Trap::TableAccessOutOfBounds)?;
442 dst_elems.copy_from_slice(src_elems);
443 Ok(())
444 }
445}
446
447impl DowncastRef<TableEntity> for TableEntityT<UnguardedFuncRef> {
448 fn downcast_ref(table: &TableEntity) -> Option<&Self> {
449 match table {
450 TableEntity::FuncRef(table) => Some(table),
451 _ => None,
452 }
453 }
454}
455
456impl DowncastMut<TableEntity> for TableEntityT<UnguardedFuncRef> {
457 fn downcast_mut(table: &mut TableEntity) -> Option<&mut Self> {
458 match table {
459 TableEntity::FuncRef(table) => Some(table),
460 _ => None,
461 }
462 }
463}
464
465impl DowncastRef<TableEntity> for TableEntityT<UnguardedExternRef> {
466 fn downcast_ref(table: &TableEntity) -> Option<&Self> {
467 match table {
468 TableEntity::ExternRef(table) => Some(table),
469 _ => None,
470 }
471 }
472}
473
474impl DowncastMut<TableEntity> for TableEntityT<UnguardedExternRef> {
475 fn downcast_mut(table: &mut TableEntity) -> Option<&mut Self> {
476 match table {
477 TableEntity::ExternRef(table) => Some(table),
478 _ => None,
479 }
480 }
481}