Coverage for wasmtime/_types.py: 89%
343 statements
« prev ^ index » next coverage.py v7.11.3, created at 2026-05-07 14:30 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2026-05-07 14:30 +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())
349 @property
350 def page_size(self) -> int:
351 """
352 Returns the page size, in bytes, of this memory type.
354 Defaults to 65536 (64 KiB). The custom-page-sizes proposal allows
355 opting into a page size of 1.
356 """
357 return ffi.wasmtime_memorytype_page_size(self.ptr())
359 @property
360 def page_size_log2(self) -> int:
361 """
362 Returns the log2 of this memory type's page size, in bytes.
363 """
364 return int(ffi.wasmtime_memorytype_page_size_log2(self.ptr()))
366 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
367 return ffi.wasm_memorytype_as_externtype_const(self.ptr())
370def wrap_externtype(ptr: "ctypes._Pointer[ffi.wasm_externtype_t]", owner: Optional[Any]) -> "AsExternType":
371 if not isinstance(ptr, POINTER(ffi.wasm_externtype_t)):
372 raise TypeError("wrong pointer type")
373 val = ffi.wasm_externtype_as_functype(ptr)
374 if val:
375 return FuncType._from_ptr(val, owner)
376 val = ffi.wasm_externtype_as_tabletype(ptr)
377 if val:
378 return TableType._from_ptr(val, owner)
379 val = ffi.wasm_externtype_as_globaltype(ptr)
380 if val:
381 return GlobalType._from_ptr(val, owner)
382 val = ffi.wasm_externtype_as_memorytype(ptr)
383 if val:
384 return MemoryType._from_ptr(val, owner)
385 val = ffi.wasm_externtype_as_tagtype(ptr)
386 if val:
387 return TagType._from_ptr(val, owner)
388 raise WasmtimeError("unknown extern type")
391class ImportType(Managed["ctypes._Pointer[ffi.wasm_importtype_t]"]):
392 _owner: Optional[Any]
394 @classmethod
395 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]", owner: Optional[Any] = None) -> "ImportType":
396 if not isinstance(ptr, POINTER(ffi.wasm_importtype_t)):
397 raise TypeError("wrong pointer type")
398 ty: "ImportType" = cls.__new__(cls)
399 ty._set_ptr(ptr)
400 ty._owner = owner
401 return ty
403 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]") -> None:
404 if self._owner is None:
405 ffi.wasm_importtype_delete(ptr)
407 @property
408 def module(self) -> str:
409 """
410 Returns the module this import type refers to
411 """
413 return ffi.to_str(ffi.wasm_importtype_module(self.ptr()).contents)
415 @property
416 def name(self) -> Optional[str]:
417 """
418 Returns the name in the module this import type refers to
420 Note that `None` may be returned for the module linking proposal where
421 the field name is optional.
422 """
423 ptr = ffi.wasm_importtype_name(self.ptr())
424 if ptr:
425 return ffi.to_str(ptr.contents)
426 return None
428 @property
429 def type(self) -> "AsExternType":
430 """
431 Returns the type that this import refers to
432 """
433 ptr = ffi.wasm_importtype_type(self.ptr())
434 return wrap_externtype(ptr, self._owner or self)
437class ExportType(Managed["ctypes._Pointer[ffi.wasm_exporttype_t]"]):
438 _ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]"
439 _owner: Optional[Any]
441 @classmethod
442 def _from_ptr(cls, ptr: 'ctypes._Pointer[ffi.wasm_exporttype_t]', owner: Optional[Any] = None) -> "ExportType":
443 if not isinstance(ptr, POINTER(ffi.wasm_exporttype_t)):
444 raise TypeError("wrong pointer type")
445 ty: "ExportType" = cls.__new__(cls)
446 ty._set_ptr(ptr)
447 ty._owner = owner
448 return ty
450 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]") -> None:
451 if self._owner is None:
452 ffi.wasm_exporttype_delete(ptr)
454 @property
455 def name(self) -> str:
456 """
457 Returns the name in the modulethis export type refers to
458 """
459 return ffi.to_str(ffi.wasm_exporttype_name(self.ptr()).contents)
461 @property
462 def type(self) -> "AsExternType":
463 """
464 Returns the type that this export refers to
465 """
466 ptr = ffi.wasm_exporttype_type(self.ptr())
467 return wrap_externtype(ptr, self._owner or self)
470class TagType(Managed["ctypes._Pointer[ffi.wasm_tagtype_t]"]):
471 """
472 Represents the type of a WebAssembly tag (used in exception handling and
473 stack-switching).
475 A `TagType` wraps a function type that describes the payload of exceptions
476 of this tag or types for stack switching.
477 """
478 _owner: Optional[Any]
480 def __init__(self, functype: FuncType) -> None:
481 if not isinstance(functype, FuncType):
482 raise TypeError("expected a FuncType")
483 ptr = ffi.wasm_tagtype_new(functype._consume())
484 if not ptr:
485 raise WasmtimeError("failed to allocate TagType")
486 self._set_ptr(ptr)
487 self._owner = None
489 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_tagtype_t]") -> None:
490 if self._owner is None:
491 ffi.wasm_tagtype_delete(ptr)
493 @classmethod
494 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_tagtype_t]", owner: Optional[Any] = None) -> "TagType":
495 if not isinstance(ptr, POINTER(ffi.wasm_tagtype_t)):
496 raise TypeError("wrong pointer type")
497 ty: "TagType" = cls.__new__(cls)
498 ty._set_ptr(ptr)
499 ty._owner = owner
500 return ty
502 def ptr(self) -> "ctypes._Pointer[ffi.wasm_tagtype_t]":
503 return super().ptr()
505 @property
506 def functype(self) -> FuncType:
507 """Returns the function type that describes the tag's payload."""
508 ptr = ffi.wasm_tagtype_functype(self.ptr())
509 return FuncType._from_ptr(ptr, self)
511 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
512 return ffi.wasm_tagtype_as_externtype_const(self.ptr())
515AsExternType = Union[FuncType, TableType, MemoryType, GlobalType, TagType]