Coverage for wasmtime/_types.py: 88%

309 statements  

« 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 

4 

5from wasmtime import Managed, WasmtimeError 

6 

7from . import _ffi as ffi 

8 

9 

10class ValType(Managed["ctypes._Pointer[ffi.wasm_valtype_t]"]): 

11 _owner: Optional[Any] 

12 

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) 

18 

19 @classmethod 

20 def i32(cls) -> "ValType": 

21 ptr = ffi.wasm_valtype_new(ffi.WASM_I32) 

22 return ValType._from_ptr(ptr, None) 

23 

24 @classmethod 

25 def i64(cls) -> "ValType": 

26 ptr = ffi.wasm_valtype_new(ffi.WASM_I64) 

27 return ValType._from_ptr(ptr, None) 

28 

29 @classmethod 

30 def f32(cls) -> "ValType": 

31 ptr = ffi.wasm_valtype_new(ffi.WASM_F32) 

32 return ValType._from_ptr(ptr, None) 

33 

34 @classmethod 

35 def f64(cls) -> "ValType": 

36 ptr = ffi.wasm_valtype_new(ffi.WASM_F64) 

37 return ValType._from_ptr(ptr, None) 

38 

39 @classmethod 

40 def externref(cls) -> "ValType": 

41 ptr = ffi.wasm_valtype_new(ffi.WASM_ANYREF) 

42 return ValType._from_ptr(ptr, None) 

43 

44 @classmethod 

45 def funcref(cls) -> "ValType": 

46 ptr = ffi.wasm_valtype_new(ffi.WASM_FUNCREF) 

47 return ValType._from_ptr(ptr, None) 

48 

49 def __init__(self) -> None: 

50 raise WasmtimeError("cannot construct directly") 

51 

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 

60 

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 

67 

68 def __ne__(self, other: object) -> bool: 

69 return not self.__eq__(other) 

70 

71 def __repr__(self) -> str: 

72 return str(self) 

73 

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 

89 

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 

96 

97 

98def take_owned_valtype(ty: ValType) -> "ctypes._Pointer[ffi.wasm_valtype_t]": 

99 if not isinstance(ty, ValType): 

100 raise TypeError("expected valtype") 

101 

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())) 

107 

108 

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") 

117 

118 params_ffi = ffi.wasm_valtype_vec_t() 

119 ffi.wasm_valtype_vec_new_uninitialized(byref(params_ffi), len(params)) 

120 

121 results_ffi = ffi.wasm_valtype_vec_t() 

122 for i, param in enumerate(params): 

123 params_ffi.data[i] = take_owned_valtype(param) 

124 

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 

134 

135 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_functype_t]") -> None: 

136 if self._owner is None: 

137 ffi.wasm_functype_delete(ptr) 

138 

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 

147 

148 @property 

149 def params(self) -> List["ValType"]: 

150 """ 

151 Returns the list of parameter types for this function type 

152 """ 

153 

154 ptr = ffi.wasm_functype_params(self.ptr()) 

155 return ValType._from_list(ptr, self) 

156 

157 @property 

158 def results(self) -> List["ValType"]: 

159 """ 

160 Returns the list of result types for this function type 

161 """ 

162 

163 ptr = ffi.wasm_functype_results(self.ptr()) 

164 return ValType._from_list(ptr, self) 

165 

166 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]": 

167 return ffi.wasm_functype_as_externtype_const(self.ptr()) 

168 

169 

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 

182 

183 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_globaltype_t]") -> None: 

184 if self._owner is None: 

185 ffi.wasm_globaltype_delete(ptr) 

186 

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 

195 

196 @property 

197 def content(self) -> ValType: 

198 """ 

199 Returns the type this global contains 

200 """ 

201 

202 ptr = ffi.wasm_globaltype_content(self.ptr()) 

203 return ValType._from_ptr(ptr, self) 

204 

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 

212 

213 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]": 

214 return ffi.wasm_globaltype_as_externtype_const(self.ptr()) 

215 

216 

217class Limits: 

218 def __init__(self, min: int, max: Optional[int]): 

219 self.min = min 

220 self.max = max 

221 

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) 

227 

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 

232 

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) 

240 

241 

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 

252 

253 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_tabletype_t]") -> None: 

254 if self._owner is None: 

255 ffi.wasm_tabletype_delete(ptr) 

256 

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 

265 

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) 

273 

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) 

281 

282 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]": 

283 return ffi.wasm_tabletype_as_externtype_const(self.ptr()) 

284 

285 

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 

307 

308 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_memorytype_t]") -> None: 

309 if self._owner is None: 

310 ffi.wasm_memorytype_delete(ptr) 

311 

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 

320 

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) 

330 

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()) 

337 

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()) 

344 

345 

346 def _as_extern(self) -> "ctypes._Pointer[ffi.wasm_externtype_t]": 

347 return ffi.wasm_memorytype_as_externtype_const(self.ptr()) 

348 

349 

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") 

366 

367 

368class ImportType(Managed["ctypes._Pointer[ffi.wasm_importtype_t]"]): 

369 _owner: Optional[Any] 

370 

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 

379 

380 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]") -> None: 

381 if self._owner is None: 

382 ffi.wasm_importtype_delete(ptr) 

383 

384 @property 

385 def module(self) -> str: 

386 """ 

387 Returns the module this import type refers to 

388 """ 

389 

390 return ffi.to_str(ffi.wasm_importtype_module(self.ptr()).contents) 

391 

392 @property 

393 def name(self) -> Optional[str]: 

394 """ 

395 Returns the name in the module this import type refers to 

396 

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 

404 

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) 

412 

413 

414class ExportType(Managed["ctypes._Pointer[ffi.wasm_exporttype_t]"]): 

415 _ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]" 

416 _owner: Optional[Any] 

417 

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 

426 

427 def _delete(self, ptr: "ctypes._Pointer[ffi.wasm_exporttype_t]") -> None: 

428 if self._owner is None: 

429 ffi.wasm_exporttype_delete(ptr) 

430 

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) 

437 

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) 

445 

446 

447AsExternType = Union[FuncType, TableType, MemoryType, GlobalType]