Coverage for wasmtime/_ffi.py: 91%
137 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
1from ctypes import POINTER, Structure, Union, addressof, byref, cdll, string_at
2from ctypes import c_double, c_float, c_int32, c_int64, c_uint8
3from pathlib import Path
4import ctypes
5import sys
6import platform
7import typing
9if sys.maxsize <= 2**32:
10 raise RuntimeError("wasmtime only works on 64-bit platforms right now")
12sys_platform = sys.platform
14# For Python versions <=3.12. 3.13+ supports PEP 738 and uses sys.platform
15if hasattr(sys, 'getandroidapilevel'):
16 sys_platform = 'android'
18if sys_platform == 'linux' or sys_platform == 'android':
19 libname = '_libwasmtime.so'
20elif sys_platform == 'win32':
21 libname = '_wasmtime.dll'
22elif sys_platform == 'darwin':
23 libname = '_libwasmtime.dylib'
24else:
25 raise RuntimeError("unsupported platform `{}` for wasmtime".format(sys_platform))
28machine = platform.machine()
29if machine == 'AMD64':
30 machine = 'x86_64'
31if machine == 'arm64' or machine == 'ARM64':
32 machine = 'aarch64'
33if machine != 'x86_64' and machine != 'aarch64':
34 raise RuntimeError("unsupported architecture for wasmtime: {}".format(machine))
36filename = Path(__file__).parent / (sys_platform + '-' + machine) / libname
38dll = cdll.LoadLibrary(str(filename))
40WASM_I32 = c_uint8(0)
41WASM_I64 = c_uint8(1)
42WASM_F32 = c_uint8(2)
43WASM_F64 = c_uint8(3)
44WASM_ANYREF = c_uint8(128)
45WASM_FUNCREF = c_uint8(129)
46# WASM_V128 = c_uint8(4)
48WASMTIME_I32 = c_uint8(0)
49WASMTIME_I64 = c_uint8(1)
50WASMTIME_F32 = c_uint8(2)
51WASMTIME_F64 = c_uint8(3)
52WASMTIME_V128 = c_uint8(4)
53WASMTIME_FUNCREF = c_uint8(5)
54WASMTIME_EXTERNREF = c_uint8(6)
56WASM_CONST = c_uint8(0)
57WASM_VAR = c_uint8(1)
59WASMTIME_EXTERN_FUNC = c_uint8(0)
60WASMTIME_EXTERN_GLOBAL = c_uint8(1)
61WASMTIME_EXTERN_TABLE = c_uint8(2)
62WASMTIME_EXTERN_MEMORY = c_uint8(3)
63WASMTIME_EXTERN_SHAREDMEMORY = c_uint8(4)
64WASMTIME_EXTERN_TAG = c_uint8(5)
66WASMTIME_FUNCREF_NULL = (1 << 64) - 1
68WASMTIME_COMPONENT_ITEM_COMPONENT = c_uint8(0)
69WASMTIME_COMPONENT_ITEM_COMPONENT_INSTANCE = c_uint8(1)
70WASMTIME_COMPONENT_ITEM_MODULE = c_uint8(2)
71WASMTIME_COMPONENT_ITEM_COMPONENT_FUNC = c_uint8(3)
72WASMTIME_COMPONENT_ITEM_RESOURCE = c_uint8(4)
73WASMTIME_COMPONENT_ITEM_CORE_FUNC = c_uint8(5)
74WASMTIME_COMPONENT_ITEM_TYPE = c_uint8(6)
76WASMTIME_COMPONENT_VALTYPE_BOOL = c_uint8(0)
77WASMTIME_COMPONENT_VALTYPE_S8 = c_uint8(1)
78WASMTIME_COMPONENT_VALTYPE_S16 = c_uint8(2)
79WASMTIME_COMPONENT_VALTYPE_S32 = c_uint8(3)
80WASMTIME_COMPONENT_VALTYPE_S64 = c_uint8(4)
81WASMTIME_COMPONENT_VALTYPE_U8 = c_uint8(5)
82WASMTIME_COMPONENT_VALTYPE_U16 = c_uint8(6)
83WASMTIME_COMPONENT_VALTYPE_U32 = c_uint8(7)
84WASMTIME_COMPONENT_VALTYPE_U64 = c_uint8(8)
85WASMTIME_COMPONENT_VALTYPE_F32 = c_uint8(9)
86WASMTIME_COMPONENT_VALTYPE_F64 = c_uint8(10)
87WASMTIME_COMPONENT_VALTYPE_CHAR = c_uint8(11)
88WASMTIME_COMPONENT_VALTYPE_STRING = c_uint8(12)
89WASMTIME_COMPONENT_VALTYPE_LIST = c_uint8(13)
90WASMTIME_COMPONENT_VALTYPE_RECORD = c_uint8(14)
91WASMTIME_COMPONENT_VALTYPE_TUPLE = c_uint8(15)
92WASMTIME_COMPONENT_VALTYPE_VARIANT = c_uint8(16)
93WASMTIME_COMPONENT_VALTYPE_ENUM = c_uint8(17)
94WASMTIME_COMPONENT_VALTYPE_OPTION = c_uint8(18)
95WASMTIME_COMPONENT_VALTYPE_RESULT = c_uint8(19)
96WASMTIME_COMPONENT_VALTYPE_FLAGS = c_uint8(20)
97WASMTIME_COMPONENT_VALTYPE_OWN = c_uint8(21)
98WASMTIME_COMPONENT_VALTYPE_BORROW = c_uint8(22)
99WASMTIME_COMPONENT_VALTYPE_FUTURE = c_uint8(23)
100WASMTIME_COMPONENT_VALTYPE_STREAM = c_uint8(24)
101WASMTIME_COMPONENT_VALTYPE_ERROR_CONTEXT = c_uint8(25)
103WASMTIME_COMPONENT_BOOL = c_uint8(0)
104WASMTIME_COMPONENT_S8 = c_uint8(1)
105WASMTIME_COMPONENT_U8 = c_uint8(2)
106WASMTIME_COMPONENT_S16 = c_uint8(3)
107WASMTIME_COMPONENT_U16 = c_uint8(4)
108WASMTIME_COMPONENT_S32 = c_uint8(5)
109WASMTIME_COMPONENT_U32 = c_uint8(6)
110WASMTIME_COMPONENT_S64 = c_uint8(7)
111WASMTIME_COMPONENT_U64 = c_uint8(8)
112WASMTIME_COMPONENT_F32 = c_uint8(9)
113WASMTIME_COMPONENT_F64 = c_uint8(10)
114WASMTIME_COMPONENT_CHAR = c_uint8(11)
115WASMTIME_COMPONENT_STRING = c_uint8(12)
116WASMTIME_COMPONENT_LIST = c_uint8(13)
117WASMTIME_COMPONENT_RECORD = c_uint8(14)
118WASMTIME_COMPONENT_TUPLE = c_uint8(15)
119WASMTIME_COMPONENT_VARIANT = c_uint8(16)
120WASMTIME_COMPONENT_ENUM = c_uint8(17)
121WASMTIME_COMPONENT_OPTION = c_uint8(18)
122WASMTIME_COMPONENT_RESULT = c_uint8(19)
123WASMTIME_COMPONENT_FLAGS = c_uint8(20)
124WASMTIME_COMPONENT_RESOURCE = c_uint8(21)
126class wasm_ref_t(Structure):
127 pass
130class wasm_val_union(Union):
131 _fields_ = [
132 ("i32", c_int32),
133 ("i64", c_int64),
134 ("f32", c_float),
135 ("f64", c_double),
136 ("ref", POINTER(wasm_ref_t)),
137 ]
139 i32: int
140 i64: int
141 f32: float
142 f64: float
143 ref: "typing.Union[ctypes._Pointer[wasm_ref_t], None]"
146class wasm_val_t(Structure):
147 _fields_ = [("kind", c_uint8), ("of", wasm_val_union)]
149 kind: int
150 of: wasm_val_union
153from ._bindings import * # noqa
156def to_bytes(vec: wasm_byte_vec_t) -> bytearray:
157 ty = c_uint8 * vec.size
158 return bytearray(ty.from_address(addressof(vec.data.contents)))
160def to_str(vec: wasm_byte_vec_t) -> str:
161 return to_bytes(vec).decode("utf-8")
164def to_str_raw(ptr: "ctypes._Pointer", size: int) -> str:
165 return string_at(ptr, size).decode("utf-8")
168def str_to_capi(s: str) -> wasm_byte_vec_t:
169 if not isinstance(s, str):
170 raise TypeError("expected a string")
171 return bytes_to_capi(s.encode('utf8'))
173def bytes_to_capi(s: typing.Union[bytes, bytearray]) -> wasm_byte_vec_t:
174 if not isinstance(s, (bytes, bytearray)):
175 raise TypeError("expected bytes or bytearray")
176 vec = wasm_byte_vec_t()
177 wasm_byte_vec_new_uninitialized(byref(vec), len(s))
178 buf = (c_uint8 * len(s)).from_buffer_copy(s)
179 ctypes.memmove(vec.data, buf, len(s))
180 return vec
182def take_pointer(structure: ctypes._Pointer, field_name: str) -> ctypes._Pointer:
183 """
184 Moral equivalent of `mem::replace(&mut structure.field_name, NULL)`
186 Ctypes explicitly documents "Surprises" which includes, for example:
188 import ctypes
190 class A(ctypes.Structure):
191 _fields_ = [("x", ctypes.POINTER(ctypes.c_int))]
193 x_p = ctypes.pointer(ctypes.c_int(3))
194 a = A(x_p)
195 x = a.x
197 print(x.contents)
198 a.x = None
199 print(x.contents)
201 This program will segfault on the second access. It turns out that `x = a.x`
202 is still actually a pointer into the original structure, and `a.x`
203 overwrites that field so accessing `x` later accesses null memory. This
204 method is an attempt to work around this surprising behavior and actually
205 read the field from a structure and replace it with null.
207 I'll be honest I just sat through a 3 hour flight, a 5 hour layover, a 9
208 hour flight, 1 hour train ride, and I'm sitting in a hotel lobby for
209 another 5 hours. That's my state of mind writing this up, so please
210 draw conclusions about this method as appropriate.
211 """
212 field = getattr(structure, field_name)
213 assert(isinstance(field, ctypes._Pointer))
214 ret = ctypes.cast(ctypes.addressof(field.contents), ctypes.POINTER(field._type_))
215 setattr(structure, field_name, None)
216 return ret