Coverage for wasmtime/_types.py: 89%
306 statements
« prev ^ index » next coverage.py v7.11.3, created at 2025-12-01 19:40 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2025-12-01 19:40 +0000
1import ctypes
2from ctypes import POINTER, byref
3from typing import Any, List, Optional, Union
5from wasmtime import Managed, WasmtimeError
7from . import _ffi as ffi
10class ValType(Managed["ctypes._Pointer[ffi.wasm_valtype_t]"]):
11 _owner: Optional[Any]
13 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_valtype_t]") -> None:
14 # If this is owned by another object we don't free it since that object
15 # is responsible for freeing the backing memory.
16 if self._owner is None:
17 ffi.wasm_valtype_delete(ptr)
19 @classmethod
20 def i32(cls) -> "ValType":
21 ptr = ffi.wasm_valtype_new(ffi.WASM_I32)
22 return ValType._from_ptr(ptr, None)
24 @classmethod
25 def i64(cls) -> "ValType":
26 ptr = ffi.wasm_valtype_new(ffi.WASM_I64)
27 return ValType._from_ptr(ptr, None)
29 @classmethod
30 def f32(cls) -> "ValType":
31 ptr = ffi.wasm_valtype_new(ffi.WASM_F32)
32 return ValType._from_ptr(ptr, None)
34 @classmethod
35 def f64(cls) -> "ValType":
36 ptr = ffi.wasm_valtype_new(ffi.WASM_F64)
37 return ValType._from_ptr(ptr, None)
39 @classmethod
40 def externref(cls) -> "ValType":
41 ptr = ffi.wasm_valtype_new(ffi.WASM_ANYREF)
42 return ValType._from_ptr(ptr, None)
44 @classmethod
45 def funcref(cls) -> "ValType":
46 ptr = ffi.wasm_valtype_new(ffi.WASM_FUNCREF)
47 return ValType._from_ptr(ptr, None)
49 def __init__(self) -> None:
50 raise WasmtimeError("cannot construct directly")
52 @classmethod
53 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_valtype_t]", owner: Optional[Any]) -> "ValType":
54 if not isinstance(ptr, POINTER(ffi.wasm_valtype_t)):
55 raise TypeError("wrong pointer type")
56 ty: "ValType" = cls.__new__(cls)
57 ty._set_ptr(ptr)
58 ty._owner = owner
59 return ty
61 def __eq__(self, other: object) -> bool:
62 if not isinstance(other, ValType):
63 return False
64 kind1 = ffi.wasm_valtype_kind(self.ptr())
65 kind2 = ffi.wasm_valtype_kind(other.ptr())
66 return kind1 == kind2
68 def __ne__(self, other: object) -> bool:
69 return not self.__eq__(other)
71 def __repr__(self) -> str:
72 return str(self)
74 def __str__(self) -> str:
75 kind = ffi.wasm_valtype_kind(self.ptr())
76 if kind == ffi.WASM_I32.value:
77 return 'i32'
78 if kind == ffi.WASM_I64.value:
79 return 'i64'
80 if kind == ffi.WASM_F32.value:
81 return 'f32'
82 if kind == ffi.WASM_F64.value:
83 return 'f64'
84 if kind == ffi.WASM_ANYREF.value:
85 return 'anyref'
86 if kind == ffi.WASM_FUNCREF.value:
87 return 'funcref'
88 return 'ValType(%d)' % kind.value
90 @classmethod
91 def _from_list(cls, items: "ctypes._Pointer[ffi.wasm_valtype_vec_t]", owner: Optional[Any]) -> List["ValType"]:
92 types = []
93 for i in range(0, items.contents.size):
94 types.append(ValType._from_ptr(items.contents.data[i], owner))
95 return types
98def take_owned_valtype(ty: ValType) -> "ctypes._Pointer[ffi.wasm_valtype_t]":
99 if not isinstance(ty, ValType):
100 raise TypeError("expected valtype")
102 # Need to allocate a new type because we need to take ownership.
103 #
104 # Trying to expose this as an implementation detail by sneaking out
105 # types and having some be "taken" feels pretty weird
106 return ffi.wasm_valtype_new(ffi.wasm_valtype_kind(ty.ptr()))
109class FuncType(Managed["ctypes._Pointer[ffi.wasm_functype_t]"]):
110 def __init__(self, params: List[ValType], results: List[ValType]):
111 for param in params:
112 if not isinstance(param, ValType):
113 raise TypeError("expected ValType")
114 for result in results:
115 if not isinstance(result, ValType):
116 raise TypeError("expected ValType")
118 params_ffi = ffi.wasm_valtype_vec_t()
119 ffi.wasm_valtype_vec_new_uninitialized(byref(params_ffi), len(params))
121 results_ffi = ffi.wasm_valtype_vec_t()
122 for i, param in enumerate(params):
123 params_ffi.data[i] = take_owned_valtype(param)
125 ffi.wasm_valtype_vec_new_uninitialized(
126 byref(results_ffi), len(results))
127 for i, result in enumerate(results):
128 results_ffi.data[i] = take_owned_valtype(result)
129 ptr = ffi.wasm_functype_new(byref(params_ffi), byref(results_ffi))
130 if not ptr:
131 raise WasmtimeError("failed to allocate FuncType")
132 self._set_ptr(ptr)
133 self._owner = None
135 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_functype_t]") -> None:
136 if self._owner is None:
137 ffi.wasm_functype_delete(ptr)
139 @classmethod
140 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_functype_t]", owner: Optional[Any]) -> "FuncType":
141 if not isinstance(ptr, POINTER(ffi.wasm_functype_t)):
142 raise TypeError("wrong pointer type")
143 ty: "FuncType" = cls.__new__(cls)
144 ty._set_ptr(ptr)
145 ty._owner = owner
146 return ty
148 @property
149 def params(self) -> List["ValType"]:
150 """
151 Returns the list of parameter types for this function type
152 """
154 ptr = ffi.wasm_functype_params(self.ptr())
155 return ValType._from_list(ptr, self)
157 @property
158 def results(self) -> List["ValType"]:
159 """
160 Returns the list of result types for this function type
161 """
163 ptr = ffi.wasm_functype_results(self.ptr())
164 return ValType._from_list(ptr, self)
166 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
167 return ffi.wasm_functype_as_externtype_const(self.ptr())
170class GlobalType(Managed["ctypes._Pointer[ffi.wasm_globaltype_t]"]):
171 def __init__(self, valtype: ValType, mutable: bool):
172 if mutable:
173 mutability = ffi.WASM_VAR
174 else:
175 mutability = ffi.WASM_CONST
176 type_ptr = take_owned_valtype(valtype)
177 ptr = ffi.wasm_globaltype_new(type_ptr, mutability)
178 if ptr == 0:
179 raise WasmtimeError("failed to allocate GlobalType")
180 self._set_ptr(ptr)
181 self._owner = None
183 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_globaltype_t]") -> None:
184 if self._owner is None:
185 ffi.wasm_globaltype_delete(ptr)
187 @classmethod
188 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_globaltype_t]", owner: Optional[Any]) -> "GlobalType":
189 if not isinstance(ptr, POINTER(ffi.wasm_globaltype_t)):
190 raise TypeError("wrong pointer type")
191 ty: "GlobalType" = cls.__new__(cls)
192 ty._set_ptr(ptr)
193 ty._owner = owner
194 return ty
196 @property
197 def content(self) -> ValType:
198 """
199 Returns the type this global contains
200 """
202 ptr = ffi.wasm_globaltype_content(self.ptr())
203 return ValType._from_ptr(ptr, self)
205 @property
206 def mutable(self) -> bool:
207 """
208 Returns whether this global is mutable or not
209 """
210 val = ffi.wasm_globaltype_mutability(self.ptr())
211 return val == ffi.WASM_VAR.value
213 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
214 return ffi.wasm_globaltype_as_externtype_const(self.ptr())
217class Limits:
218 def __init__(self, min: int, max: Optional[int]):
219 self.min = min
220 self.max = max
222 def __ffi__(self) -> ffi.wasm_limits_t:
223 max = self.max
224 if max is None:
225 max = 0xffffffff
226 return ffi.wasm_limits_t(self.min, max)
228 def __eq__(self, other: object) -> bool:
229 if not isinstance(other, Limits):
230 return False
231 return self.min == other.min and self.max == other.max
233 @classmethod
234 def _from_ffi(cls, val: 'ctypes._Pointer[ffi.wasm_limits_t]') -> "Limits":
235 min = val.contents.min
236 max = val.contents.max
237 if max == 0xffffffff:
238 return Limits(min, None)
239 return Limits(min, max)
242class TableType(Managed["ctypes._Pointer[ffi.wasm_tabletype_t]"]):
243 def __init__(self, valtype: ValType, limits: Limits):
244 if not isinstance(limits, Limits):
245 raise TypeError("expected Limits")
246 type_ptr = take_owned_valtype(valtype)
247 ptr = ffi.wasm_tabletype_new(type_ptr, byref(limits.__ffi__()))
248 if not ptr:
249 raise WasmtimeError("failed to allocate TableType")
250 self._set_ptr(ptr)
251 self._owner = None
253 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_tabletype_t]") -> None:
254 if self._owner is None:
255 ffi.wasm_tabletype_delete(ptr)
257 @classmethod
258 def _from_ptr(cls, ptr: 'ctypes._Pointer[ffi.wasm_tabletype_t]', owner: Optional[Any]) -> "TableType":
259 ty: "TableType" = cls.__new__(cls)
260 if not isinstance(ptr, POINTER(ffi.wasm_tabletype_t)):
261 raise TypeError("wrong pointer type")
262 ty._set_ptr(ptr)
263 ty._owner = owner
264 return ty
266 @property
267 def element(self) -> ValType:
268 """
269 Returns the type of this table's elements
270 """
271 ptr = ffi.wasm_tabletype_element(self.ptr())
272 return ValType._from_ptr(ptr, self)
274 @property
275 def limits(self) -> Limits:
276 """
277 Returns the limits on the size of thi stable
278 """
279 val = ffi.wasm_tabletype_limits(self.ptr())
280 return Limits._from_ffi(val)
282 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
283 return ffi.wasm_tabletype_as_externtype_const(self.ptr())
286class MemoryType(Managed["ctypes._Pointer[ffi.wasm_memorytype_t]"]):
287 def __init__(self, limits: Limits, is_64: bool = False, shared: bool = False,
288 page_size_log2: int = 16):
289 if not isinstance(limits, Limits):
290 raise TypeError("expected Limits")
291 if is_64:
292 maximum = 0x10000000000000000
293 else:
294 maximum = 0x100000000
295 if limits.min >= maximum:
296 raise WasmtimeError("minimum size too large")
297 if limits.max and limits.max >= maximum:
298 raise WasmtimeError("maximum size too large")
299 ptr = POINTER(ffi.wasm_memorytype_t)()
300 err = ffi.wasmtime_memorytype_new(limits.min,
301 limits.max is not None,
302 limits.max if limits.max else 0,
303 is_64,
304 shared,
305 page_size_log2,
306 byref(ptr))
307 if err:
308 raise WasmtimeError._from_ptr(err)
309 self._set_ptr(ptr)
310 self._owner = None
312 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_memorytype_t]") -> None:
313 if self._owner is None:
314 ffi.wasm_memorytype_delete(ptr)
316 @classmethod
317 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_memorytype_t]", owner: Optional[Any]) -> "MemoryType":
318 if not isinstance(ptr, POINTER(ffi.wasm_memorytype_t)):
319 raise TypeError("wrong pointer type")
320 ty: "MemoryType" = cls.__new__(cls)
321 ty._set_ptr(ptr)
322 ty._owner = owner
323 return ty
325 @property
326 def limits(self) -> Limits:
327 """
328 Returns the limits on the size of this table
329 """
330 minimum = ffi.wasmtime_memorytype_minimum(self.ptr())
331 maximum = ctypes.c_uint64(0)
332 has_max = ffi.wasmtime_memorytype_maximum(self.ptr(), byref(maximum))
333 return Limits(minimum, maximum.value if has_max else None)
335 @property
336 def is_64(self) -> bool:
337 """
338 Returns whether or not this is a 64-bit memory
339 """
340 return ffi.wasmtime_memorytype_is64(self.ptr())
342 @property
343 def is_shared(self) -> bool:
344 """
345 Returns whether or not this is a shared memory
346 """
347 return ffi.wasmtime_memorytype_isshared(self.ptr())
350 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
351 return ffi.wasm_memorytype_as_externtype_const(self.ptr())
354def wrap_externtype(ptr: "ctypes._Pointer[ffi.wasm_externtype_t]", owner: Optional[Any]) -> "AsExternType":
355 if not isinstance(ptr, POINTER(ffi.wasm_externtype_t)):
356 raise TypeError("wrong pointer type")
357 val = ffi.wasm_externtype_as_functype(ptr)
358 if val:
359 return FuncType._from_ptr(val, owner)
360 val = ffi.wasm_externtype_as_tabletype(ptr)
361 if val:
362 return TableType._from_ptr(val, owner)
363 val = ffi.wasm_externtype_as_globaltype(ptr)
364 if val:
365 return GlobalType._from_ptr(val, owner)
366 val = ffi.wasm_externtype_as_memorytype(ptr)
367 if val:
368 return MemoryType._from_ptr(val, owner)
369 raise WasmtimeError("unknown extern type")
372class ImportType(Managed["ctypes._Pointer[ffi.wasm_importtype_t]"]):
373 _owner: Optional[Any]
375 @classmethod
376 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]", owner: Optional[Any] = None) -> "ImportType":
377 if not isinstance(ptr, POINTER(ffi.wasm_importtype_t)):
378 raise TypeError("wrong pointer type")
379 ty: "ImportType" = cls.__new__(cls)
380 ty._set_ptr(ptr)
381 ty._owner = owner
382 return ty
384 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]") -> None:
385 if self._owner is None:
386 ffi.wasm_importtype_delete(ptr)
388 @property
389 def module(self) -> str:
390 """
391 Returns the module this import type refers to
392 """
394 return ffi.to_str(ffi.wasm_importtype_module(self.ptr()).contents)
396 @property
397 def name(self) -> Optional[str]:
398 """
399 Returns the name in the module this import type refers to
401 Note that `None` may be returned for the module linking proposal where
402 the field name is optional.
403 """
404 ptr = ffi.wasm_importtype_name(self.ptr())
405 if ptr:
406 return ffi.to_str(ptr.contents)
407 return None
409 @property
410 def type(self) -> "AsExternType":
411 """
412 Returns the type that this import refers to
413 """
414 ptr = ffi.wasm_importtype_type(self.ptr())
415 return wrap_externtype(ptr, self._owner or self)
418class ExportType(Managed["ctypes._Pointer[ffi.wasm_exporttype_t]"]):
419 _ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]"
420 _owner: Optional[Any]
422 @classmethod
423 def _from_ptr(cls, ptr: 'ctypes._Pointer[ffi.wasm_exporttype_t]', owner: Optional[Any] = None) -> "ExportType":
424 if not isinstance(ptr, POINTER(ffi.wasm_exporttype_t)):
425 raise TypeError("wrong pointer type")
426 ty: "ExportType" = cls.__new__(cls)
427 ty._set_ptr(ptr)
428 ty._owner = owner
429 return ty
431 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]") -> None:
432 if self._owner is None:
433 ffi.wasm_exporttype_delete(ptr)
435 @property
436 def name(self) -> str:
437 """
438 Returns the name in the modulethis export type refers to
439 """
440 return ffi.to_str(ffi.wasm_exporttype_name(self.ptr()).contents)
442 @property
443 def type(self) -> "AsExternType":
444 """
445 Returns the type that this export refers to
446 """
447 ptr = ffi.wasm_exporttype_type(self.ptr())
448 return wrap_externtype(ptr, self._owner or self)
451AsExternType = Union[FuncType, TableType, MemoryType, GlobalType]