Coverage for wasmtime/_types.py: 88%
309 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-20 16:25 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-20 16:25 +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 if not isinstance(limits, Limits):
289 raise TypeError("expected Limits")
290 if is_64:
291 maximum = 0x10000000000000000
292 else:
293 maximum = 0x100000000
294 if limits.min >= maximum:
295 raise WasmtimeError("minimum size too large")
296 if limits.max and limits.max >= maximum:
297 raise WasmtimeError("maximum size too large")
298 ptr = ffi.wasmtime_memorytype_new(limits.min,
299 limits.max is not None,
300 limits.max if limits.max else 0,
301 is_64,
302 shared)
303 if not ptr:
304 raise WasmtimeError("failed to allocate MemoryType")
305 self._set_ptr(ptr)
306 self._owner = None
308 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_memorytype_t]") -> None:
309 if self._owner is None:
310 ffi.wasm_memorytype_delete(ptr)
312 @classmethod
313 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_memorytype_t]", owner: Optional[Any]) -> "MemoryType":
314 if not isinstance(ptr, POINTER(ffi.wasm_memorytype_t)):
315 raise TypeError("wrong pointer type")
316 ty: "MemoryType" = cls.__new__(cls)
317 ty._set_ptr(ptr)
318 ty._owner = owner
319 return ty
321 @property
322 def limits(self) -> Limits:
323 """
324 Returns the limits on the size of this table
325 """
326 minimum = ffi.wasmtime_memorytype_minimum(self.ptr())
327 maximum = ffi.c_uint64(0)
328 has_max = ffi.wasmtime_memorytype_maximum(self.ptr(), byref(maximum))
329 return Limits(minimum, maximum.value if has_max else None)
331 @property
332 def is_64(self) -> bool:
333 """
334 Returns whether or not this is a 64-bit memory
335 """
336 return ffi.wasmtime_memorytype_is64(self.ptr())
338 @property
339 def is_shared(self) -> bool:
340 """
341 Returns whether or not this is a shared memory
342 """
343 return ffi.wasmtime_memorytype_isshared(self.ptr())
346 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]":
347 return ffi.wasm_memorytype_as_externtype_const(self.ptr())
350def wrap_externtype(ptr: "ctypes._Pointer[ffi.wasm_externtype_t]", owner: Optional[Any]) -> "AsExternType":
351 if not isinstance(ptr, POINTER(ffi.wasm_externtype_t)):
352 raise TypeError("wrong pointer type")
353 val = ffi.wasm_externtype_as_functype(ptr)
354 if val:
355 return FuncType._from_ptr(val, owner)
356 val = ffi.wasm_externtype_as_tabletype(ptr)
357 if val:
358 return TableType._from_ptr(val, owner)
359 val = ffi.wasm_externtype_as_globaltype(ptr)
360 if val:
361 return GlobalType._from_ptr(val, owner)
362 val = ffi.wasm_externtype_as_memorytype(ptr)
363 if val:
364 return MemoryType._from_ptr(val, owner)
365 raise WasmtimeError("unknown extern type")
368class ImportType(Managed["ctypes._Pointer[ffi.wasm_importtype_t]"]):
369 _owner: Optional[Any]
371 @classmethod
372 def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]", owner: Optional[Any]) -> "ImportType":
373 if not isinstance(ptr, POINTER(ffi.wasm_importtype_t)):
374 raise TypeError("wrong pointer type")
375 ty: "ImportType" = cls.__new__(cls)
376 ty._set_ptr(ptr)
377 ty._owner = owner
378 return ty
380 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]") -> None:
381 if self._owner is None:
382 ffi.wasm_importtype_delete(ptr)
384 @property
385 def module(self) -> str:
386 """
387 Returns the module this import type refers to
388 """
390 return ffi.to_str(ffi.wasm_importtype_module(self.ptr()).contents)
392 @property
393 def name(self) -> Optional[str]:
394 """
395 Returns the name in the module this import type refers to
397 Note that `None` may be returned for the module linking proposal where
398 the field name is optional.
399 """
400 ptr = ffi.wasm_importtype_name(self.ptr())
401 if ptr:
402 return ffi.to_str(ptr.contents)
403 return None
405 @property
406 def type(self) -> "AsExternType":
407 """
408 Returns the type that this import refers to
409 """
410 ptr = ffi.wasm_importtype_type(self.ptr())
411 return wrap_externtype(ptr, self._owner or self)
414class ExportType(Managed["ctypes._Pointer[ffi.wasm_exporttype_t]"]):
415 _ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]"
416 _owner: Optional[Any]
418 @classmethod
419 def _from_ptr(cls, ptr: 'ctypes._Pointer[ffi.wasm_exporttype_t]', owner: Optional[Any]) -> "ExportType":
420 if not isinstance(ptr, POINTER(ffi.wasm_exporttype_t)):
421 raise TypeError("wrong pointer type")
422 ty: "ExportType" = cls.__new__(cls)
423 ty._set_ptr(ptr)
424 ty._owner = owner
425 return ty
427 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]") -> None:
428 if self._owner is None:
429 ffi.wasm_exporttype_delete(ptr)
431 @property
432 def name(self) -> str:
433 """
434 Returns the name in the modulethis export type refers to
435 """
436 return ffi.to_str(ffi.wasm_exporttype_name(self.ptr()).contents)
438 @property
439 def type(self) -> "AsExternType":
440 """
441 Returns the type that this export refers to
442 """
443 ptr = ffi.wasm_exporttype_type(self.ptr())
444 return wrap_externtype(ptr, self._owner or self)
447AsExternType = Union[FuncType, TableType, MemoryType, GlobalType]