Coverage for wasmtime/_table.py: 100%

50 statements  

« prev     ^ index     » next       coverage.py v7.11.3, created at 2025-12-01 19:40 +0000

1import ctypes 

2 

3from . import _ffi as ffi 

4from wasmtime import TableType, Store, WasmtimeError, Val 

5from typing import Optional, Any 

6from ._store import Storelike 

7 

8 

9class Table: 

10 _table: ffi.wasmtime_table_t 

11 

12 def __init__(self, store: Store, ty: TableType, init: Any): 

13 """ 

14 Creates a new table within `store` with the specified `ty`. 

15 """ 

16 

17 init_val = Val._convert_to_raw(store, ty.element, init) 

18 

19 table = ffi.wasmtime_table_t() 

20 error = ffi.wasmtime_table_new(store._context(), ty.ptr(), ctypes.byref(init_val), ctypes.byref(table)) 

21 ffi.wasmtime_val_unroot(ctypes.byref(init_val)) 

22 if error: 

23 raise WasmtimeError._from_ptr(error) 

24 self._table = table 

25 

26 @classmethod 

27 def _from_raw(cls, table: ffi.wasmtime_table_t) -> "Table": 

28 ty: "Table" = cls.__new__(cls) 

29 ty._table = table 

30 return ty 

31 

32 def type(self, store: Storelike) -> TableType: 

33 """ 

34 Gets the type of this table as a `TableType` 

35 """ 

36 

37 ptr = ffi.wasmtime_table_type(store._context(), ctypes.byref(self._table)) 

38 return TableType._from_ptr(ptr, None) 

39 

40 def size(self, store: Storelike) -> int: 

41 """ 

42 Gets the size, in elements, of this table 

43 """ 

44 return ffi.wasmtime_table_size(store._context(), ctypes.byref(self._table)) 

45 

46 def grow(self, store: Storelike, amt: int, init: Any) -> int: 

47 """ 

48 Grows this table by the specified number of slots, using the specified 

49 initializer for all new table slots. 

50 

51 Raises a `WasmtimeError` if the table could not be grown. 

52 Returns the previous size of the table otherwise. 

53 """ 

54 init_val = Val._convert_to_raw(store, self.type(store).element, init) 

55 prev = ctypes.c_uint64(0) 

56 error = ffi.wasmtime_table_grow(store._context(), ctypes.byref(self._table), ctypes.c_uint64(amt), ctypes.byref(init_val), ctypes.byref(prev)) 

57 ffi.wasmtime_val_unroot(ctypes.byref(init_val)) 

58 if error: 

59 raise WasmtimeError._from_ptr(error) 

60 return prev.value 

61 

62 def get(self, store: Store, idx: int) -> Optional[Any]: 

63 """ 

64 Gets an individual element within this table. 

65 

66 Returns `None` for null references in the table (i.e. a null `funcref` 

67 or a null `externref). 

68 

69 Returns a `Func` for non-null `funcref` table elements. 

70 

71 Returns the wrapped extern data for non-null `externref` table elements. 

72 

73 Returns `None` if `idx` is out of bounds. 

74 """ 

75 raw = ffi.wasmtime_val_t() 

76 ok = ffi.wasmtime_table_get(store._context(), ctypes.byref(self._table), idx, ctypes.byref(raw)) 

77 if not ok: 

78 return None 

79 val = Val._from_raw(store, raw) 

80 if val.value: 

81 return val.value 

82 else: 

83 return val 

84 

85 def set(self, store: Store, idx: int, val: Any) -> None: 

86 """ 

87 Sets an individual element within this table. 

88 

89 `idx` must be an integer index. 

90 

91 The `val` specified must be convertible into this table's element 

92 type. I.e. for a `funcref` table, `val` must either be a `Func` or 

93 `None`, and for an `externref` table, `val` may be any arbitrary 

94 external data. 

95 

96 Raises a `WasmtimeError` if `idx` is out of bounds. 

97 """ 

98 value = Val._convert_to_raw(store, self.type(store).element, val) 

99 error = ffi.wasmtime_table_set(store._context(), ctypes.byref(self._table), idx, ctypes.byref(value)) 

100 ffi.wasmtime_val_unroot(ctypes.byref(value)) 

101 if error: 

102 raise WasmtimeError._from_ptr(error) 

103 

104 def _as_extern(self) -> ffi.wasmtime_extern_t: 

105 union = ffi.wasmtime_extern_union(table=self._table) 

106 return ffi.wasmtime_extern_t(ffi.WASMTIME_EXTERN_TABLE, union)