From 9e2fbe7f00e5e014c6c4c12d6c130a17a999f7d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Nov 2025 09:24:33 -0700 Subject: [PATCH 1/5] Fix defining fields of forward-declared structures This fixes a typo in the bindings generation script which set the `_fields` field rather than `_fields_` --- ci/cbindgen.py | 2 +- wasmtime/_bindings.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/cbindgen.py b/ci/cbindgen.py index 27f68e0d..4c2188ed 100644 --- a/ci/cbindgen.py +++ b/ci/cbindgen.py @@ -53,7 +53,7 @@ def visit_Struct(self, node): decl.name = '_anon_' + str(anon_decl) if node.name in self.forward_declared: - self.ret += "{}._fields = [ # type: ignore\n".format(node.name) + self.ret += "{}._fields_ = [\n".format(node.name) else: self.ret += "class {}(Structure):\n".format(node.name) self.ret += " _fields_ = [\n" diff --git a/wasmtime/_bindings.py b/wasmtime/_bindings.py index a9218a00..64b8d6c4 100644 --- a/wasmtime/_bindings.py +++ b/wasmtime/_bindings.py @@ -3942,14 +3942,14 @@ class wasmtime_component_valunion(Union): wasmtime_component_valunion_t = wasmtime_component_valunion -wasmtime_component_val._fields = [ # type: ignore +wasmtime_component_val._fields_ = [ ("kind", wasmtime_component_valkind_t), ("of", wasmtime_component_valunion_t), ] wasmtime_component_val_t = wasmtime_component_val -wasmtime_component_valrecord_entry._fields = [ # type: ignore +wasmtime_component_valrecord_entry._fields_ = [ ("name", wasm_name_t), ("val", wasmtime_component_val_t), ] From d368c86d29b94a1c9c048a2c022b63a77aa5c472 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Oct 2025 10:41:03 -0700 Subject: [PATCH 2/5] Bind the C API for components --- tests/component/test_component.py | 79 ++ tests/component/test_func.py | 438 +++++++++ tests/component/test_instance.py | 70 ++ tests/component/test_linker.py | 144 +++ tests/component/test_types.py | 258 ++++++ tests/component/test_value.py | 174 ++++ tests/test_linker.py | 2 - wasmtime/__init__.py | 3 +- wasmtime/_bindings.py | 658 ++++++++++++- wasmtime/_error.py | 3 +- wasmtime/_exportable.py | 4 +- wasmtime/_extern.py | 14 +- wasmtime/_ffi.py | 115 ++- wasmtime/_instance.py | 4 - wasmtime/_linker.py | 2 - wasmtime/_module.py | 35 +- wasmtime/_store.py | 17 +- wasmtime/_types.py | 4 +- wasmtime/_wat2wasm.py | 14 + wasmtime/component/__init__.py | 55 ++ wasmtime/component/_component.py | 155 ++++ wasmtime/component/_enter.py | 43 + wasmtime/component/_func.py | 74 ++ wasmtime/component/_instance.py | 65 ++ wasmtime/component/_linker.py | 246 +++++ wasmtime/component/_resource_type.py | 34 + wasmtime/component/_resources.py | 120 +++ wasmtime/component/_types.py | 1268 ++++++++++++++++++++++++++ 28 files changed, 3999 insertions(+), 99 deletions(-) create mode 100644 tests/component/test_component.py create mode 100644 tests/component/test_func.py create mode 100644 tests/component/test_instance.py create mode 100644 tests/component/test_linker.py create mode 100644 tests/component/test_types.py create mode 100644 tests/component/test_value.py create mode 100644 wasmtime/component/__init__.py create mode 100644 wasmtime/component/_component.py create mode 100644 wasmtime/component/_enter.py create mode 100644 wasmtime/component/_func.py create mode 100644 wasmtime/component/_instance.py create mode 100644 wasmtime/component/_linker.py create mode 100644 wasmtime/component/_resource_type.py create mode 100644 wasmtime/component/_resources.py create mode 100644 wasmtime/component/_types.py diff --git a/tests/component/test_component.py b/tests/component/test_component.py new file mode 100644 index 00000000..7381f18c --- /dev/null +++ b/tests/component/test_component.py @@ -0,0 +1,79 @@ +import unittest +import tempfile + +from wasmtime import * +from wasmtime.component import Component, ExportIndex + +class TestComponent(unittest.TestCase): + def test_smoke(self): + Component(Engine(), '(component)') + Component(Engine(), bytes(b'\0asm\x0d\0\x01\0')) + Component(Engine(), bytearray(b'\0asm\x0d\0\x01\0')) + + with self.assertRaises(WasmtimeError): + Component(Engine(), '(component2)') + with self.assertRaises(WasmtimeError): + Component(Engine(), bytes(b'\0asm\x01\0\0\0')) + + def test_invalid(self): + with self.assertRaises(TypeError): + Component(1, b'') # type: ignore + with self.assertRaises(TypeError): + Component(Engine(), 2) # type: ignore + with self.assertRaises(WasmtimeError): + Component(Engine(), b'') + with self.assertRaises(WasmtimeError): + Component(Engine(), b'\x00') + + def test_serialize(self): + engine = Engine() + component = Component(engine, '(component)') + encoded = component.serialize() + component = Component.deserialize(engine, encoded) + with tempfile.TemporaryDirectory() as d: + path = d + '/component.bin' + with open(path, 'wb') as f: + f.write(encoded) + component = Component.deserialize_file(engine, path) + + # Run the destructor for `Component` which has an mmap to the file + # which prevents deletion on Windows. + del component + + def test_exports(self): + engine = Engine() + + c = Component(engine, '(component)') + self.assertIsNone(c.get_export_index('foo')) + self.assertIsNone(c.get_export_index('foo', instance = None)) + + c = Component(engine, """ + (component + (core module (export "foo")) + ) + """) + foo = c.get_export_index('foo') + self.assertIsNotNone(foo) + self.assertIsNone(c.get_export_index('foo', instance = foo)) + self.assertIsInstance(foo, ExportIndex) + + c = Component(engine, """ + (component + (core module $a) + (instance (export "x") + (export "m" (core module $a)) + ) + ) + """) + self.assertIsNotNone(c.get_export_index('x')) + self.assertIsNotNone(c.get_export_index('m', instance = c.get_export_index('x'))) + + c2 = Component(engine, """ + (component + (core module $a) + (instance (export "x") + (export "m" (core module $a)) + ) + ) + """) + self.assertIsNone(c2.get_export_index('m', instance = c.get_export_index('x'))) diff --git a/tests/component/test_func.py b/tests/component/test_func.py new file mode 100644 index 00000000..51cb23fa --- /dev/null +++ b/tests/component/test_func.py @@ -0,0 +1,438 @@ +import unittest +from dataclasses import dataclass +from wasmtime import Store, WasmtimeError, Engine +from wasmtime.component import * +from typing import Any, List + +def list_component(ty_wit: str): + return f""" + (component + (import "x" (func $x (param "x" {ty_wit}) (result {ty_wit}))) + (core module $libc + (memory (export "mem") 1) + (global $base (mut i32) (i32.const 100)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + (local $ret i32) + local.get 0 + if unreachable end + local.get 1 + if unreachable end + + (local.set $ret (global.get $base)) + (global.set $base + (i32.add + (global.get $base) + (local.get 2))) + local.get $ret) + ) + (core instance $libc (instantiate $libc)) + (core module $a + (import "" "x" (func (param i32 i32 i32))) + (func (export "x") (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.const 0 + call 0 + i32.const 0) + ) + (core func $x (canon lower (func $x) + (memory $libc "mem") (realloc (func $libc "realloc")))) + (core instance $a (instantiate $a + (with "" (instance + (export "x" (func $x)) + )) + )) + (func (export "x") (param "x" {ty_wit}) (result {ty_wit}) + (canon lift (core func $a "x") (memory $libc "mem") + (realloc (func $libc "realloc")))) + ) + """ + +def retptr_component(ty_wit: str, ty_wasm: str): + return f""" + (component + (type $t' {ty_wit}) + (import "t" (type $t (eq $t'))) + (import "x" (func $x (param "x" $t) (result $t))) + (core module $libc (memory (export "mem") 1)) + (core instance $libc (instantiate $libc)) + (core module $a + (import "" "x" (func (param {ty_wasm} i32))) + (func (export "x") (param {ty_wasm}) (result i32) + local.get 0 + local.get 1 + i32.const 0 + call 0 + i32.const 0) + ) + (core func $x (canon lower (func $x) (memory $libc "mem"))) + (core instance $a (instantiate $a + (with "" (instance + (export "x" (func $x)) + )) + )) + (func (export "x") (param "x" $t) (result $t) + (canon lift (core func $a "x") (memory $libc "mem"))) + ) + """ + +class TestFunc(unittest.TestCase): + def roundtrip(self, wat: str, values: List[Any], bad = TypeError) -> None: + engine = Engine() + store = Store(engine) + component = Component(engine, wat) + value_being_tested = None + + def roundtrip(_store, val): + self.assertEqual(value_being_tested, val) + return val + + linker = Linker(engine) + with linker.root() as l: + l.add_func('x', roundtrip) + instance = linker.instantiate(store, component) + f = instance.get_func(store, 'x') + assert(f is not None) + for val in values: + value_being_tested = val + ret = f(store, val) + self.assertEqual(ret, val) + f.post_return(store) + + class Bad: + pass + with self.assertRaises(bad): + f(store, Bad()) + + def roundtrip_simple(self, ty_wit: str, ty_wasm: str, values: List[Any]) -> None: + wat = f""" + (component + (type $t' {ty_wit}) + (import "t" (type $t (eq $t'))) + (import "x" (func $x (param "x" $t) (result $t))) + (core module $a + (import "" "x" (func (param {ty_wasm}) (result {ty_wasm}))) + (func (export "x") (param {ty_wasm}) (result {ty_wasm}) + local.get 0 + call 0) + ) + (core func $x (canon lower (func $x))) + (core instance $a (instantiate $a + (with "" (instance + (export "x" (func $x)) + )) + )) + (func (export "x") (param "x" $t) (result $t) + (canon lift (core func $a "x"))) + ) + """ + self.roundtrip(wat, values) + + def test_init(self): + with self.assertRaises(WasmtimeError): + Func() + + def test_type_reflection(self): + engine = Engine() + store = Store(engine) + component = Component(engine, """ + (component + (core module $a + (func (export "a")) + (func (export "b") (param i32) (result i32) unreachable) + ) + (core instance $a (instantiate $a)) + (func (export "a") (canon lift (core func $a "a"))) + (func (export "b") (param "x" u32) (result u32) + (canon lift (core func $a "b"))) + ) + """) + instance = Linker(engine).instantiate(store, component) + ai = instance.get_export_index(store, 'a') + bi = instance.get_export_index(store, 'b') + assert(ai is not None) + assert(bi is not None) + a = instance.get_func(store, ai) + b = instance.get_func(store, bi) + assert(a is not None) + assert(b is not None) + self.assertEqual(a.type(store).params, []) + self.assertIsNone(a.type(store).result) + self.assertEqual(b.type(store).params, [('x', U32())]) + self.assertEqual(b.type(store).result, U32()) + + def test_call(self): + engine = Engine() + store = Store(engine) + component = Component(engine, """ + (component + (core module $a + (func (export "a")) + (func (export "b") (param i32) + local.get 0 + i32.const 100 + i32.ne + if unreachable end) + (func (export "c") (result i32) (i32.const 101)) + ) + (core instance $a (instantiate $a)) + (func (export "a") (canon lift (core func $a "a"))) + (func (export "b") (param "x" u32) (canon lift (core func $a "b"))) + (func (export "c") (result u32) (canon lift (core func $a "c"))) + ) + """) + instance = Linker(engine).instantiate(store, component) + a = instance.get_func(store, 'a') + assert(a is not None) + ret = a(store) + self.assertEqual(ret, None) + a.post_return(store) + + b = instance.get_func(store, 'b') + assert(b is not None) + ret = b(store, 100) + self.assertEqual(ret, None) + b.post_return(store) + + c = instance.get_func(store, 'c') + assert(c is not None) + ret = c(store) + self.assertEqual(ret, 101) + c.post_return(store) + + with self.assertRaises(TypeError): + b(store) + + def test_roundtrip_empty(self): + engine = Engine() + store = Store(engine) + component = Component(engine, f""" + (component + (import "x" (func $x)) + (core module $a + (import "" "x" (func)) + (func (export "x") call 0) + ) + (core func $x (canon lower (func $x))) + (core instance $a (instantiate $a + (with "" (instance + (export "x" (func $x)) + )) + )) + (func (export "x") (canon lift (core func $a "x"))) + ) + """) + + linker = Linker(engine) + with linker.root() as l: + l.add_func('x', lambda _store: None) + instance = linker.instantiate(store, component) + f = instance.get_func(store, 'x') + assert(f is not None) + + self.assertIsNone(f(store)) + f.post_return(store) + + def test_roundtrip_primitive(self): + self.roundtrip_simple('bool', 'i32', [True, False]) + self.roundtrip_simple('u8', 'i32', [0, 1, 42, 255]) + self.roundtrip_simple('u16', 'i32', [0, 1, 42, 65535]) + self.roundtrip_simple('u32', 'i32', [0, 1, 42, 4294967295]) + self.roundtrip_simple('u64', 'i64', [0, 1, 42, 18446744073709551615]) + self.roundtrip_simple('s8', 'i32', [0, 1, -1, 42, -42, 127, -128]) + self.roundtrip_simple('s16', 'i32', [0, 1, -1, 42, -42, 32767, -32768]) + self.roundtrip_simple('s32', 'i32', [0, 1, -1, 42, -42, 2147483647, -2147483648]) + self.roundtrip_simple('s64', 'i64', [0, 1, -1, 42, -42, 9223372036854775807, -9223372036854775808]) + self.roundtrip_simple('f32', 'f32', [0.0, 1.0, -1.0]) + self.roundtrip_simple('f64', 'f64', [0.0, 1.0, -1.0]) + self.roundtrip_simple('char', 'i32', ['a', 'b']) + + def test_resources(self): + engine = Engine() + store = Store(engine) + component = Component(engine, f""" + (component + (import "t" (type $t (sub resource))) + (import "mk" (func $mk (result (own $t)))) + (import "borrow" (func $borrow (param "t" (borrow $t)))) + (import "own" (func $own (param "t" (own $t)))) + (core module $a + (import "" "mk" (func $mk (result i32))) + (import "" "borrow" (func $borrow (param i32))) + (import "" "own" (func $own (param i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "mk") (result i32) call $mk) + (func (export "borrow") (param i32) + (call $borrow (local.get 0)) + (call $drop (local.get 0))) + (func (export "own") (param i32) local.get 0 call $own) + ) + (core func $mk (canon lower (func $mk))) + (core func $borrow (canon lower (func $borrow))) + (core func $own (canon lower (func $own))) + (core func $drop (canon resource.drop $t)) + (core instance $a (instantiate $a + (with "" (instance + (export "mk" (func $mk)) + (export "borrow" (func $borrow)) + (export "own" (func $own)) + (export "drop" (func $drop)) + )) + )) + (func (export "mk") (result (own $t)) + (canon lift (core func $a "mk"))) + (func (export "borrow") (param "x" (borrow $t)) + (canon lift (core func $a "borrow"))) + (func (export "own") (param "x" (own $t)) + (canon lift (core func $a "own"))) + ) + """) + + ty = ResourceType.host(2) + + def mk(_store): + return ResourceHost.own(1, 2) + + def borrow(_store, b): + self.assertFalse(b.owned) + handle = b.to_host(store) + self.assertEqual(handle.type, 2) + + def own(_store, b): + self.assertTrue(b.owned) + + linker = Linker(engine) + with linker.root() as l: + l.add_resource('t', ty, lambda _store, _rep: None) + l.add_func('mk', mk) + l.add_func('borrow', borrow) + l.add_func('own', own) + instance = linker.instantiate(store, component) + f_mk = instance.get_func(store, 'mk') + f_borrow = instance.get_func(store, 'borrow') + f_own = instance.get_func(store, 'own') + assert(f_mk is not None) + assert(f_borrow is not None) + assert(f_own is not None) + + r1 = f_mk(store) + self.assertIsInstance(r1, ResourceAny) + f_mk.post_return(store) + f_borrow(store, r1) + f_borrow.post_return(store) + f_borrow(store, ResourceHost.own(1, 2)) + f_borrow.post_return(store) + f_own(store, r1) + f_own.post_return(store) + f_own(store, ResourceHost.own(1, 2)) + f_own.post_return(store) + + with self.assertRaises(TypeError): + f_borrow(store, 1) + + with self.assertRaises(TypeError): + f_own(store, 1) + + + def test_enum(self): + self.roundtrip_simple('(enum "a" "b" "c")', 'i32', ['a', 'b', 'c']) + with self.assertRaises(WasmtimeError): + self.roundtrip_simple('(enum "a" "b" "c")', 'i32', ['d']) + + + def test_flags(self): + vals = [{'a'}, {'b'}, {'c'}, {'a', 'b'}, {'a', 'c'}, {'b', 'c'}] + self.roundtrip_simple('(flags "a" "b" "c")', 'i32', vals) + with self.assertRaises(WasmtimeError): + self.roundtrip_simple('(flags "a" "b" "c")', 'i32', [{'d'}]) + + + def test_record(self): + ty_wit = '(record (field "a" u32) (field "b" bool))' + ty_wasm = 'i32 i32' + wat = retptr_component(ty_wit, ty_wasm) + @dataclass + class Record: + a: int + b: bool + values = [ + Record(0, False), + Record(1, True), + Record(42, False), + Record(65535, True) + ] + self.roundtrip(wat, values, bad = AttributeError) + + @dataclass + class RecordBad: + a: int + with self.assertRaises(AttributeError): + self.roundtrip(wat, [RecordBad(0)]) + + def test_tuple(self): + ty_wit = '(tuple u32 bool)' + ty_wasm = 'i32 i32' + wat = retptr_component(ty_wit, ty_wasm) + values = [(0, False), (1, True), (42, False), (65535, True)] + self.roundtrip(wat, values) + + with self.assertRaises(TypeError): + self.roundtrip(wat, [(0,)]) + + with self.assertRaises(TypeError): + self.roundtrip(wat, [(0, 'x')]) + + def test_string(self): + wat = list_component('string') + self.roundtrip(wat, ['', 'a', 'hello, world!']) + + def test_list(self): + wat = list_component('(list u8)') + self.roundtrip(wat, [b'', b'a', b'hello, world!']) + wat = list_component('(list u32)') + self.roundtrip(wat, [[], [1], [1, 2, 3, 4, 5]]) + with self.assertRaises(TypeError): + self.roundtrip(wat, [[1, 2, 3, 'x']]) + + def test_variant(self): + self.roundtrip_simple('(variant (case "a") (case "b"))', + 'i32', + [Variant('a'), Variant('b')]) + + with self.assertRaises(ValueError): + self.roundtrip_simple('(variant (case "a") (case "b"))', + 'i32', + [Variant('c')]) + + wat = retptr_component('(variant (case "a" u32) (case "b" u64))', 'i32 i64') + self.roundtrip(wat, [Variant('a', 1), Variant('b', 2)]) + + wat = retptr_component('(variant (case "a" u32) (case "b" f32))', 'i32 i32') + self.roundtrip(wat, [1, 2.], bad=ValueError) + wat = retptr_component('(variant (case "a") (case "b" f32))', 'i32 f32') + self.roundtrip(wat, [None, 2.], bad=ValueError) + + + def test_option(self): + wat = retptr_component('(option u32)', 'i32 i32') + self.roundtrip(wat, [None, 3, 0], bad=ValueError) + + + def test_result(self): + wat = retptr_component('(result u32 (error f32))', 'i32 i32') + self.roundtrip(wat, [3, 1.], bad=ValueError) + + wat = retptr_component('(result u32)', 'i32 i32') + self.roundtrip(wat, [3, None], bad=ValueError) + + wat = retptr_component('(result (error f32))', 'i32 f32') + self.roundtrip(wat, [3., None], bad=ValueError) + + self.roundtrip_simple('(result)', 'i32', [Variant('ok'), Variant('err')]) + + + # TODO: roundtrip future + # TODO: roundtrip stream + # TODO: roundtrip error-context + # TODO: typechecking in variants-of-python-types (e.g. `add_classes`) diff --git a/tests/component/test_instance.py b/tests/component/test_instance.py new file mode 100644 index 00000000..e5f5e0cd --- /dev/null +++ b/tests/component/test_instance.py @@ -0,0 +1,70 @@ +import unittest + +from wasmtime import Engine, WasmtimeError, Store +from wasmtime.component import Linker, Component, Instance + + +class TestInstance(unittest.TestCase): + def test_init(self): + with self.assertRaises(WasmtimeError): + Instance() + + def test_smoke(self): + engine = Engine() + linker = Linker(engine) + component = Component(engine, '(component)') + store = Store(engine) + + instance = linker.instantiate(store, component) + self.assertIsNotNone(instance) + self.assertIsNone(instance.get_export_index(store, 'hello')) + + component = Component(engine, """ + (component + (core module (export "foo")) + ) + """) + instance = linker.instantiate(store, component) + self.assertIsNotNone(instance.get_export_index(store, 'foo')) + + component = Component(engine, """ + (component + (core module $a) + (instance (export "x") + (export "m" (core module $a)) + ) + ) + """) + instance = linker.instantiate(store, component) + e1 = instance.get_export_index(store, 'x') + e2 = component.get_export_index('x') + assert(e1 is not None) + assert(e2 is not None) + self.assertIsNotNone(instance.get_export_index(store, 'm', instance = e1)) + self.assertIsNotNone(instance.get_export_index(store, 'm', instance = e2)) + + self.assertIsNone(instance.get_func(store, e1)) + self.assertIsNone(instance.get_func(store, e2)) + + def test_get_func(self): + engine = Engine() + linker = Linker(engine) + store = Store(engine) + + component = Component(engine, """ + (component + (core module $a + (func (export "foo")) + ) + (core instance $a (instantiate $a)) + (func (export "a") (canon lift (core func $a "foo"))) + ) + """) + instance = linker.instantiate(store, component) + index = instance.get_export_index(store, 'a') + assert(index is not None) + func = instance.get_func(store, index) + self.assertIsNotNone(func) + + self.assertIsNotNone(instance.get_func(store, 'a')) + self.assertIsNone(instance.get_func(store, 'b')) diff --git a/tests/component/test_linker.py b/tests/component/test_linker.py new file mode 100644 index 00000000..2e23c98f --- /dev/null +++ b/tests/component/test_linker.py @@ -0,0 +1,144 @@ +import unittest + +from wasmtime import Engine, WasmtimeError, Module, Store +from wasmtime.component import Linker, Component, LinkerInstance + + +class TestLinker(unittest.TestCase): + def test_smoke(self): + engine = Engine() + linker = Linker(engine) + linker.allow_shadowing = True + linker.allow_shadowing = False + + def test_init_linker_instance(self): + with self.assertRaises(WasmtimeError): + LinkerInstance() + + def test_root(self): + engine = Engine() + linker = Linker(engine) + with linker.root() as root: + pass + with linker.root() as root: + with self.assertRaises(WasmtimeError): + linker.root() + with linker.root() as root: + pass + + def test_add_instance(self): + engine = Engine() + linker = Linker(engine) + with linker.root() as root: + with root.add_instance('x'): + pass + with root.add_instance('y'): + pass + with self.assertRaises(WasmtimeError): + root.add_instance('x') + with self.assertRaises(WasmtimeError): + root.add_instance('y') + with root.add_instance('z'): + pass + + with linker.root() as root: + with root.add_instance('again'): + pass + + with linker.root() as root: + with root.add_instance('another') as x: + # Reuse `root` while `x` is alive + with self.assertRaises(WasmtimeError): + root.add_instance('y') + + # Reuse `x` while `x` is alive + with x.add_instance('x'): + with self.assertRaises(WasmtimeError): + x.add_instance('y') + + def test_add_module(self): + engine = Engine() + linker = Linker(engine) + with linker.root() as root: + root.add_module('x', Module(engine, b'(module)')) + root.add_module('y', Module(engine, b'(module)')) + + with self.assertRaises(WasmtimeError): + root.add_module('x', Module(engine, b'(module)')) + + with root.add_instance('z'): + with self.assertRaises(WasmtimeError): + root.add_module('not-used-yet', Module(engine, b'(module)')) + + def test_add_wasip2(self): + engine = Engine() + linker = Linker(engine) + linker.add_wasip2() + + with linker.root(): + with self.assertRaises(WasmtimeError): + linker.add_wasip2() + + linker.close() + + with Linker(engine) as l2: + l2.add_wasip2() + with self.assertRaises(WasmtimeError): + l2.add_wasip2() + l2.allow_shadowing = True + l2.add_wasip2() + + def test_host_exception(self): + engine = Engine() + store = Store(engine) + component = Component(engine, """ + (component + (import "x" (func $x)) + (core module $a + (import "" "x" (func)) + (func (export "x") call 0) + ) + (core func $x (canon lower (func $x))) + (core instance $a (instantiate $a + (with "" (instance + (export "x" (func $x)) + )) + )) + (func (export "x") (canon lift (core func $a "x"))) + ) + """) + def host_func(_store): + raise RuntimeError("oh no") + linker = Linker(engine) + with linker.root() as l: + l.add_func('x', host_func) + instance = linker.instantiate(store, component) + func = instance.get_func(store, 'x') + assert(func is not None) + with self.assertRaises(RuntimeError) as cm: + func(store) + self.assertEqual(str(cm.exception), "oh no") + + def test_fail_instantiate(self): + engine = Engine() + store = Store(engine) + component = Component(engine, """ + (component + (import "x" (func $x)) + ) + """) + linker = Linker(engine) + with self.assertRaises(WasmtimeError): + linker.instantiate(store, component) + + def test_shadow_func(self): + engine = Engine() + store = Store(engine) + linker = Linker(engine) + with linker.root() as l: + l.add_func('x', lambda: None) + with self.assertRaises(WasmtimeError): + l.add_func('x', lambda: None) + linker.allow_shadowing = True + with linker.root() as l: + l.add_func('x', lambda: None) diff --git a/tests/component/test_types.py b/tests/component/test_types.py new file mode 100644 index 00000000..5202db67 --- /dev/null +++ b/tests/component/test_types.py @@ -0,0 +1,258 @@ +import unittest + +from wasmtime import Engine, FuncType as CoreFuncType, GlobalType, WasmtimeError +from wasmtime.component import * + +def simplety(name): + engine = Engine() + c = Component(engine, f""" + (component + (import "a" (func (result {name}))) + ) + """) + fty = c.type.imports(engine)['a'] + assert(isinstance(fty, FuncType)) + return fty.result + +def namedty(contents): + engine = Engine() + c = Component(engine, f""" + (component + (type $t' {contents}) + (import "t" (type $t (eq $t'))) + (import "a" (func (result $t))) + ) + """) + fty = c.type.imports(engine)['a'] + assert(isinstance(fty, FuncType)) + return fty.result + +class TestTypes(unittest.TestCase): + def test_component(self): + engine = Engine() + ty = Component(engine, '(component)').type + self.assertEqual(len(ty.imports(engine)), 0) + self.assertEqual(len(ty.exports(engine)), 0) + + ty = Component(engine, """ + (component + (import "a" (core module $a)) + (export "g" (core module $a)) + ) + """).type + self.assertEqual(len(ty.imports(engine)), 1) + self.assertIsInstance(ty.imports(engine)['a'], ModuleType) + self.assertEqual(len(ty.exports(engine)), 1) + self.assertIsInstance(ty.exports(engine)['g'], ModuleType) + + with self.assertRaises(WasmtimeError): + ComponentType() + + def test_module(self): + engine = Engine() + c = Component(engine, """ + (component + (import "a" (core module $a + (import "b" "c" (func)) + (export "d" (global i32)) + )) + ) + """) + mty = c.type.imports(engine)['a'] + assert(isinstance(mty, ModuleType)) + imports = mty.imports(engine) + self.assertEqual(len(imports), 1) + exports = mty.exports(engine) + self.assertEqual(len(exports), 1) + + self.assertEqual(imports[0].module, 'b') + self.assertEqual(imports[0].name, 'c') + self.assertIsInstance(imports[0].type, CoreFuncType) + + self.assertEqual(exports[0].name, 'd') + self.assertIsInstance(exports[0].type, GlobalType) + + with self.assertRaises(WasmtimeError): + ModuleType() + + def test_resource(self): + engine = Engine() + c = Component(engine, """ + (component + (import "a" (type $t (sub resource))) + (export "a" (type $t)) + (type $t2 (resource (rep i32))) + (export "b" (type $t2)) + ) + """) + a1 = c.type.imports(engine)['a'] + a2 = c.type.exports(engine)['a'] + b = c.type.exports(engine)['b'] + assert(isinstance(a1, ResourceType)) + assert(isinstance(a2, ResourceType)) + assert(isinstance(b, ResourceType)) + self.assertEqual(a1, a2) + self.assertNotEqual(a1, b) + self.assertNotEqual(a2, b) + self.assertNotEqual(a2, 'hello') + + with self.assertRaises(WasmtimeError): + ResourceType() + + def test_instance(self): + engine = Engine() + cty = Component(engine, """ + (component + (import "a" (instance + (export "a" (func)) + (export "b" (core module)) + )) + (import "b" (instance)) + ) + """).type + a = cty.imports(engine)['a'] + b = cty.imports(engine)['b'] + assert(isinstance(a, ComponentInstanceType)) + assert(isinstance(b, ComponentInstanceType)) + exports = a.exports(engine) + self.assertEqual(len(exports), 2) + self.assertIsInstance(exports['a'], FuncType) + self.assertIsInstance(exports['b'], ModuleType) + + self.assertEqual(len(b.exports(engine)), 0) + + with self.assertRaises(WasmtimeError): + ComponentInstanceType() + + def test_func(self): + engine = Engine() + cty = Component(engine, """ + (component + (import "a" (func)) + (import "b" (func (param "x" u32))) + (import "c" (func (result string))) + (import "d" (func (param "a" u8) (param "b" u16) (result u32))) + ) + """).type + a = cty.imports(engine)['a'] + b = cty.imports(engine)['b'] + c = cty.imports(engine)['c'] + d = cty.imports(engine)['d'] + assert(isinstance(a, FuncType)) + assert(isinstance(b, FuncType)) + assert(isinstance(c, FuncType)) + assert(isinstance(d, FuncType)) + + self.assertEqual(a.params, []) + self.assertIsNone(a.result) + self.assertEqual(b.params, [('x', U32())]) + self.assertIsNone(a.result) + self.assertEqual(c.params, []) + self.assertEqual(c.result, String()) + self.assertEqual(d.params, [('a', U8()), ('b', U16())]) + self.assertEqual(d.result, U32()) + + with self.assertRaises(WasmtimeError): + FuncType() + + def test_primitives(self): + self.assertEqual(simplety('bool'), Bool()) + self.assertEqual(simplety('u8'), U8()) + self.assertEqual(simplety('u16'), U16()) + self.assertEqual(simplety('u32'), U32()) + self.assertEqual(simplety('u64'), U64()) + self.assertEqual(simplety('s8'), S8()) + self.assertEqual(simplety('s16'), S16()) + self.assertEqual(simplety('s32'), S32()) + self.assertEqual(simplety('s64'), S64()) + self.assertEqual(simplety('f32'), F32()) + self.assertEqual(simplety('f64'), F64()) + self.assertEqual(simplety('char'), Char()) + self.assertEqual(simplety('string'), String()) + + def test_list(self): + l = simplety('(list u8)') + assert(isinstance(l, ListType)) + self.assertEqual(l.element, U8()) + self.assertEqual(l, simplety('(list u8)')) + self.assertNotEqual(l, simplety('(list u16)')) + + def test_record(self): + r = namedty('(record (field "a" u8) (field "b" f32))') + assert(isinstance(r, RecordType)) + self.assertEqual(r.fields, [('a', U8()), ('b', F32())]) + self.assertEqual(r, namedty('(record (field "a" u8) (field "b" f32))')) + self.assertNotEqual(r, namedty('(record (field "a" u8) (field "b" f64))')) + + def test_tuple(self): + t = namedty('(tuple u8 f32)') + assert(isinstance(t, TupleType)) + self.assertEqual(t.elements, [U8(), F32()]) + self.assertEqual(t, namedty('(tuple u8 f32)')) + self.assertNotEqual(t, namedty('(tuple u8 f64)')) + + def test_variant(self): + t = namedty('(variant (case "a") (case "b" f32))') + assert(isinstance(t, VariantType)) + self.assertEqual(t.cases, [('a', None), ('b', F32())]) + self.assertEqual(t, namedty('(variant (case "a") (case "b" f32))')) + self.assertNotEqual(t, namedty('(variant (case "a") (case "b" f64))')) + + def test_enum(self): + e = namedty('(enum "a" "b" "c")') + assert(isinstance(e, EnumType)) + self.assertEqual(e.names, ['a', 'b', 'c']) + self.assertEqual(e, namedty('(enum "a" "b" "c")')) + self.assertNotEqual(e, namedty('(enum "a" "b" "d")')) + + def test_option(self): + o = simplety('(option u32)') + assert(isinstance(o, OptionType)) + self.assertEqual(o.payload, U32()) + self.assertEqual(o, simplety('(option u32)')) + self.assertNotEqual(o, simplety('(option u64)')) + + def test_result(self): + r = simplety('(result u32 (error f32))') + assert(isinstance(r, ResultType)) + self.assertEqual(r.ok, U32()) + self.assertEqual(r.err, F32()) + self.assertEqual(r, simplety('(result u32 (error f32))')) + + r = simplety('(result (error f32))') + assert(isinstance(r, ResultType)) + self.assertIsNone(r.ok) + self.assertEqual(r.err, F32()) + + r = simplety('(result u32)') + assert(isinstance(r, ResultType)) + self.assertEqual(r.ok, U32()) + self.assertIsNone(r.err) + + r = simplety('(result)') + assert(isinstance(r, ResultType)) + self.assertIsNone(r.ok) + self.assertIsNone(r.err) + + def test_flags(self): + f = namedty('(flags "a" "b" "c")') + assert(isinstance(f, FlagsType)) + self.assertEqual(f.names, ['a', 'b', 'c']) + self.assertEqual(f, namedty('(flags "a" "b" "c")')) + self.assertNotEqual(f, namedty('(flags "a" "b" "d")')) + + def test_own_and_borrow(self): + engine = Engine() + c = Component(engine, f""" + (component + (import "r" (type $r (sub resource))) + (import "a" (func (param "x" (borrow $r)) (result (own $r)))) + ) + """) + fty = c.type.imports(engine)['a'] + assert(isinstance(fty, FuncType)) + _, param = fty.params[0] + result = fty.result + assert(isinstance(param, BorrowType)) + assert(isinstance(result, OwnType)) + self.assertEqual(param.ty, result.ty) diff --git a/tests/component/test_value.py b/tests/component/test_value.py new file mode 100644 index 00000000..78d8f486 --- /dev/null +++ b/tests/component/test_value.py @@ -0,0 +1,174 @@ +import unittest + +from wasmtime import Store, WasmtimeError +from wasmtime.component import * + + +class TestValue(unittest.TestCase): + def test_resource_type(self): + r1 = ResourceType.host(1) + r2 = ResourceType.host(2) + r3 = ResourceType.host(1) + self.assertNotEqual(r1, r2) + self.assertEqual(r1, r3) + + def test_resource_host(self): + store = Store() + r1 = ResourceHost.own(42, 1) + + r2 = r1.to_any(store) + self.assertEqual(r2.type, ResourceType.host(1)) + self.assertTrue(r2.owned) + + r3 = r2.to_host(store) + self.assertTrue(r3.owned) + self.assertEqual(r3.rep, 42) + self.assertEqual(r3.type, 1) + + with self.assertRaises(WasmtimeError): + r2.drop(store) + + r4 = r3.to_any(store) + r4.drop(store) + + r5 = ResourceHost.borrow(84, 2) + self.assertFalse(r5.owned) + self.assertEqual(r5.rep, 84) + self.assertEqual(r5.type, 2) + + with self.assertRaises(WasmtimeError): + ResourceHost() + + def test_resource_host_dtor(self): + store = Store() + linker = Linker(store.engine) + + def drop(_store, rep): + self.assertEqual(rep, 100) + + with linker.root() as l: + l.add_resource('t', ResourceType.host(23), drop) + + component = Component(store.engine, """ + (component + (import "t" (type $t (sub resource))) + (core func $drop (canon resource.drop $t)) + (core module $a + (import "" "drop" (func $drop (param i32))) + (func (export "drop") (param i32) + local.get 0 + call $drop) + ) + (core instance $a (instantiate $a + (with "" (instance + (export "drop" (func $drop)) + )) + )) + (func (export "drop") (param "x" (own $t)) + (canon lift (core func $a "drop"))) + ) + """) + instance = linker.instantiate(store, component) + f = instance.get_func(store, 'drop') + assert(f is not None) + + with self.assertRaises(WasmtimeError): + f(store, ResourceHost.own(1, 2)) + + instance = linker.instantiate(store, component) + f = instance.get_func(store, 'drop') + assert(f is not None) + f(store, ResourceHost.own(100, 23)) + + def test_exception_in_host_resource_dtor(self): + store = Store() + linker = Linker(store.engine) + + def drop(_store, _rep): + raise RuntimeError('oh no') + + with linker.root() as l: + l.add_resource('t', ResourceType.host(2), drop) + + component = Component(store.engine, """ + (component + (import "t" (type $t (sub resource))) + (core func $drop (canon resource.drop $t)) + (core module $a + (import "" "drop" (func $drop (param i32))) + (func (export "drop") (param i32) + local.get 0 + call $drop) + ) + (core instance $a (instantiate $a + (with "" (instance + (export "drop" (func $drop)) + )) + )) + (func (export "drop") (param "x" (own $t)) + (canon lift (core func $a "drop"))) + ) + """) + instance = linker.instantiate(store, component) + f = instance.get_func(store, 'drop') + assert(f is not None) + + with self.assertRaises(RuntimeError) as cm: + f(store, ResourceHost.own(1, 2)) + self.assertEqual(str(cm.exception), 'oh no') + + def test_resource_any(self): + with self.assertRaises(WasmtimeError): + ResourceAny() + + store = Store() + linker = Linker(store.engine) + + component = Component(store.engine, """ + (component + (type $t' (resource (rep i32))) + (export $t "t" (type $t')) + (core func $new (canon resource.new $t)) + (core func $drop (canon resource.drop $t)) + (core module $a + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + (func (export "new") (param i32) (result i32) + local.get 0 + call $new) + (func (export "drop") (param i32) + local.get 0 + call $drop) + ) + (core instance $a (instantiate $a + (with "" (instance + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) + (func (export "new") (param "x" u32) (result (own $t)) + (canon lift (core func $a "new"))) + (func (export "drop") (param "x" (own $t)) + (canon lift (core func $a "drop"))) + ) + """) + instance = linker.instantiate(store, component) + new = instance.get_func(store, 'new') + drop = instance.get_func(store, 'drop') + assert(new is not None) + assert(drop is not None) + + r1 = new(store, 100) + new.post_return(store) + r2 = new(store, 200) + new.post_return(store) + + with self.assertRaises(WasmtimeError): + r1.to_host(store) + + r1.drop(store) + drop(store, r2) + drop.post_return(store) + + with self.assertRaises(WasmtimeError): + drop(store, ResourceHost.own(1, 1)) diff --git a/tests/test_linker.py b/tests/test_linker.py index f72bdd84..7b914d44 100644 --- a/tests/test_linker.py +++ b/tests/test_linker.py @@ -99,8 +99,6 @@ def test_instantiate(self): def test_errors(self): linker = Linker(Engine()) - with self.assertRaises(TypeError): - linker.allow_shadowing = 2 with self.assertRaises(AttributeError): Linker(2) # type: ignore with self.assertRaises(AttributeError): diff --git a/wasmtime/__init__.py b/wasmtime/__init__.py index df9454fa..fc918ee4 100644 --- a/wasmtime/__init__.py +++ b/wasmtime/__init__.py @@ -17,7 +17,7 @@ from ._error import WasmtimeError, ExitTrap from ._config import Config from ._engine import Engine -from ._store import Store, Storelike +from ._store import Store, Storelike, StoreContext from ._types import FuncType, GlobalType, MemoryType, TableType from ._types import ValType, Limits, ImportType, ExportType from ._wat2wasm import wat2wasm @@ -64,4 +64,5 @@ 'DirPerms', 'Linker', 'WasmtimeError', + 'StoreContext', ] diff --git a/wasmtime/_bindings.py b/wasmtime/_bindings.py index 64b8d6c4..93031b3b 100644 --- a/wasmtime/_bindings.py +++ b/wasmtime/_bindings.py @@ -3527,6 +3527,621 @@ class wasmtime_stack_creator(Structure): def wasmtime_config_host_stack_creator_set(arg0: Any, arg1: Any) -> None: return _wasmtime_config_host_stack_creator_set(arg0, arg1) # type: ignore +class wasmtime_component_resource_type(Structure): + pass + +wasmtime_component_resource_type_t = wasmtime_component_resource_type + +_wasmtime_component_resource_type_new_host = dll.wasmtime_component_resource_type_new_host +_wasmtime_component_resource_type_new_host.restype = POINTER(wasmtime_component_resource_type_t) +_wasmtime_component_resource_type_new_host.argtypes = [c_uint32] +def wasmtime_component_resource_type_new_host(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_resource_type_new_host(ty) # type: ignore + +_wasmtime_component_resource_type_clone = dll.wasmtime_component_resource_type_clone +_wasmtime_component_resource_type_clone.restype = POINTER(wasmtime_component_resource_type_t) +_wasmtime_component_resource_type_clone.argtypes = [POINTER(wasmtime_component_resource_type_t)] +def wasmtime_component_resource_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_resource_type_clone(ty) # type: ignore + +_wasmtime_component_resource_type_equal = dll.wasmtime_component_resource_type_equal +_wasmtime_component_resource_type_equal.restype = c_bool +_wasmtime_component_resource_type_equal.argtypes = [POINTER(wasmtime_component_resource_type_t), POINTER(wasmtime_component_resource_type_t)] +def wasmtime_component_resource_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_resource_type_equal(a, b) # type: ignore + +_wasmtime_component_resource_type_delete = dll.wasmtime_component_resource_type_delete +_wasmtime_component_resource_type_delete.restype = None +_wasmtime_component_resource_type_delete.argtypes = [POINTER(wasmtime_component_resource_type_t)] +def wasmtime_component_resource_type_delete(resource: Any) -> None: + return _wasmtime_component_resource_type_delete(resource) # type: ignore + +class wasmtime_component_valtype_t(Structure): + pass + +class wasmtime_component_list_type(Structure): + pass + +wasmtime_component_list_type_t = wasmtime_component_list_type + +_wasmtime_component_list_type_clone = dll.wasmtime_component_list_type_clone +_wasmtime_component_list_type_clone.restype = POINTER(wasmtime_component_list_type_t) +_wasmtime_component_list_type_clone.argtypes = [POINTER(wasmtime_component_list_type_t)] +def wasmtime_component_list_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_list_type_clone(ty) # type: ignore + +_wasmtime_component_list_type_equal = dll.wasmtime_component_list_type_equal +_wasmtime_component_list_type_equal.restype = c_bool +_wasmtime_component_list_type_equal.argtypes = [POINTER(wasmtime_component_list_type_t), POINTER(wasmtime_component_list_type_t)] +def wasmtime_component_list_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_list_type_equal(a, b) # type: ignore + +_wasmtime_component_list_type_delete = dll.wasmtime_component_list_type_delete +_wasmtime_component_list_type_delete.restype = None +_wasmtime_component_list_type_delete.argtypes = [POINTER(wasmtime_component_list_type_t)] +def wasmtime_component_list_type_delete(ptr: Any) -> None: + return _wasmtime_component_list_type_delete(ptr) # type: ignore + +_wasmtime_component_list_type_element = dll.wasmtime_component_list_type_element +_wasmtime_component_list_type_element.restype = None +_wasmtime_component_list_type_element.argtypes = [POINTER(wasmtime_component_list_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_list_type_element(ty: Any, type_ret: Any) -> None: + return _wasmtime_component_list_type_element(ty, type_ret) # type: ignore + +class wasmtime_component_record_type(Structure): + pass + +wasmtime_component_record_type_t = wasmtime_component_record_type + +_wasmtime_component_record_type_clone = dll.wasmtime_component_record_type_clone +_wasmtime_component_record_type_clone.restype = POINTER(wasmtime_component_record_type_t) +_wasmtime_component_record_type_clone.argtypes = [POINTER(wasmtime_component_record_type_t)] +def wasmtime_component_record_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_record_type_clone(ty) # type: ignore + +_wasmtime_component_record_type_equal = dll.wasmtime_component_record_type_equal +_wasmtime_component_record_type_equal.restype = c_bool +_wasmtime_component_record_type_equal.argtypes = [POINTER(wasmtime_component_record_type_t), POINTER(wasmtime_component_record_type_t)] +def wasmtime_component_record_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_record_type_equal(a, b) # type: ignore + +_wasmtime_component_record_type_delete = dll.wasmtime_component_record_type_delete +_wasmtime_component_record_type_delete.restype = None +_wasmtime_component_record_type_delete.argtypes = [POINTER(wasmtime_component_record_type_t)] +def wasmtime_component_record_type_delete(ptr: Any) -> None: + return _wasmtime_component_record_type_delete(ptr) # type: ignore + +_wasmtime_component_record_type_field_count = dll.wasmtime_component_record_type_field_count +_wasmtime_component_record_type_field_count.restype = c_size_t +_wasmtime_component_record_type_field_count.argtypes = [POINTER(wasmtime_component_record_type_t)] +def wasmtime_component_record_type_field_count(ty: Any) -> int: + return _wasmtime_component_record_type_field_count(ty) # type: ignore + +_wasmtime_component_record_type_field_nth = dll.wasmtime_component_record_type_field_nth +_wasmtime_component_record_type_field_nth.restype = c_bool +_wasmtime_component_record_type_field_nth.argtypes = [POINTER(wasmtime_component_record_type_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_record_type_field_nth(ty: Any, nth: Any, name_ret: Any, name_len_ret: Any, type_ret: Any) -> bool: + return _wasmtime_component_record_type_field_nth(ty, nth, name_ret, name_len_ret, type_ret) # type: ignore + +class wasmtime_component_tuple_type(Structure): + pass + +wasmtime_component_tuple_type_t = wasmtime_component_tuple_type + +_wasmtime_component_tuple_type_clone = dll.wasmtime_component_tuple_type_clone +_wasmtime_component_tuple_type_clone.restype = POINTER(wasmtime_component_tuple_type_t) +_wasmtime_component_tuple_type_clone.argtypes = [POINTER(wasmtime_component_tuple_type_t)] +def wasmtime_component_tuple_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_tuple_type_clone(ty) # type: ignore + +_wasmtime_component_tuple_type_equal = dll.wasmtime_component_tuple_type_equal +_wasmtime_component_tuple_type_equal.restype = c_bool +_wasmtime_component_tuple_type_equal.argtypes = [POINTER(wasmtime_component_tuple_type_t), POINTER(wasmtime_component_tuple_type_t)] +def wasmtime_component_tuple_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_tuple_type_equal(a, b) # type: ignore + +_wasmtime_component_tuple_type_delete = dll.wasmtime_component_tuple_type_delete +_wasmtime_component_tuple_type_delete.restype = None +_wasmtime_component_tuple_type_delete.argtypes = [POINTER(wasmtime_component_tuple_type_t)] +def wasmtime_component_tuple_type_delete(ptr: Any) -> None: + return _wasmtime_component_tuple_type_delete(ptr) # type: ignore + +_wasmtime_component_tuple_type_types_count = dll.wasmtime_component_tuple_type_types_count +_wasmtime_component_tuple_type_types_count.restype = c_size_t +_wasmtime_component_tuple_type_types_count.argtypes = [POINTER(wasmtime_component_tuple_type_t)] +def wasmtime_component_tuple_type_types_count(ty: Any) -> int: + return _wasmtime_component_tuple_type_types_count(ty) # type: ignore + +_wasmtime_component_tuple_type_types_nth = dll.wasmtime_component_tuple_type_types_nth +_wasmtime_component_tuple_type_types_nth.restype = c_bool +_wasmtime_component_tuple_type_types_nth.argtypes = [POINTER(wasmtime_component_tuple_type_t), c_size_t, POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_tuple_type_types_nth(ty: Any, nth: Any, type_ret: Any) -> bool: + return _wasmtime_component_tuple_type_types_nth(ty, nth, type_ret) # type: ignore + +class wasmtime_component_variant_type(Structure): + pass + +wasmtime_component_variant_type_t = wasmtime_component_variant_type + +_wasmtime_component_variant_type_clone = dll.wasmtime_component_variant_type_clone +_wasmtime_component_variant_type_clone.restype = POINTER(wasmtime_component_variant_type_t) +_wasmtime_component_variant_type_clone.argtypes = [POINTER(wasmtime_component_variant_type_t)] +def wasmtime_component_variant_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_variant_type_clone(ty) # type: ignore + +_wasmtime_component_variant_type_equal = dll.wasmtime_component_variant_type_equal +_wasmtime_component_variant_type_equal.restype = c_bool +_wasmtime_component_variant_type_equal.argtypes = [POINTER(wasmtime_component_variant_type_t), POINTER(wasmtime_component_variant_type_t)] +def wasmtime_component_variant_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_variant_type_equal(a, b) # type: ignore + +_wasmtime_component_variant_type_delete = dll.wasmtime_component_variant_type_delete +_wasmtime_component_variant_type_delete.restype = None +_wasmtime_component_variant_type_delete.argtypes = [POINTER(wasmtime_component_variant_type_t)] +def wasmtime_component_variant_type_delete(ptr: Any) -> None: + return _wasmtime_component_variant_type_delete(ptr) # type: ignore + +_wasmtime_component_variant_type_case_count = dll.wasmtime_component_variant_type_case_count +_wasmtime_component_variant_type_case_count.restype = c_size_t +_wasmtime_component_variant_type_case_count.argtypes = [POINTER(wasmtime_component_variant_type_t)] +def wasmtime_component_variant_type_case_count(ty: Any) -> int: + return _wasmtime_component_variant_type_case_count(ty) # type: ignore + +_wasmtime_component_variant_type_case_nth = dll.wasmtime_component_variant_type_case_nth +_wasmtime_component_variant_type_case_nth.restype = c_bool +_wasmtime_component_variant_type_case_nth.argtypes = [POINTER(wasmtime_component_variant_type_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t), POINTER(c_bool), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_variant_type_case_nth(ty: Any, nth: Any, name_ret: Any, name_len_ret: Any, has_payload_ret: Any, payload_ret: Any) -> bool: + return _wasmtime_component_variant_type_case_nth(ty, nth, name_ret, name_len_ret, has_payload_ret, payload_ret) # type: ignore + +class wasmtime_component_enum_type(Structure): + pass + +wasmtime_component_enum_type_t = wasmtime_component_enum_type + +_wasmtime_component_enum_type_clone = dll.wasmtime_component_enum_type_clone +_wasmtime_component_enum_type_clone.restype = POINTER(wasmtime_component_enum_type_t) +_wasmtime_component_enum_type_clone.argtypes = [POINTER(wasmtime_component_enum_type_t)] +def wasmtime_component_enum_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_enum_type_clone(ty) # type: ignore + +_wasmtime_component_enum_type_equal = dll.wasmtime_component_enum_type_equal +_wasmtime_component_enum_type_equal.restype = c_bool +_wasmtime_component_enum_type_equal.argtypes = [POINTER(wasmtime_component_enum_type_t), POINTER(wasmtime_component_enum_type_t)] +def wasmtime_component_enum_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_enum_type_equal(a, b) # type: ignore + +_wasmtime_component_enum_type_delete = dll.wasmtime_component_enum_type_delete +_wasmtime_component_enum_type_delete.restype = None +_wasmtime_component_enum_type_delete.argtypes = [POINTER(wasmtime_component_enum_type_t)] +def wasmtime_component_enum_type_delete(ptr: Any) -> None: + return _wasmtime_component_enum_type_delete(ptr) # type: ignore + +_wasmtime_component_enum_type_names_count = dll.wasmtime_component_enum_type_names_count +_wasmtime_component_enum_type_names_count.restype = c_size_t +_wasmtime_component_enum_type_names_count.argtypes = [POINTER(wasmtime_component_enum_type_t)] +def wasmtime_component_enum_type_names_count(ty: Any) -> int: + return _wasmtime_component_enum_type_names_count(ty) # type: ignore + +_wasmtime_component_enum_type_names_nth = dll.wasmtime_component_enum_type_names_nth +_wasmtime_component_enum_type_names_nth.restype = c_bool +_wasmtime_component_enum_type_names_nth.argtypes = [POINTER(wasmtime_component_enum_type_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t)] +def wasmtime_component_enum_type_names_nth(ty: Any, nth: Any, name_ret: Any, name_len_ret: Any) -> bool: + return _wasmtime_component_enum_type_names_nth(ty, nth, name_ret, name_len_ret) # type: ignore + +class wasmtime_component_option_type(Structure): + pass + +wasmtime_component_option_type_t = wasmtime_component_option_type + +_wasmtime_component_option_type_clone = dll.wasmtime_component_option_type_clone +_wasmtime_component_option_type_clone.restype = POINTER(wasmtime_component_option_type_t) +_wasmtime_component_option_type_clone.argtypes = [POINTER(wasmtime_component_option_type_t)] +def wasmtime_component_option_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_option_type_clone(ty) # type: ignore + +_wasmtime_component_option_type_equal = dll.wasmtime_component_option_type_equal +_wasmtime_component_option_type_equal.restype = c_bool +_wasmtime_component_option_type_equal.argtypes = [POINTER(wasmtime_component_option_type_t), POINTER(wasmtime_component_option_type_t)] +def wasmtime_component_option_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_option_type_equal(a, b) # type: ignore + +_wasmtime_component_option_type_delete = dll.wasmtime_component_option_type_delete +_wasmtime_component_option_type_delete.restype = None +_wasmtime_component_option_type_delete.argtypes = [POINTER(wasmtime_component_option_type_t)] +def wasmtime_component_option_type_delete(ptr: Any) -> None: + return _wasmtime_component_option_type_delete(ptr) # type: ignore + +_wasmtime_component_option_type_ty = dll.wasmtime_component_option_type_ty +_wasmtime_component_option_type_ty.restype = None +_wasmtime_component_option_type_ty.argtypes = [POINTER(wasmtime_component_option_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_option_type_ty(ty: Any, type_ret: Any) -> None: + return _wasmtime_component_option_type_ty(ty, type_ret) # type: ignore + +class wasmtime_component_result_type(Structure): + pass + +wasmtime_component_result_type_t = wasmtime_component_result_type + +_wasmtime_component_result_type_clone = dll.wasmtime_component_result_type_clone +_wasmtime_component_result_type_clone.restype = POINTER(wasmtime_component_result_type_t) +_wasmtime_component_result_type_clone.argtypes = [POINTER(wasmtime_component_result_type_t)] +def wasmtime_component_result_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_result_type_clone(ty) # type: ignore + +_wasmtime_component_result_type_equal = dll.wasmtime_component_result_type_equal +_wasmtime_component_result_type_equal.restype = c_bool +_wasmtime_component_result_type_equal.argtypes = [POINTER(wasmtime_component_result_type_t), POINTER(wasmtime_component_result_type_t)] +def wasmtime_component_result_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_result_type_equal(a, b) # type: ignore + +_wasmtime_component_result_type_delete = dll.wasmtime_component_result_type_delete +_wasmtime_component_result_type_delete.restype = None +_wasmtime_component_result_type_delete.argtypes = [POINTER(wasmtime_component_result_type_t)] +def wasmtime_component_result_type_delete(ptr: Any) -> None: + return _wasmtime_component_result_type_delete(ptr) # type: ignore + +_wasmtime_component_result_type_ok = dll.wasmtime_component_result_type_ok +_wasmtime_component_result_type_ok.restype = c_bool +_wasmtime_component_result_type_ok.argtypes = [POINTER(wasmtime_component_result_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_result_type_ok(ty: Any, type_ret: Any) -> bool: + return _wasmtime_component_result_type_ok(ty, type_ret) # type: ignore + +_wasmtime_component_result_type_err = dll.wasmtime_component_result_type_err +_wasmtime_component_result_type_err.restype = c_bool +_wasmtime_component_result_type_err.argtypes = [POINTER(wasmtime_component_result_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_result_type_err(ty: Any, type_ret: Any) -> bool: + return _wasmtime_component_result_type_err(ty, type_ret) # type: ignore + +class wasmtime_component_flags_type(Structure): + pass + +wasmtime_component_flags_type_t = wasmtime_component_flags_type + +_wasmtime_component_flags_type_clone = dll.wasmtime_component_flags_type_clone +_wasmtime_component_flags_type_clone.restype = POINTER(wasmtime_component_flags_type_t) +_wasmtime_component_flags_type_clone.argtypes = [POINTER(wasmtime_component_flags_type_t)] +def wasmtime_component_flags_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_flags_type_clone(ty) # type: ignore + +_wasmtime_component_flags_type_equal = dll.wasmtime_component_flags_type_equal +_wasmtime_component_flags_type_equal.restype = c_bool +_wasmtime_component_flags_type_equal.argtypes = [POINTER(wasmtime_component_flags_type_t), POINTER(wasmtime_component_flags_type_t)] +def wasmtime_component_flags_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_flags_type_equal(a, b) # type: ignore + +_wasmtime_component_flags_type_delete = dll.wasmtime_component_flags_type_delete +_wasmtime_component_flags_type_delete.restype = None +_wasmtime_component_flags_type_delete.argtypes = [POINTER(wasmtime_component_flags_type_t)] +def wasmtime_component_flags_type_delete(ptr: Any) -> None: + return _wasmtime_component_flags_type_delete(ptr) # type: ignore + +_wasmtime_component_flags_type_names_count = dll.wasmtime_component_flags_type_names_count +_wasmtime_component_flags_type_names_count.restype = c_size_t +_wasmtime_component_flags_type_names_count.argtypes = [POINTER(wasmtime_component_flags_type_t)] +def wasmtime_component_flags_type_names_count(ty: Any) -> int: + return _wasmtime_component_flags_type_names_count(ty) # type: ignore + +_wasmtime_component_flags_type_names_nth = dll.wasmtime_component_flags_type_names_nth +_wasmtime_component_flags_type_names_nth.restype = c_bool +_wasmtime_component_flags_type_names_nth.argtypes = [POINTER(wasmtime_component_flags_type_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t)] +def wasmtime_component_flags_type_names_nth(ty: Any, nth: Any, name_ret: Any, name_len_ret: Any) -> bool: + return _wasmtime_component_flags_type_names_nth(ty, nth, name_ret, name_len_ret) # type: ignore + +class wasmtime_component_future_type(Structure): + pass + +wasmtime_component_future_type_t = wasmtime_component_future_type + +_wasmtime_component_future_type_clone = dll.wasmtime_component_future_type_clone +_wasmtime_component_future_type_clone.restype = POINTER(wasmtime_component_future_type_t) +_wasmtime_component_future_type_clone.argtypes = [POINTER(wasmtime_component_future_type_t)] +def wasmtime_component_future_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_future_type_clone(ty) # type: ignore + +_wasmtime_component_future_type_equal = dll.wasmtime_component_future_type_equal +_wasmtime_component_future_type_equal.restype = c_bool +_wasmtime_component_future_type_equal.argtypes = [POINTER(wasmtime_component_future_type_t), POINTER(wasmtime_component_future_type_t)] +def wasmtime_component_future_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_future_type_equal(a, b) # type: ignore + +_wasmtime_component_future_type_delete = dll.wasmtime_component_future_type_delete +_wasmtime_component_future_type_delete.restype = None +_wasmtime_component_future_type_delete.argtypes = [POINTER(wasmtime_component_future_type_t)] +def wasmtime_component_future_type_delete(ptr: Any) -> None: + return _wasmtime_component_future_type_delete(ptr) # type: ignore + +_wasmtime_component_future_type_ty = dll.wasmtime_component_future_type_ty +_wasmtime_component_future_type_ty.restype = c_bool +_wasmtime_component_future_type_ty.argtypes = [POINTER(wasmtime_component_future_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_future_type_ty(ty: Any, type_ret: Any) -> bool: + return _wasmtime_component_future_type_ty(ty, type_ret) # type: ignore + +class wasmtime_component_stream_type(Structure): + pass + +wasmtime_component_stream_type_t = wasmtime_component_stream_type + +_wasmtime_component_stream_type_clone = dll.wasmtime_component_stream_type_clone +_wasmtime_component_stream_type_clone.restype = POINTER(wasmtime_component_stream_type_t) +_wasmtime_component_stream_type_clone.argtypes = [POINTER(wasmtime_component_stream_type_t)] +def wasmtime_component_stream_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_stream_type_clone(ty) # type: ignore + +_wasmtime_component_stream_type_equal = dll.wasmtime_component_stream_type_equal +_wasmtime_component_stream_type_equal.restype = c_bool +_wasmtime_component_stream_type_equal.argtypes = [POINTER(wasmtime_component_stream_type_t), POINTER(wasmtime_component_stream_type_t)] +def wasmtime_component_stream_type_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_stream_type_equal(a, b) # type: ignore + +_wasmtime_component_stream_type_delete = dll.wasmtime_component_stream_type_delete +_wasmtime_component_stream_type_delete.restype = None +_wasmtime_component_stream_type_delete.argtypes = [POINTER(wasmtime_component_stream_type_t)] +def wasmtime_component_stream_type_delete(ptr: Any) -> None: + return _wasmtime_component_stream_type_delete(ptr) # type: ignore + +_wasmtime_component_stream_type_ty = dll.wasmtime_component_stream_type_ty +_wasmtime_component_stream_type_ty.restype = c_bool +_wasmtime_component_stream_type_ty.argtypes = [POINTER(wasmtime_component_stream_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_stream_type_ty(ty: Any, type_ret: Any) -> bool: + return _wasmtime_component_stream_type_ty(ty, type_ret) # type: ignore + +wasmtime_component_valtype_kind_t = c_uint8 + +class wasmtime_component_valtype_union(Union): + _fields_ = [ + ("list", POINTER(wasmtime_component_list_type_t)), + ("record", POINTER(wasmtime_component_record_type_t)), + ("tuple", POINTER(wasmtime_component_tuple_type_t)), + ("variant", POINTER(wasmtime_component_variant_type_t)), + ("enum_", POINTER(wasmtime_component_enum_type_t)), + ("option", POINTER(wasmtime_component_option_type_t)), + ("result", POINTER(wasmtime_component_result_type_t)), + ("flags", POINTER(wasmtime_component_flags_type_t)), + ("own", POINTER(wasmtime_component_resource_type_t)), + ("borrow", POINTER(wasmtime_component_resource_type_t)), + ("future", POINTER(wasmtime_component_future_type_t)), + ("stream", POINTER(wasmtime_component_stream_type_t)), + ] + list: ctypes._Pointer + record: ctypes._Pointer + tuple: ctypes._Pointer + variant: ctypes._Pointer + enum_: ctypes._Pointer + option: ctypes._Pointer + result: ctypes._Pointer + flags: ctypes._Pointer + own: ctypes._Pointer + borrow: ctypes._Pointer + future: ctypes._Pointer + stream: ctypes._Pointer + +wasmtime_component_valtype_union_t = wasmtime_component_valtype_union + +wasmtime_component_valtype_t._fields_ = [ + ("kind", wasmtime_component_valtype_kind_t), + ("of", wasmtime_component_valtype_union_t), + ] + +_wasmtime_component_valtype_clone = dll.wasmtime_component_valtype_clone +_wasmtime_component_valtype_clone.restype = None +_wasmtime_component_valtype_clone.argtypes = [POINTER(wasmtime_component_valtype_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_valtype_clone(ty: Any, out: Any) -> None: + return _wasmtime_component_valtype_clone(ty, out) # type: ignore + +_wasmtime_component_valtype_equal = dll.wasmtime_component_valtype_equal +_wasmtime_component_valtype_equal.restype = c_bool +_wasmtime_component_valtype_equal.argtypes = [POINTER(wasmtime_component_valtype_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_valtype_equal(a: Any, b: Any) -> bool: + return _wasmtime_component_valtype_equal(a, b) # type: ignore + +_wasmtime_component_valtype_delete = dll.wasmtime_component_valtype_delete +_wasmtime_component_valtype_delete.restype = None +_wasmtime_component_valtype_delete.argtypes = [POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_valtype_delete(ptr: Any) -> None: + return _wasmtime_component_valtype_delete(ptr) # type: ignore + +class wasmtime_component_func_type_t(Structure): + pass + +_wasmtime_component_func_type_clone = dll.wasmtime_component_func_type_clone +_wasmtime_component_func_type_clone.restype = POINTER(wasmtime_component_func_type_t) +_wasmtime_component_func_type_clone.argtypes = [POINTER(wasmtime_component_func_type_t)] +def wasmtime_component_func_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_func_type_clone(ty) # type: ignore + +_wasmtime_component_func_type_delete = dll.wasmtime_component_func_type_delete +_wasmtime_component_func_type_delete.restype = None +_wasmtime_component_func_type_delete.argtypes = [POINTER(wasmtime_component_func_type_t)] +def wasmtime_component_func_type_delete(ty: Any) -> None: + return _wasmtime_component_func_type_delete(ty) # type: ignore + +_wasmtime_component_func_type_param_count = dll.wasmtime_component_func_type_param_count +_wasmtime_component_func_type_param_count.restype = c_size_t +_wasmtime_component_func_type_param_count.argtypes = [POINTER(wasmtime_component_func_type_t)] +def wasmtime_component_func_type_param_count(ty: Any) -> int: + return _wasmtime_component_func_type_param_count(ty) # type: ignore + +_wasmtime_component_func_type_param_nth = dll.wasmtime_component_func_type_param_nth +_wasmtime_component_func_type_param_nth.restype = c_bool +_wasmtime_component_func_type_param_nth.argtypes = [POINTER(wasmtime_component_func_type_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_func_type_param_nth(ty: Any, nth: Any, name_ret: Any, name_len_ret: Any, type_ret: Any) -> bool: + return _wasmtime_component_func_type_param_nth(ty, nth, name_ret, name_len_ret, type_ret) # type: ignore + +_wasmtime_component_func_type_result = dll.wasmtime_component_func_type_result +_wasmtime_component_func_type_result.restype = c_bool +_wasmtime_component_func_type_result.argtypes = [POINTER(wasmtime_component_func_type_t), POINTER(wasmtime_component_valtype_t)] +def wasmtime_component_func_type_result(ty: Any, type_ret: Any) -> bool: + return _wasmtime_component_func_type_result(ty, type_ret) # type: ignore + +class wasmtime_component_item_t(Structure): + pass + +class wasmtime_component_instance_type(Structure): + pass + +wasmtime_component_instance_type_t = wasmtime_component_instance_type + +_wasmtime_component_instance_type_clone = dll.wasmtime_component_instance_type_clone +_wasmtime_component_instance_type_clone.restype = POINTER(wasmtime_component_instance_type_t) +_wasmtime_component_instance_type_clone.argtypes = [POINTER(wasmtime_component_instance_type_t)] +def wasmtime_component_instance_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_instance_type_clone(ty) # type: ignore + +_wasmtime_component_instance_type_delete = dll.wasmtime_component_instance_type_delete +_wasmtime_component_instance_type_delete.restype = None +_wasmtime_component_instance_type_delete.argtypes = [POINTER(wasmtime_component_instance_type_t)] +def wasmtime_component_instance_type_delete(ty: Any) -> None: + return _wasmtime_component_instance_type_delete(ty) # type: ignore + +_wasmtime_component_instance_type_export_count = dll.wasmtime_component_instance_type_export_count +_wasmtime_component_instance_type_export_count.restype = c_size_t +_wasmtime_component_instance_type_export_count.argtypes = [POINTER(wasmtime_component_instance_type_t), POINTER(wasm_engine_t)] +def wasmtime_component_instance_type_export_count(ty: Any, engine: Any) -> int: + return _wasmtime_component_instance_type_export_count(ty, engine) # type: ignore + +_wasmtime_component_instance_type_export_get = dll.wasmtime_component_instance_type_export_get +_wasmtime_component_instance_type_export_get.restype = c_bool +_wasmtime_component_instance_type_export_get.argtypes = [POINTER(wasmtime_component_instance_type_t), POINTER(wasm_engine_t), POINTER(c_char), c_size_t, POINTER(wasmtime_component_item_t)] +def wasmtime_component_instance_type_export_get(ty: Any, engine: Any, name: Any, name_len: Any, ret: Any) -> bool: + return _wasmtime_component_instance_type_export_get(ty, engine, name, name_len, ret) # type: ignore + +_wasmtime_component_instance_type_export_nth = dll.wasmtime_component_instance_type_export_nth +_wasmtime_component_instance_type_export_nth.restype = c_bool +_wasmtime_component_instance_type_export_nth.argtypes = [POINTER(wasmtime_component_instance_type_t), POINTER(wasm_engine_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t), POINTER(wasmtime_component_item_t)] +def wasmtime_component_instance_type_export_nth(ty: Any, engine: Any, nth: Any, name_ret: Any, name_len_ret: Any, type_ret: Any) -> bool: + return _wasmtime_component_instance_type_export_nth(ty, engine, nth, name_ret, name_len_ret, type_ret) # type: ignore + +class wasmtime_module_type(Structure): + pass + +wasmtime_module_type_t = wasmtime_module_type + +_wasmtime_module_type_clone = dll.wasmtime_module_type_clone +_wasmtime_module_type_clone.restype = POINTER(wasmtime_module_type_t) +_wasmtime_module_type_clone.argtypes = [POINTER(wasmtime_module_type_t)] +def wasmtime_module_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_module_type_clone(ty) # type: ignore + +_wasmtime_module_type_delete = dll.wasmtime_module_type_delete +_wasmtime_module_type_delete.restype = None +_wasmtime_module_type_delete.argtypes = [POINTER(wasmtime_module_type_t)] +def wasmtime_module_type_delete(ty: Any) -> None: + return _wasmtime_module_type_delete(ty) # type: ignore + +_wasmtime_module_type_import_count = dll.wasmtime_module_type_import_count +_wasmtime_module_type_import_count.restype = c_size_t +_wasmtime_module_type_import_count.argtypes = [POINTER(wasmtime_module_type_t), POINTER(wasm_engine_t)] +def wasmtime_module_type_import_count(ty: Any, engine: Any) -> int: + return _wasmtime_module_type_import_count(ty, engine) # type: ignore + +_wasmtime_module_type_import_nth = dll.wasmtime_module_type_import_nth +_wasmtime_module_type_import_nth.restype = POINTER(wasm_importtype_t) +_wasmtime_module_type_import_nth.argtypes = [POINTER(wasmtime_module_type_t), POINTER(wasm_engine_t), c_size_t] +def wasmtime_module_type_import_nth(ty: Any, engine: Any, nth: Any) -> ctypes._Pointer: + return _wasmtime_module_type_import_nth(ty, engine, nth) # type: ignore + +_wasmtime_module_type_export_count = dll.wasmtime_module_type_export_count +_wasmtime_module_type_export_count.restype = c_size_t +_wasmtime_module_type_export_count.argtypes = [POINTER(wasmtime_module_type_t), POINTER(wasm_engine_t)] +def wasmtime_module_type_export_count(ty: Any, engine: Any) -> int: + return _wasmtime_module_type_export_count(ty, engine) # type: ignore + +_wasmtime_module_type_export_nth = dll.wasmtime_module_type_export_nth +_wasmtime_module_type_export_nth.restype = POINTER(wasm_exporttype_t) +_wasmtime_module_type_export_nth.argtypes = [POINTER(wasmtime_module_type_t), POINTER(wasm_engine_t), c_size_t] +def wasmtime_module_type_export_nth(ty: Any, engine: Any, nth: Any) -> ctypes._Pointer: + return _wasmtime_module_type_export_nth(ty, engine, nth) # type: ignore + +class wasmtime_component_type_t(Structure): + pass + +_wasmtime_component_type_clone = dll.wasmtime_component_type_clone +_wasmtime_component_type_clone.restype = POINTER(wasmtime_component_type_t) +_wasmtime_component_type_clone.argtypes = [POINTER(wasmtime_component_type_t)] +def wasmtime_component_type_clone(ty: Any) -> ctypes._Pointer: + return _wasmtime_component_type_clone(ty) # type: ignore + +_wasmtime_component_type_delete = dll.wasmtime_component_type_delete +_wasmtime_component_type_delete.restype = None +_wasmtime_component_type_delete.argtypes = [POINTER(wasmtime_component_type_t)] +def wasmtime_component_type_delete(ty: Any) -> None: + return _wasmtime_component_type_delete(ty) # type: ignore + +_wasmtime_component_type_import_count = dll.wasmtime_component_type_import_count +_wasmtime_component_type_import_count.restype = c_size_t +_wasmtime_component_type_import_count.argtypes = [POINTER(wasmtime_component_type_t), POINTER(wasm_engine_t)] +def wasmtime_component_type_import_count(ty: Any, engine: Any) -> int: + return _wasmtime_component_type_import_count(ty, engine) # type: ignore + +_wasmtime_component_type_import_get = dll.wasmtime_component_type_import_get +_wasmtime_component_type_import_get.restype = c_bool +_wasmtime_component_type_import_get.argtypes = [POINTER(wasmtime_component_type_t), POINTER(wasm_engine_t), POINTER(c_char), c_size_t, POINTER(wasmtime_component_item_t)] +def wasmtime_component_type_import_get(ty: Any, engine: Any, name: Any, name_len: Any, ret: Any) -> bool: + return _wasmtime_component_type_import_get(ty, engine, name, name_len, ret) # type: ignore + +_wasmtime_component_type_import_nth = dll.wasmtime_component_type_import_nth +_wasmtime_component_type_import_nth.restype = c_bool +_wasmtime_component_type_import_nth.argtypes = [POINTER(wasmtime_component_type_t), POINTER(wasm_engine_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t), POINTER(wasmtime_component_item_t)] +def wasmtime_component_type_import_nth(ty: Any, engine: Any, nth: Any, name_ret: Any, name_len_ret: Any, type_ret: Any) -> bool: + return _wasmtime_component_type_import_nth(ty, engine, nth, name_ret, name_len_ret, type_ret) # type: ignore + +_wasmtime_component_type_export_count = dll.wasmtime_component_type_export_count +_wasmtime_component_type_export_count.restype = c_size_t +_wasmtime_component_type_export_count.argtypes = [POINTER(wasmtime_component_type_t), POINTER(wasm_engine_t)] +def wasmtime_component_type_export_count(ty: Any, engine: Any) -> int: + return _wasmtime_component_type_export_count(ty, engine) # type: ignore + +_wasmtime_component_type_export_get = dll.wasmtime_component_type_export_get +_wasmtime_component_type_export_get.restype = c_bool +_wasmtime_component_type_export_get.argtypes = [POINTER(wasmtime_component_type_t), POINTER(wasm_engine_t), POINTER(c_char), c_size_t, POINTER(wasmtime_component_item_t)] +def wasmtime_component_type_export_get(ty: Any, engine: Any, name: Any, name_len: Any, ret: Any) -> bool: + return _wasmtime_component_type_export_get(ty, engine, name, name_len, ret) # type: ignore + +_wasmtime_component_type_export_nth = dll.wasmtime_component_type_export_nth +_wasmtime_component_type_export_nth.restype = c_bool +_wasmtime_component_type_export_nth.argtypes = [POINTER(wasmtime_component_type_t), POINTER(wasm_engine_t), c_size_t, POINTER(POINTER(c_char)), POINTER(c_size_t), POINTER(wasmtime_component_item_t)] +def wasmtime_component_type_export_nth(ty: Any, engine: Any, nth: Any, name_ret: Any, name_len_ret: Any, type_ret: Any) -> bool: + return _wasmtime_component_type_export_nth(ty, engine, nth, name_ret, name_len_ret, type_ret) # type: ignore + +wasmtime_component_item_kind_t = c_uint8 + +class wasmtime_component_item_union(Union): + _fields_ = [ + ("component", POINTER(wasmtime_component_type_t)), + ("component_instance", POINTER(wasmtime_component_instance_type_t)), + ("module", POINTER(wasmtime_module_type_t)), + ("component_func", POINTER(wasmtime_component_func_type_t)), + ("resource", POINTER(wasmtime_component_resource_type_t)), + ("core_func", POINTER(wasm_functype_t)), + ("type", wasmtime_component_valtype_t), + ] + component: ctypes._Pointer + component_instance: ctypes._Pointer + module: ctypes._Pointer + component_func: ctypes._Pointer + resource: ctypes._Pointer + core_func: ctypes._Pointer + type: wasmtime_component_valtype_t + +wasmtime_component_item_union_t = wasmtime_component_item_union + +wasmtime_component_item_t._fields_ = [ + ("kind", wasmtime_component_item_kind_t), + ("of", wasmtime_component_item_union_t), + ] + +_wasmtime_component_item_clone = dll.wasmtime_component_item_clone +_wasmtime_component_item_clone.restype = None +_wasmtime_component_item_clone.argtypes = [POINTER(wasmtime_component_item_t), POINTER(wasmtime_component_item_t)] +def wasmtime_component_item_clone(item: Any, out: Any) -> None: + return _wasmtime_component_item_clone(item, out) # type: ignore + +_wasmtime_component_item_delete = dll.wasmtime_component_item_delete +_wasmtime_component_item_delete.restype = None +_wasmtime_component_item_delete.argtypes = [POINTER(wasmtime_component_item_t)] +def wasmtime_component_item_delete(ptr: Any) -> None: + return _wasmtime_component_item_delete(ptr) # type: ignore + class wasmtime_component_t(Structure): pass @@ -3560,6 +4175,12 @@ def wasmtime_component_deserialize_file(engine: Any, path: Any, component_out: A def wasmtime_component_clone(component: Any) -> ctypes._Pointer: return _wasmtime_component_clone(component) # type: ignore +_wasmtime_component_type = dll.wasmtime_component_type +_wasmtime_component_type.restype = POINTER(wasmtime_component_type_t) +_wasmtime_component_type.argtypes = [POINTER(wasmtime_component_t)] +def wasmtime_component_type(component: Any) -> ctypes._Pointer: + return _wasmtime_component_type(component) # type: ignore + _wasmtime_component_delete = dll.wasmtime_component_delete _wasmtime_component_delete.restype = None _wasmtime_component_delete.argtypes = [POINTER(wasmtime_component_t)] @@ -3587,35 +4208,6 @@ def wasmtime_component_export_index_clone(index: Any) -> ctypes._Pointer: def wasmtime_component_export_index_delete(export_index: Any) -> None: return _wasmtime_component_export_index_delete(export_index) # type: ignore -class wasmtime_component_resource_type(Structure): - pass - -wasmtime_component_resource_type_t = wasmtime_component_resource_type - -_wasmtime_component_resource_type_new_host = dll.wasmtime_component_resource_type_new_host -_wasmtime_component_resource_type_new_host.restype = POINTER(wasmtime_component_resource_type_t) -_wasmtime_component_resource_type_new_host.argtypes = [c_uint32] -def wasmtime_component_resource_type_new_host(ty: Any) -> ctypes._Pointer: - return _wasmtime_component_resource_type_new_host(ty) # type: ignore - -_wasmtime_component_resource_type_clone = dll.wasmtime_component_resource_type_clone -_wasmtime_component_resource_type_clone.restype = POINTER(wasmtime_component_resource_type_t) -_wasmtime_component_resource_type_clone.argtypes = [POINTER(wasmtime_component_resource_type_t)] -def wasmtime_component_resource_type_clone(ty: Any) -> ctypes._Pointer: - return _wasmtime_component_resource_type_clone(ty) # type: ignore - -_wasmtime_component_resource_type_equal = dll.wasmtime_component_resource_type_equal -_wasmtime_component_resource_type_equal.restype = c_bool -_wasmtime_component_resource_type_equal.argtypes = [POINTER(wasmtime_component_resource_type_t), POINTER(wasmtime_component_resource_type_t)] -def wasmtime_component_resource_type_equal(a: Any, b: Any) -> bool: - return _wasmtime_component_resource_type_equal(a, b) # type: ignore - -_wasmtime_component_resource_type_delete = dll.wasmtime_component_resource_type_delete -_wasmtime_component_resource_type_delete.restype = None -_wasmtime_component_resource_type_delete.argtypes = [POINTER(wasmtime_component_resource_type_t)] -def wasmtime_component_resource_type_delete(resource: Any) -> None: - return _wasmtime_component_resource_type_delete(resource) # type: ignore - class wasmtime_component_resource_any(Structure): pass @@ -3998,6 +4590,12 @@ class wasmtime_component_func(Structure): wasmtime_component_func_t = wasmtime_component_func +_wasmtime_component_func_type = dll.wasmtime_component_func_type +_wasmtime_component_func_type.restype = POINTER(wasmtime_component_func_type_t) +_wasmtime_component_func_type.argtypes = [POINTER(wasmtime_component_func_t), POINTER(wasmtime_context_t)] +def wasmtime_component_func_type(func: Any, context: Any) -> ctypes._Pointer: + return _wasmtime_component_func_type(func, context) # type: ignore + _wasmtime_component_func_call = dll.wasmtime_component_func_call _wasmtime_component_func_call.restype = POINTER(wasmtime_error_t) _wasmtime_component_func_call.argtypes = [POINTER(wasmtime_component_func_t), POINTER(wasmtime_context_t), POINTER(wasmtime_component_val_t), c_size_t, POINTER(wasmtime_component_val_t), c_size_t] @@ -4080,7 +4678,7 @@ def wasmtime_component_linker_instance_add_instance(linker_instance: Any, name: def wasmtime_component_linker_instance_add_module(linker_instance: Any, name: Any, name_len: Any, module: Any) -> ctypes._Pointer: return _wasmtime_component_linker_instance_add_module(linker_instance, name, name_len, module) # type: ignore -wasmtime_component_func_callback_t = CFUNCTYPE(c_size_t, c_void_p, POINTER(wasmtime_context_t), POINTER(wasmtime_component_val_t), c_size_t, POINTER(wasmtime_component_val_t), c_size_t) +wasmtime_component_func_callback_t = CFUNCTYPE(c_size_t, c_void_p, POINTER(wasmtime_context_t), POINTER(wasmtime_component_func_type_t), POINTER(wasmtime_component_val_t), c_size_t, POINTER(wasmtime_component_val_t), c_size_t) _wasmtime_component_linker_instance_add_func = dll.wasmtime_component_linker_instance_add_func _wasmtime_component_linker_instance_add_func.restype = POINTER(wasmtime_error_t) diff --git a/wasmtime/_error.py b/wasmtime/_error.py index 7152be5d..d2089cd8 100644 --- a/wasmtime/_error.py +++ b/wasmtime/_error.py @@ -10,12 +10,13 @@ class WasmtimeError(Exception, Managed["ctypes._Pointer[ffi.wasmtime_error_t]"]) def __init__(self, message: str): self.__message = message + self._set_ptr(ffi.wasmtime_error_new(message.encode('utf-8'))) def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_error_t]") -> None: ffi.wasmtime_error_delete(ptr) @classmethod - def _from_ptr(cls, ptr: "ctypes._Pointer") -> 'WasmtimeError': + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_error_t]") -> 'WasmtimeError': from . import _ffi as ffi if not isinstance(ptr, POINTER(ffi.wasmtime_error_t)): raise TypeError("wrong pointer type") diff --git a/wasmtime/_exportable.py b/wasmtime/_exportable.py index 28e75431..b6854d06 100644 --- a/wasmtime/_exportable.py +++ b/wasmtime/_exportable.py @@ -6,7 +6,5 @@ from ._memory import Memory from ._sharedmemory import SharedMemory from ._table import Table - from ._module import Module - from ._instance import Instance -AsExtern = typing.Union["Func", "Table", "Memory", "SharedMemory", "Global", "Instance", "Module"] +AsExtern = typing.Union["Func", "Table", "Memory", "SharedMemory", "Global"] diff --git a/wasmtime/_extern.py b/wasmtime/_extern.py index 2b8a18ba..16f4d362 100644 --- a/wasmtime/_extern.py +++ b/wasmtime/_extern.py @@ -5,7 +5,7 @@ def wrap_extern(ptr: ffi.wasmtime_extern_t) -> AsExtern: - from wasmtime import Func, Table, Global, Memory, SharedMemory, Module, Instance + from wasmtime import Func, Table, Global, Memory, SharedMemory if ptr.kind == ffi.WASMTIME_EXTERN_FUNC.value: return Func._from_raw(ptr.of.func) @@ -17,15 +17,11 @@ def wrap_extern(ptr: ffi.wasmtime_extern_t) -> AsExtern: return Memory._from_raw(ptr.of.memory) if ptr.kind == ffi.WASMTIME_EXTERN_SHAREDMEMORY.value: return SharedMemory._from_ptr(ptr.of.sharedmemory) - if ptr.kind == ffi.WASMTIME_EXTERN_INSTANCE.value: - return Instance._from_raw(ptr.of.instance) - if ptr.kind == ffi.WASMTIME_EXTERN_MODULE.value: - return Module._from_ptr(ptr.of.module) raise WasmtimeError("unknown extern") def get_extern_ptr(item: AsExtern) -> ffi.wasmtime_extern_t: - from wasmtime import Func, Table, Global, Memory, SharedMemory, Module, Instance + from wasmtime import Func, Table, Global, Memory, SharedMemory if isinstance(item, Func): return item._as_extern() @@ -37,12 +33,8 @@ def get_extern_ptr(item: AsExtern) -> ffi.wasmtime_extern_t: return item._as_extern() elif isinstance(item, Table): return item._as_extern() - elif isinstance(item, Module): - return item._as_extern() - elif isinstance(item, Instance): - return item._as_extern() else: - raise TypeError("expected a Func, Global, Memory, Table, Module, or Instance") + raise TypeError("expected a Func, Global, Memory, or Table") class Extern(Managed["ctypes._Pointer[ffi.wasm_extern_t]"]): diff --git a/wasmtime/_ffi.py b/wasmtime/_ffi.py index b47894fb..7d05af3d 100644 --- a/wasmtime/_ffi.py +++ b/wasmtime/_ffi.py @@ -60,11 +60,66 @@ WASMTIME_EXTERN_TABLE = c_uint8(2) WASMTIME_EXTERN_MEMORY = c_uint8(3) WASMTIME_EXTERN_SHAREDMEMORY = c_uint8(4) -WASMTIME_EXTERN_INSTANCE = c_uint8(4) -WASMTIME_EXTERN_MODULE = c_uint8(5) WASMTIME_FUNCREF_NULL = (1 << 64) - 1 +WASMTIME_COMPONENT_ITEM_COMPONENT = c_uint8(0) +WASMTIME_COMPONENT_ITEM_COMPONENT_INSTANCE = c_uint8(1) +WASMTIME_COMPONENT_ITEM_MODULE = c_uint8(2) +WASMTIME_COMPONENT_ITEM_COMPONENT_FUNC = c_uint8(3) +WASMTIME_COMPONENT_ITEM_RESOURCE = c_uint8(4) +WASMTIME_COMPONENT_ITEM_CORE_FUNC = c_uint8(5) +WASMTIME_COMPONENT_ITEM_TYPE = c_uint8(6) + +WASMTIME_COMPONENT_VALTYPE_BOOL = c_uint8(0) +WASMTIME_COMPONENT_VALTYPE_S8 = c_uint8(1) +WASMTIME_COMPONENT_VALTYPE_S16 = c_uint8(2) +WASMTIME_COMPONENT_VALTYPE_S32 = c_uint8(3) +WASMTIME_COMPONENT_VALTYPE_S64 = c_uint8(4) +WASMTIME_COMPONENT_VALTYPE_U8 = c_uint8(5) +WASMTIME_COMPONENT_VALTYPE_U16 = c_uint8(6) +WASMTIME_COMPONENT_VALTYPE_U32 = c_uint8(7) +WASMTIME_COMPONENT_VALTYPE_U64 = c_uint8(8) +WASMTIME_COMPONENT_VALTYPE_F32 = c_uint8(9) +WASMTIME_COMPONENT_VALTYPE_F64 = c_uint8(10) +WASMTIME_COMPONENT_VALTYPE_CHAR = c_uint8(11) +WASMTIME_COMPONENT_VALTYPE_STRING = c_uint8(12) +WASMTIME_COMPONENT_VALTYPE_LIST = c_uint8(13) +WASMTIME_COMPONENT_VALTYPE_RECORD = c_uint8(14) +WASMTIME_COMPONENT_VALTYPE_TUPLE = c_uint8(15) +WASMTIME_COMPONENT_VALTYPE_VARIANT = c_uint8(16) +WASMTIME_COMPONENT_VALTYPE_ENUM = c_uint8(17) +WASMTIME_COMPONENT_VALTYPE_OPTION = c_uint8(18) +WASMTIME_COMPONENT_VALTYPE_RESULT = c_uint8(19) +WASMTIME_COMPONENT_VALTYPE_FLAGS = c_uint8(20) +WASMTIME_COMPONENT_VALTYPE_OWN = c_uint8(21) +WASMTIME_COMPONENT_VALTYPE_BORROW = c_uint8(22) +WASMTIME_COMPONENT_VALTYPE_FUTURE = c_uint8(23) +WASMTIME_COMPONENT_VALTYPE_STREAM = c_uint8(24) +WASMTIME_COMPONENT_VALTYPE_ERROR_CONTEXT = c_uint8(25) + +WASMTIME_COMPONENT_BOOL = c_uint8(0) +WASMTIME_COMPONENT_S8 = c_uint8(1) +WASMTIME_COMPONENT_U8 = c_uint8(2) +WASMTIME_COMPONENT_S16 = c_uint8(3) +WASMTIME_COMPONENT_U16 = c_uint8(4) +WASMTIME_COMPONENT_S32 = c_uint8(5) +WASMTIME_COMPONENT_U32 = c_uint8(6) +WASMTIME_COMPONENT_S64 = c_uint8(7) +WASMTIME_COMPONENT_U64 = c_uint8(8) +WASMTIME_COMPONENT_F32 = c_uint8(9) +WASMTIME_COMPONENT_F64 = c_uint8(10) +WASMTIME_COMPONENT_CHAR = c_uint8(11) +WASMTIME_COMPONENT_STRING = c_uint8(12) +WASMTIME_COMPONENT_LIST = c_uint8(13) +WASMTIME_COMPONENT_RECORD = c_uint8(14) +WASMTIME_COMPONENT_TUPLE = c_uint8(15) +WASMTIME_COMPONENT_VARIANT = c_uint8(16) +WASMTIME_COMPONENT_ENUM = c_uint8(17) +WASMTIME_COMPONENT_OPTION = c_uint8(18) +WASMTIME_COMPONENT_RESULT = c_uint8(19) +WASMTIME_COMPONENT_FLAGS = c_uint8(20) +WASMTIME_COMPONENT_RESOURCE = c_uint8(21) class wasm_ref_t(Structure): pass @@ -100,7 +155,6 @@ def to_bytes(vec: wasm_byte_vec_t) -> bytearray: ty = c_uint8 * vec.size return bytearray(ty.from_address(addressof(vec.data.contents))) - def to_str(vec: wasm_byte_vec_t) -> str: return to_bytes(vec).decode("utf-8") @@ -109,13 +163,52 @@ def to_str_raw(ptr: "ctypes._Pointer", size: int) -> str: return string_at(ptr, size).decode("utf-8") -def str_to_name(s: str, trailing_nul: bool = False) -> wasm_byte_vec_t: +def str_to_capi(s: str) -> wasm_byte_vec_t: if not isinstance(s, str): raise TypeError("expected a string") - s_bytes = s.encode('utf8') - buf = cast(create_string_buffer(s_bytes), POINTER(c_uint8)) - if trailing_nul: - extra = 1 - else: - extra = 0 - return wasm_byte_vec_t(len(s_bytes) + extra, buf) + return bytes_to_capi(s.encode('utf8')) + +def bytes_to_capi(s: typing.Union[bytes, bytearray]) -> wasm_byte_vec_t: + if not isinstance(s, (bytes, bytearray)): + raise TypeError("expected bytes or bytearray") + vec = wasm_byte_vec_t() + wasm_byte_vec_new_uninitialized(byref(vec), len(s)) + buf = (c_uint8 * len(s)).from_buffer_copy(s) + ctypes.memmove(vec.data, buf, len(s)) + return vec + +def take_pointer(structure: ctypes._Pointer, field_name: str) -> ctypes._Pointer: + """ + Moral equivalent of `mem::replace(&mut structure.field_name, NULL)` + + Ctypes explicitly documents "Surprises" which includes, for example: + + import ctypes + + class A(ctypes.Structure): + _fields_ = [("x", ctypes.POINTER(ctypes.c_int))] + + x_p = ctypes.pointer(ctypes.c_int(3)) + a = A(x_p) + x = a.x + + print(x.contents) + a.x = None + print(x.contents) + + This program will segfault on the second access. It turns out that `x = a.x` + is still actually a pointer into the original structure, and `a.x` + overwrites that field so accessing `x` later accesses null memory. This + method is an attempt to work around this surprising behavior and actually + read the field from a structure and replace it with null. + + I'll be honest I just sat through a 3 hour flight, a 5 hour layover, a 9 + hour flight, 1 hour train ride, and I'm sitting in a hotel lobby for + another 5 hours. That's my state of mind writing this up, so please + draw conclusions about this method as appropriate. + """ + field = getattr(structure, field_name) + assert(isinstance(field, ctypes._Pointer)) + ret = ctypes.cast(ctypes.addressof(field.contents), ctypes.POINTER(field._type_)) + setattr(structure, field_name, None) + return ret diff --git a/wasmtime/_instance.py b/wasmtime/_instance.py index c82d7aa5..f1ed709b 100644 --- a/wasmtime/_instance.py +++ b/wasmtime/_instance.py @@ -61,10 +61,6 @@ def exports(self, store: Storelike) -> "InstanceExports": self._exports = InstanceExports(store, self) return self._exports - def _as_extern(self) -> ffi.wasmtime_extern_t: - union = ffi.wasmtime_extern_union(instance=self._instance) - return ffi.wasmtime_extern_t(ffi.WASMTIME_EXTERN_INSTANCE, union) - class InstanceExports(Mapping[str, AsExtern]): _extern_seq: Sequence[AsExtern] diff --git a/wasmtime/_linker.py b/wasmtime/_linker.py index 9ceacfd5..37551cc6 100644 --- a/wasmtime/_linker.py +++ b/wasmtime/_linker.py @@ -32,8 +32,6 @@ def allow_shadowing(self, allow: bool) -> None: Configures whether definitions are allowed to shadow one another within this linker """ - if not isinstance(allow, bool): - raise TypeError("expected a boolean") ffi.wasmtime_linker_allow_shadowing(self.ptr(), allow) def define(self, store: Storelike, module: str, name: str, item: AsExtern) -> None: diff --git a/wasmtime/_module.py b/wasmtime/_module.py index dbea124b..18013a6c 100644 --- a/wasmtime/_module.py +++ b/wasmtime/_module.py @@ -1,4 +1,5 @@ from . import _ffi as ffi +from ._wat2wasm import _to_wasm from ctypes import * import ctypes from wasmtime import Engine, wat2wasm, ImportType, ExportType, WasmtimeError, Managed @@ -20,21 +21,10 @@ def from_file(cls, engine: Engine, path: typing.Union[str, bytes, PathLike]) -> return cls(engine, contents) def __init__(self, engine: Engine, wasm: typing.Union[str, bytes]): - if not isinstance(engine, Engine): raise TypeError("expected an Engine") - # If this looks like a string, parse it as the text format. Note that - # in python 2 strings and bytes are basically the same, so we skip this - # if the first byte in the string is 0, meaning this is actually a wasm - # module. - if isinstance(wasm, str) and len(wasm) > 0 and ord(wasm[0]) != 0: - wasm = wat2wasm(wasm) - if isinstance(wasm, bytes) and len(wasm) > 0 and wasm[0] != 0: - wasm = wat2wasm(wasm) - - if not isinstance(wasm, (bytes, bytearray)): - raise TypeError("expected wasm bytes") + wasm = _to_wasm(wasm) # TODO: can the copy be avoided here? I can't for the life of me # figure this out. @@ -81,9 +71,7 @@ def deserialize(cls, engine: Engine, encoded: typing.Union[bytes, bytearray]) -> byref(ptr)) if error: raise WasmtimeError._from_ptr(error) - ret: "Module" = cls.__new__(cls) - ret._set_ptr(ptr) - return ret + return cls._from_ptr(ptr) @classmethod def deserialize_file(cls, engine: Engine, path: str) -> 'Module': @@ -102,9 +90,7 @@ def deserialize_file(cls, engine: Engine, path: str) -> 'Module': byref(ptr)) if error: raise WasmtimeError._from_ptr(error) - ret: "Module" = cls.__new__(cls) - ret._set_ptr(ptr) - return ret + return cls._from_ptr(ptr) @classmethod def validate(cls, engine: Engine, wasm: typing.Union[bytes, bytearray]) -> None: @@ -126,15 +112,6 @@ def validate(cls, engine: Engine, wasm: typing.Union[bytes, bytearray]) -> None: if error: raise WasmtimeError._from_ptr(error) -# @property -# def type(self) -> ModuleType: -# """ -# Gets the type of this module as a `ModuleType` -# """ - -# ptr = ffi.wasmtime_module_type(self.ptr()) -# return ModuleType._from_ptr(ptr, None) - @property def imports(self) -> typing.List[ImportType]: """ @@ -177,10 +154,6 @@ def serialize(self) -> bytearray: ffi.wasm_byte_vec_delete(byref(raw)) return ret - def _as_extern(self) -> ffi.wasmtime_extern_t: - union = ffi.wasmtime_extern_union(module=self.ptr()) - return ffi.wasmtime_extern_t(ffi.WASMTIME_EXTERN_MODULE, union) - class ImportTypeList: def __init__(self) -> None: diff --git a/wasmtime/_store.py b/wasmtime/_store.py index fbd37966..87da563b 100644 --- a/wasmtime/_store.py +++ b/wasmtime/_store.py @@ -137,8 +137,23 @@ def set_limits(self, ffi.wasmtime_store_limiter(self.ptr(), memory_size, table_elements, instances, tables, memories) +class StoreContext: + __ptr: typing.Optional["ctypes._Pointer[ffi.wasmtime_context_t]"] + + def __init__(self, ptr: "ctypes._Pointer[ffi.wasmtime_context_t]"): + self.__ptr = ptr + + def _context(self) -> "ctypes._Pointer[ffi.wasmtime_context_t]": + if self.__ptr is None: + raise ValueError("caller is no longer valid") + return self.__ptr + + def _invalidate(self) -> None: + self.__ptr = None + + if typing.TYPE_CHECKING: from ._func import Caller -Storelike = typing.Union[Store, "Caller"] +Storelike = typing.Union[Store, "Caller", StoreContext] diff --git a/wasmtime/_types.py b/wasmtime/_types.py index 9a43a4da..ed7ea8f6 100644 --- a/wasmtime/_types.py +++ b/wasmtime/_types.py @@ -373,7 +373,7 @@ class ImportType(Managed["ctypes._Pointer[ffi.wasm_importtype_t]"]): _owner: Optional[Any] @classmethod - def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]", owner: Optional[Any]) -> "ImportType": + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasm_importtype_t]", owner: Optional[Any] = None) -> "ImportType": if not isinstance(ptr, POINTER(ffi.wasm_importtype_t)): raise TypeError("wrong pointer type") ty: "ImportType" = cls.__new__(cls) @@ -420,7 +420,7 @@ class ExportType(Managed["ctypes._Pointer[ffi.wasm_exporttype_t]"]): _owner: Optional[Any] @classmethod - def _from_ptr(cls, ptr: 'ctypes._Pointer[ffi.wasm_exporttype_t]', owner: Optional[Any]) -> "ExportType": + def _from_ptr(cls, ptr: 'ctypes._Pointer[ffi.wasm_exporttype_t]', owner: Optional[Any] = None) -> "ExportType": if not isinstance(ptr, POINTER(ffi.wasm_exporttype_t)): raise TypeError("wrong pointer type") ty: "ExportType" = cls.__new__(cls) diff --git a/wasmtime/_wat2wasm.py b/wasmtime/_wat2wasm.py index 93a3f14a..5733fa6f 100644 --- a/wasmtime/_wat2wasm.py +++ b/wasmtime/_wat2wasm.py @@ -33,3 +33,17 @@ def wat2wasm(wat: typing.Union[str, bytes]) -> bytearray: ret = ffi.to_bytes(wasm) ffi.wasm_byte_vec_delete(byref(wasm)) return ret + +def _to_wasm(wasm: typing.Union[str, bytes, bytearray]) -> typing.Union[bytes, bytearray]: + # If this looks like a string, parse it as the text format. Note that + # in python 2 strings and bytes are basically the same, so we skip this + # if the first byte in the string is 0, meaning this is actually a wasm + # module. + if isinstance(wasm, str) and len(wasm) > 0 and ord(wasm[0]) != 0: + wasm = wat2wasm(wasm) + if isinstance(wasm, bytes) and len(wasm) > 0 and wasm[0] != 0: + wasm = wat2wasm(wasm) + + if not isinstance(wasm, (bytes, bytearray)): + raise TypeError("expected wasm bytes") + return wasm diff --git a/wasmtime/component/__init__.py b/wasmtime/component/__init__.py new file mode 100644 index 00000000..ba633508 --- /dev/null +++ b/wasmtime/component/__init__.py @@ -0,0 +1,55 @@ +from ._component import Component, ExportIndex +from ._linker import Linker, LinkerInstance +from ._instance import Instance +from ._func import Func +from ._types import ComponentType, ModuleType, ComponentItem, ComponentInstanceType, FuncType, ResourceType +from ._types import ValType, Bool, U8, U16, U32, U64, S8, S16, S32, S64, F32, F64, Char, String, ErrorContext +from ._types import ListType, RecordType, TupleType, VariantType, EnumType, OptionType, ResultType, FlagsType +from ._types import StreamType, FutureType, OwnType, BorrowType, Variant, Record +from ._resources import ResourceAny, ResourceHost + +__all__ = [ + 'Component', + 'ExportIndex', + 'Linker', + 'LinkerInstance', + 'Instance', + 'Func', + 'ResourceType', + 'ResourceAny', + 'ResourceHost', + 'ComponentType', + 'ModuleType', + 'ComponentItem', + 'ComponentInstanceType', + 'FuncType', + 'ValType', + 'Bool', + 'U8', + 'U16', + 'U32', + 'U64', + 'S8', + 'S16', + 'S32', + 'S64', + 'F32', + 'F64', + 'Char', + 'String', + 'ErrorContext', + 'ListType', + 'RecordType', + 'TupleType', + 'VariantType', + 'EnumType', + 'OptionType', + 'ResultType', + 'FlagsType', + 'StreamType', + 'FutureType', + 'OwnType', + 'BorrowType', + 'Variant', + 'Record', +] diff --git a/wasmtime/component/_component.py b/wasmtime/component/_component.py new file mode 100644 index 00000000..f21006bd --- /dev/null +++ b/wasmtime/component/_component.py @@ -0,0 +1,155 @@ +from .. import _ffi as ffi +from .._wat2wasm import _to_wasm +from ._types import ComponentType +from ctypes import * +import ctypes +from wasmtime import Engine, wat2wasm, WasmtimeError, Managed, Module +import typing +from os import PathLike + + +class ExportIndex(Managed["ctypes._Pointer[ffi.wasmtime_component_export_index_t]"]): + + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct an `ExportIndex`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_export_index_t]") -> None: + ffi.wasmtime_component_export_index_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_export_index_t]") -> "ExportIndex": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_export_index_t)): + raise TypeError("wrong pointer type") + ty: "ExportIndex" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + +class Component(Managed["ctypes._Pointer[ffi.wasmtime_component_t]"]): + + @classmethod + def from_file(cls, engine: Engine, path: typing.Union[str, bytes, PathLike]) -> "Component": + """ + Compiles and creates a new `Component` by reading the file at `path` and + then delegating to the `Component` constructor. + """ + + with open(path, "rb") as f: + contents = f.read() + return cls(engine, contents) + + def __init__(self, engine: Engine, wasm: typing.Union[str, bytes, bytearray]): + if not isinstance(engine, Engine): + raise TypeError("expected an Engine") + + wasm = _to_wasm(wasm) + + # TODO: can the copy be avoided here? I can't for the life of me + # figure this out. + binary = (c_uint8 * len(wasm)).from_buffer_copy(wasm) + ptr = POINTER(ffi.wasmtime_component_t)() + error = ffi.wasmtime_component_new(engine.ptr(), binary, len(wasm), byref(ptr)) + if error: + raise WasmtimeError._from_ptr(error) + self._set_ptr(ptr) + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_t]") -> None: + ffi.wasmtime_component_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_t]") -> "Component": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_t)): + raise TypeError("wrong pointer type") + ty: "Component" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @classmethod + def deserialize(cls, engine: Engine, encoded: typing.Union[bytes, bytearray]) -> 'Component': + """ + Deserializes bytes previously created by `Component.serialize`. + + This constructor for `Component` will deserialize bytes previously created + by a serialized component. This will only succeed if the bytes were + previously created by the same version of `wasmtime` as well as the + same configuration within `Engine`. + """ + + if not isinstance(encoded, (bytes, bytearray)): + raise TypeError("expected bytes") + + ptr = POINTER(ffi.wasmtime_component_t)() + + # TODO: can the copy be avoided here? I can't for the life of me + # figure this out. + error = ffi.wasmtime_component_deserialize( + engine.ptr(), + (c_uint8 * len(encoded)).from_buffer_copy(encoded), + len(encoded), + byref(ptr)) + if error: + raise WasmtimeError._from_ptr(error) + return cls._from_ptr(ptr) + + @classmethod + def deserialize_file(cls, engine: Engine, path: str) -> 'Component': + """ + Deserializes bytes previously created by `Component.serialize` that are + stored in a file on the filesystem. + + Otherwise this function is the same as `Component.deserialize`. + """ + + ptr = POINTER(ffi.wasmtime_component_t)() + path_bytes = path.encode('utf-8') + error = ffi.wasmtime_component_deserialize_file( + engine.ptr(), + path_bytes, + byref(ptr)) + if error: + raise WasmtimeError._from_ptr(error) + return cls._from_ptr(ptr) + + def serialize(self) -> bytearray: + """ + Serializes this component to a binary representation. + + This method will serialize this component to an in-memory byte array + which can be cached and later passed to `Component.deserialize` to + recreate this component. + """ + raw = ffi.wasm_byte_vec_t() + err = ffi.wasmtime_component_serialize(self.ptr(), byref(raw)) + if err: + raise WasmtimeError._from_ptr(err) + ret = ffi.to_bytes(raw) + ffi.wasm_byte_vec_delete(byref(raw)) + return ret + + def get_export_index(self, name: str, instance : typing.Optional[ExportIndex] = None) -> typing.Optional[ExportIndex]: + """ + Gets an `ExportIndex` from this component pointing to a specific item + in this component. + + The returned `ExportIndex` can later be used to lookup exports on an + instance or it can be used to lookup further indexes if it points to an + instance for example. + """ + name_bytes = name.encode('utf-8') + name_buf = create_string_buffer(name_bytes) + ret = ffi.wasmtime_component_get_export_index( + self.ptr(), + instance.ptr() if instance is not None else None, + name_buf, + len(name_bytes)) + if not ret: + return None + return ExportIndex._from_ptr(ret) + + @property + def type(self) -> ComponentType: + """ + Returns the `ComponentType` corresponding to this component. + """ + ptr = ffi.wasmtime_component_type(self.ptr()) + return ComponentType._from_ptr(ptr) diff --git a/wasmtime/component/_enter.py b/wasmtime/component/_enter.py new file mode 100644 index 00000000..b7492cee --- /dev/null +++ b/wasmtime/component/_enter.py @@ -0,0 +1,43 @@ +from contextlib import contextmanager +import ctypes +from .. import _ffi as ffi, StoreContext, WasmtimeError +from typing import Optional, Callable + + +LAST_EXCEPTION: Optional[Exception] = None + + +def catch_exceptions(store_raw: 'ctypes._Pointer[ffi.wasmtime_context_t]', func: Callable[[StoreContext], None]) -> ctypes.c_size_t: + store = StoreContext(store_raw) + exception = None + try: + func(store) + except WasmtimeError as e: + exception = e + except Exception as e: + global LAST_EXCEPTION + LAST_EXCEPTION = e + exception = WasmtimeError("python exception") + finally: + store._invalidate() + + if exception: + return ctypes.cast(exception._consume(), ctypes.c_void_p).value # type: ignore + return 0 # type: ignore + + +def enter_wasm(func: Callable[[], 'ctypes._Pointer[ffi.wasmtime_error_t]']) -> None: + ptr = func() + if ptr: + error = WasmtimeError._from_ptr(ptr) + maybe_raise_last_exn() + raise error + + +def maybe_raise_last_exn() -> None: + global LAST_EXCEPTION + if LAST_EXCEPTION is None: + return + exn = LAST_EXCEPTION + LAST_EXCEPTION = None + raise exn diff --git a/wasmtime/component/_func.py b/wasmtime/component/_func.py new file mode 100644 index 00000000..30786a0a --- /dev/null +++ b/wasmtime/component/_func.py @@ -0,0 +1,74 @@ +from .. import _ffi as ffi, WasmtimeError, Storelike +from ctypes import byref, pointer +import ctypes +from ._types import ValType, valtype_from_ptr, FuncType +from typing import List, Tuple, Optional, Any +from ._enter import enter_wasm + + +class Func: + _func: ffi.wasmtime_component_func_t + + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `Func`") + + @classmethod + def _from_raw(cls, func: ffi.wasmtime_component_func_t) -> "Func": + ty: "Func" = cls.__new__(cls) + ty._func = func + return ty + + def __call__(self, store: Storelike, *params: Any) -> Any: + fty = self.type(store) + param_tys = fty.params + result_ty = fty.result + if len(params) != len(param_tys): + raise TypeError("wrong number of parameters provided: given %s, expected %s" % + (len(params), len(param_tys))) + param_capi = (ffi.wasmtime_component_val_t * len(params))() + n = 0 + try: + for (_name, ty), val in zip(param_tys, params): + ty.convert_to_c(store, val, pointer(param_capi[n])) + n += 1 + result_space = None + result_capi = None + result_len = 0 + if result_ty is not None: + result_space = ffi.wasmtime_component_val_t() + result_capi = byref(result_space) + result_len = 1 + + def run() -> 'ctypes._Pointer[ffi.wasmtime_error_t]': + return ffi.wasmtime_component_func_call(byref(self._func), + store._context(), + param_capi, + n, + result_capi, + result_len) + enter_wasm(run) + + if result_space is None: + return None + assert(result_ty is not None) + return result_ty.convert_from_c(result_space) + + finally: + for i in range(n): + ffi.wasmtime_component_val_delete(byref(param_capi[i])) + + + def post_return(self, store: Storelike) -> None: + """ + Performs any necessary post-return operations for this function. + """ + def run() -> 'ctypes._Pointer[ffi.wasmtime_error_t]': + return ffi.wasmtime_component_func_post_return(byref(self._func), store._context()) + enter_wasm(run) + + def type(self, store: Storelike) -> FuncType: + """ + Returns the type of this function. + """ + ptr = ffi.wasmtime_component_func_type(byref(self._func), store._context()) + return FuncType._from_ptr(ptr) diff --git a/wasmtime/component/_instance.py b/wasmtime/component/_instance.py new file mode 100644 index 00000000..b0a4f879 --- /dev/null +++ b/wasmtime/component/_instance.py @@ -0,0 +1,65 @@ +from .. import _ffi as ffi, WasmtimeError, Storelike +from ctypes import byref +from typing import Optional +from ._component import ExportIndex +from ._func import Func + + +class Instance: + _instance: ffi.wasmtime_component_instance_t + + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct an `Instance`") + + @classmethod + def _from_raw(cls, instance: ffi.wasmtime_component_instance_t) -> "Instance": + ty: "Instance" = cls.__new__(cls) + ty._instance = instance + return ty + + def get_export_index(self, store: Storelike, name: str, instance: Optional[ExportIndex] = None) -> Optional[ExportIndex]: + """ + Retrieves the export index for the export named `name` from this + component instance. + + If `instance` is provided then the export is looked up within that + nested instance. + + Returns `None` if no such export exists otherwise returns the export + index. + """ + name_bytes = name.encode('utf-8') + name_buf = ffi.create_string_buffer(name_bytes) + + ptr = ffi.wasmtime_component_instance_get_export_index( + byref(self._instance), + store._context(), + instance.ptr() if instance is not None else None, + name_buf, + len(name_bytes)) + if ptr: + return ExportIndex._from_ptr(ptr) + return None + + def get_func(self, store: Storelike, index: ExportIndex | str) -> Optional[Func]: + """ + Retrieves the function export for the given export index. + + Returns `None` if the export index does not correspond to a function + export and otherwise returns the function. + """ + if isinstance(index, str): + ei = self.get_export_index(store, index) + if ei is None: + return None + index = ei + + raw = ffi.wasmtime_component_func_t() + found = ffi.wasmtime_component_instance_get_func( + byref(self._instance), + store._context(), + index.ptr(), + byref(raw)) + if found: + return Func._from_raw(raw) + return None diff --git a/wasmtime/component/_linker.py b/wasmtime/component/_linker.py new file mode 100644 index 00000000..b95804e1 --- /dev/null +++ b/wasmtime/component/_linker.py @@ -0,0 +1,246 @@ +import ctypes +from ctypes import POINTER, byref, create_string_buffer, CFUNCTYPE, c_void_p +from .. import Managed, Engine, WasmtimeError, Module, _ffi as ffi, Storelike, StoreContext +from .._config import setter_property +from ._instance import Instance +from ._component import Component +from ._resource_type import ResourceType +from typing import Union, Tuple, Callable, Optional, List, Any, Concatenate +from .._func import Slab +from ._enter import catch_exceptions +from ._types import ValType, FuncType + +LinkerInstanceParent = Union['Linker', 'LinkerInstance'] + +ResourceDtor = Callable[[StoreContext, int], None] +RESOURCE_DTORS: Slab[ResourceDtor] = Slab() + +UserFunc = Callable[Concatenate[StoreContext, ...], Optional[Any]] +FUNCTIONS: Slab[UserFunc] = Slab() + + +class Linker(Managed["ctypes._Pointer[ffi.wasmtime_component_linker_t]"]): + engine: Engine + locked: bool + + def __init__(self, engine: Engine): + """ + Creates a new linker ready to instantiate modules within the store + provided. + """ + self._set_ptr(ffi.wasmtime_component_linker_new(engine.ptr())) + self.engine = engine + self.locked = False + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_linker_t]") -> None: + self._assert_not_locked() + ffi.wasmtime_component_linker_delete(ptr) + + @setter_property + def allow_shadowing(self, allow: bool) -> None: + """ + Configures whether definitions are allowed to shadow one another within + this linker + """ + self._assert_not_locked() + ffi.wasmtime_component_linker_allow_shadowing(self.ptr(), allow) + + def _assert_not_locked(self) -> None: + if self.locked: + raise WasmtimeError("cannot use linker while it's in use by other instances") + + def root(self) -> "LinkerInstance": + """ + Returns the root instance used to defined new items in this linker. + + While this root instance is alive this linker cannot be used for any + other operations. Until the returned object is destroyed this linker is + considered "locked". + + It's recommended to bind the return value in a `with` block to + automatically dispose of it when it's done. + """ + self._assert_not_locked() + ptr = ffi.wasmtime_component_linker_root(self.ptr()) + return LinkerInstance._from_ptr(ptr, self) + + def add_wasip2(self) -> None: + """ + Adds the WASIp2 API definitions, from Wasmtime, in this linker. + """ + self._assert_not_locked() + err = ffi.wasmtime_component_linker_add_wasip2(self.ptr()) + if err: + raise WasmtimeError._from_ptr(err) + + def instantiate(self, store: Storelike, component: Component) -> Instance: + """ + Instantiates the given component using this linker within the provided + store. + + Returns the instantiated `Instance` on success. + """ + self._assert_not_locked() + instance = ffi.wasmtime_component_instance_t() + err = ffi.wasmtime_component_linker_instantiate( + self.ptr(), + store._context(), + component.ptr(), + byref(instance)) + if err: + raise WasmtimeError._from_ptr(err) + return Instance._from_raw(instance) + + +class LinkerInstance(Managed["ctypes._Pointer[ffi.wasmtime_component_linker_instance_t]"]): + parent: Union[LinkerInstanceParent, None] + locked: bool + + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `LinkerInstance`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_linker_instance_t]") -> None: + self._assert_not_locked() + ffi.wasmtime_component_linker_instance_delete(ptr) + assert(self.parent is not None) + assert(self.parent.locked) + self.parent.locked = False + self.parent = None + + def _assert_not_locked(self) -> None: + if self.locked: + raise WasmtimeError("cannot use linker instance while it's in use by other instances") + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_linker_instance_t]", parent: LinkerInstanceParent) -> "LinkerInstance": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_linker_instance_t)): + raise TypeError("wrong pointer type") + ty: "LinkerInstance" = cls.__new__(cls) + ty._set_ptr(ptr) + ty.parent = parent + ty.locked = False + assert(not parent.locked) + parent.locked = True + return ty + + + def add_instance(self, name: str) -> "LinkerInstance": + """ + Adds a new instance to this linker instance under the given name. + + Returns a new `LinkerInstance` which can be used to define further + items. + + While the returned instance is alive this linker instance cannot be + used for other operations. Until the returned object is destroyed this + linker instance is considered "locked". + + It's recommended to bind the return value in a `with` block to + automatically dispose of it when it's done. + """ + self._assert_not_locked() + name_bytes = name.encode('utf-8') + name_buf = create_string_buffer(name_bytes) + ptr = POINTER(ffi.wasmtime_component_linker_instance_t)() + err = ffi.wasmtime_component_linker_instance_add_instance(self.ptr(), + name_buf, + len(name_bytes), + byref(ptr)) + if err: + raise WasmtimeError._from_ptr(err) + return LinkerInstance._from_ptr(ptr, self) + + def add_module(self, name: str, module: Module) -> None: + """ + Adds a new module to this linker instance under the given name. + """ + self._assert_not_locked() + name_bytes = name.encode('utf-8') + name_buf = create_string_buffer(name_bytes) + err = ffi.wasmtime_component_linker_instance_add_module(self.ptr(), + name_buf, + len(name_bytes), + module.ptr()) + if err: + raise WasmtimeError._from_ptr(err) + + def add_resource(self, name: str, ty: ResourceType, dtor: ResourceDtor) -> None: + """ + Defines a the resource type `ty` under `name` + + When a value of this resource is destroyed then `dtor` is invoked. + """ + self._assert_not_locked() + name_bytes = name.encode('utf-8') + name_buf = create_string_buffer(name_bytes) + idx = RESOURCE_DTORS.allocate(dtor) + err = ffi.wasmtime_component_linker_instance_add_resource(self.ptr(), + name_buf, + len(name_bytes), + ty.ptr(), + resource_dtor_impl, + idx, + resource_dtor_finalize) + if err: + raise WasmtimeError._from_ptr(err) + + def add_func(self, name: str, func: UserFunc) -> None: + self._assert_not_locked() + name_bytes = name.encode('utf-8') + name_buf = create_string_buffer(name_bytes) + idx = FUNCTIONS.allocate(func) + err = ffi.wasmtime_component_linker_instance_add_func(self.ptr(), + name_buf, + len(name_bytes), + func_impl, + idx, + func_finalize) + if err: + raise WasmtimeError._from_ptr(err) + + +@ffi.wasmtime_component_resource_destructor_t +def resource_dtor_impl(idx, context, rep): # type: ignore + def run(store: StoreContext) -> None: + return RESOURCE_DTORS.get(idx or 0)(store, rep) + return catch_exceptions(context, run) + + +@CFUNCTYPE(None, c_void_p) +def resource_dtor_finalize(idx): # type: ignore + if RESOURCE_DTORS: + RESOURCE_DTORS.deallocate(idx or 0) + return None + + +@ffi.wasmtime_component_func_callback_t +def func_impl(idx, context, ty_raw, args, nargs, results, nresults): # type: ignore + def run(store: StoreContext) -> None: + with FuncType._from_ptr(ty_raw, owner=store) as fty: + func = FUNCTIONS.get(idx or 0) + param_tys = fty.params + result_ty = fty.result + assert(len(param_tys) == nargs) + if result_ty is None: + assert(nresults == 0) + else: + assert(nresults == 1) + + pyargs = [] + for (_, ty), i in zip(param_tys, range(nargs)): + val = ty.convert_from_c(args[i]) + pyargs.append(val) + result = func(store, *pyargs) + + if result_ty is None: + assert(result is None) + else: + result_ty.convert_to_c(store, result, results) + return catch_exceptions(context, run) + + +@CFUNCTYPE(None, c_void_p) +def func_finalize(idx): # type: ignore + if FUNCTIONS: + FUNCTIONS.deallocate(idx or 0) + return None diff --git a/wasmtime/component/_resource_type.py b/wasmtime/component/_resource_type.py new file mode 100644 index 00000000..b2183428 --- /dev/null +++ b/wasmtime/component/_resource_type.py @@ -0,0 +1,34 @@ +from .. import _ffi as ffi, WasmtimeError +from ctypes import POINTER +import ctypes +from wasmtime import Managed + + +class ResourceType(Managed["ctypes._Pointer[ffi.wasmtime_component_resource_type_t]"]): + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `ResourceType`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_resource_type_t]") -> None: + ffi.wasmtime_component_resource_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_resource_type_t]") -> "ResourceType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_resource_type_t)): + raise TypeError("wrong pointer type") + ty: "ResourceType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @classmethod + def host(cls, val: int) -> "ResourceType": + """ + Creates a new `ResourceType` representing a host-defined resource + identified by the integer identifier `val` given. + """ + ptr = ffi.wasmtime_component_resource_type_new_host(val) + return cls._from_ptr(ptr) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ResourceType): + return False + return ffi.wasmtime_component_resource_type_equal(self.ptr(), other.ptr()) diff --git a/wasmtime/component/_resources.py b/wasmtime/component/_resources.py new file mode 100644 index 00000000..d8c1bd5c --- /dev/null +++ b/wasmtime/component/_resources.py @@ -0,0 +1,120 @@ +from .. import _ffi as ffi, WasmtimeError, Managed, Storelike, WasmtimeError +from ctypes import POINTER, byref +import ctypes +from ._resource_type import ResourceType +from ._enter import enter_wasm + + +class ResourceAny(Managed["ctypes._Pointer[ffi.wasmtime_component_resource_any_t]"]): + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `ResourceAny`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_resource_any_t]") -> None: + ffi.wasmtime_component_resource_any_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_resource_any_t]") -> "ResourceAny": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_resource_any_t)): + raise TypeError("wrong pointer type") + ty: "ResourceAny" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def type(self) -> ResourceType: + """ + Returns the `ResourceType` of this `ResourceAny`. + """ + ptr = ffi.wasmtime_component_resource_any_type(self.ptr()) + return ResourceType._from_ptr(ptr) + + @property + def owned(self) -> bool: + """ + Returns whether this `ResourceAny` is an `own` resource or a `borrow` + resource. + """ + return ffi.wasmtime_component_resource_any_owned(self.ptr()) + + def drop(self, store: Storelike) -> None: + """ + Runs the WebAssembly-defined destructor, if any, for this resource. + + This is required to be called to clean up state information in the + store about this resource. This may execute WebAssembly code if the + resource is a guest-owned resource with a defined destructor. + """ + def run() -> 'ctypes._Pointer[ffi.wasmtime_error_t]': + return ffi.wasmtime_component_resource_any_drop(store._context(), self.ptr()) + enter_wasm(run) + + def to_host(self, store: Storelike) -> "ResourceHost": + """ + Attempts to downcast this `ResourceAny` to a `ResourceHost`. + + This will raise a `WasmtimeError` if this `ResourceAny` is not + actually a host-defined resource. + """ + ptr = POINTER(ffi.wasmtime_component_resource_host_t)() + error = ffi.wasmtime_component_resource_any_to_host(store._context(), self.ptr(), byref(ptr)) + if error: + raise WasmtimeError._from_ptr(error) + return ResourceHost._from_ptr(ptr) + + +class ResourceHost(Managed["ctypes._Pointer[ffi.wasmtime_component_resource_host_t]"]): + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `ResourceHost`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_resource_host_t]") -> None: + ffi.wasmtime_component_resource_host_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_resource_host_t]") -> "ResourceHost": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_resource_host_t)): + raise TypeError("wrong pointer type") + ty: "ResourceHost" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @classmethod + def own(cls, rep: int, ty: int) -> "ResourceHost": + ptr = ffi.wasmtime_component_resource_host_new(True, rep, ty) + return cls._from_ptr(ptr) + + @classmethod + def borrow(cls, rep: int, ty: int) -> "ResourceHost": + ptr = ffi.wasmtime_component_resource_host_new(False, rep, ty) + return cls._from_ptr(ptr) + + @property + def rep(self) -> int: + """ + Returns the integer representation associated with this host resource. + """ + return ffi.wasmtime_component_resource_host_rep(self.ptr()) + + @property + def type(self) -> int: + """ + Returns the integer type identifier associated with this host resource. + """ + return ffi.wasmtime_component_resource_host_type(self.ptr()) + + @property + def owned(self) -> bool: + """ + Returns whether this `ResourceHost` is an `own` resource or a `borrow` + resource. + """ + return ffi.wasmtime_component_resource_host_owned(self.ptr()) + + def to_any(self, store: Storelike) -> ResourceAny: + """ + Upcasts this `ResourceHost` to a `ResourceAny`. + """ + ptr = POINTER(ffi.wasmtime_component_resource_any_t)() + error = ffi.wasmtime_component_resource_host_to_any(store._context(), self.ptr(), byref(ptr)) + if error: + raise WasmtimeError._from_ptr(error) + return ResourceAny._from_ptr(ptr) diff --git a/wasmtime/component/_types.py b/wasmtime/component/_types.py new file mode 100644 index 00000000..d086f660 --- /dev/null +++ b/wasmtime/component/_types.py @@ -0,0 +1,1268 @@ +from abc import abstractmethod +from .. import _ffi as ffi, ImportType, ExportType, WasmtimeError, Storelike +from ._resources import ResourceAny, ResourceHost +from ._resource_type import ResourceType +from dataclasses import dataclass +import ctypes +from ctypes import byref, POINTER +from typing import Any, Optional, Dict, List, Union, Tuple, Set +from wasmtime import Managed, Engine + + +class ComponentType(Managed["ctypes._Pointer[ffi.wasmtime_component_type_t]"]): + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `ComponentType`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_type_t]") -> None: + ffi.wasmtime_component_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_type_t]") -> "ComponentType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_type_t)): + raise TypeError("wrong pointer type") + ty: "ComponentType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + def imports(self, engine: Engine) -> Dict[str, "ComponentItem"]: + """ + Returns a dictionary of the imports of this component type. + """ + n = ffi.wasmtime_component_type_import_count(self.ptr(), engine.ptr()) + items = {} + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + item = ffi.wasmtime_component_item_t() + found = ffi.wasmtime_component_type_import_nth(self.ptr(), + engine.ptr(), + i, + byref(name_ptr), + byref(name_len), + byref(item)) + assert(found) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + items[name] = component_item_from_ptr(item) + return items + + def exports(self, engine: Engine) -> Dict[str, "ComponentItem"]: + """ + Returns a dictionary of the exports of this component type. + """ + n = ffi.wasmtime_component_type_export_count(self.ptr(), engine.ptr()) + items = {} + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + item = ffi.wasmtime_component_item_t() + found = ffi.wasmtime_component_type_export_nth(self.ptr(), + engine.ptr(), + i, + byref(name_ptr), + byref(name_len), + byref(item)) + assert(found) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + items[name] = component_item_from_ptr(item) + return items + + +class ComponentInstanceType(Managed["ctypes._Pointer[ffi.wasmtime_component_instance_type_t]"]): + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `ComponentInstanceType`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_instance_type_t]") -> None: + ffi.wasmtime_component_instance_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_instance_type_t]") -> "ComponentInstanceType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_instance_type_t)): + raise TypeError("wrong pointer type") + ty: "ComponentInstanceType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + def exports(self, engine: Engine) -> Dict[str, "ComponentItem"]: + """ + Returns a dictionary of the exports of this component instance type. + """ + n = ffi.wasmtime_component_instance_type_export_count(self.ptr(), engine.ptr()) + items = {} + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + item = ffi.wasmtime_component_item_t() + found = ffi.wasmtime_component_instance_type_export_nth(self.ptr(), + engine.ptr(), + i, + byref(name_ptr), + byref(name_len), + byref(item)) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + items[name] = component_item_from_ptr(item) + assert(found) + return items + + +class ModuleType(Managed["ctypes._Pointer[ffi.wasmtime_module_type_t]"]): + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `ModuleType`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_module_type_t]") -> None: + ffi.wasmtime_module_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_module_type_t]") -> "ModuleType": + if not isinstance(ptr, POINTER(ffi.wasmtime_module_type_t)): + raise TypeError("wrong pointer type") + ty: "ModuleType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + def imports(self, engine: Engine) -> List[ImportType]: + """ + Returns a list of the imports of this module type. + """ + n = ffi.wasmtime_module_type_import_count(self.ptr(), engine.ptr()) + items = [] + for i in range(n): + item = ffi.wasmtime_module_type_import_nth(self.ptr(), + engine.ptr(), + i) + items.append(ImportType._from_ptr(item)) + return items + + def exports(self, engine: Engine) -> List[ExportType]: + """ + Returns a list of the exports of this module type. + """ + n = ffi.wasmtime_module_type_export_count(self.ptr(), engine.ptr()) + items = [] + for i in range(n): + item = ffi.wasmtime_module_type_export_nth(self.ptr(), + engine.ptr(), + i) + items.append(ExportType._from_ptr(item)) + return items + + +class FuncType(Managed["ctypes._Pointer[ffi.wasmtime_component_func_type_t]"]): + _owner: Any + + def __init__(self) -> None: + raise WasmtimeError("Cannot directly construct a `FuncType`") + + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_func_type_t]") -> None: + if self._owner is None: + ffi.wasmtime_component_func_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_func_type_t]", owner: Any = None) -> "FuncType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_func_type_t)): + raise TypeError("wrong pointer type") + ty: "FuncType" = cls.__new__(cls) + ty._set_ptr(ptr) + ty._owner = owner + return ty + + @property + def params(self) -> List[Tuple[str, 'ValType']]: + """ + Returns the parameter types of this component function type. + """ + n = ffi.wasmtime_component_func_type_param_count(self.ptr()) + items = [] + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + valtype_ptr = ffi.wasmtime_component_valtype_t() + found = ffi.wasmtime_component_func_type_param_nth(self.ptr(), + i, + byref(name_ptr), + byref(name_len), + byref(valtype_ptr)) + assert(found) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + valtype = valtype_from_ptr(valtype_ptr) + items.append((name, valtype)) + return items + + @property + def result(self) -> Optional['ValType']: + """ + Returns the result type of this component function type, if any. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + has_result = ffi.wasmtime_component_func_type_result(self.ptr(), byref(valtype_ptr)) + if not has_result: + return None + return valtype_from_ptr(valtype_ptr) + + +class ValType: + @abstractmethod + def add_classes(self, s: Set[type]) -> None: + """ + Returns the python class that is created by `convert_from_c` and + accepted by `convert_to_c` + """ + pass + + @abstractmethod + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + """ + Converts `val` to this type and stores it in `ptr` + """ + pass + + @abstractmethod + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + """ + Converts `val` to Python + """ + pass + + +@dataclass +class Bool(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(bool) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, bool): + raise TypeError("expected bool for Bool type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_BOOL + ptr.contents.of.boolean = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_BOOL.value) + return bool(c.of.boolean) + + +@dataclass +class S8(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for S8 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_S8 + ptr.contents.of.s8 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_S8.value) + return int(c.of.s8) + + +@dataclass +class S16(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for S16 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_S16 + ptr.contents.of.s16 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_S16.value) + return int(c.of.s16) + + +@dataclass +class S32(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for S32 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_S32 + ptr.contents.of.s32 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_S32.value) + return int(c.of.s32) + + +@dataclass +class S64(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for S64 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_S64 + ptr.contents.of.s64 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_S64.value) + return int(c.of.s64) + + +@dataclass +class U8(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for U8 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_U8 + ptr.contents.of.u8 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_U8.value) + return int(c.of.u8) + + +@dataclass +class U16(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for U16 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_U16 + ptr.contents.of.u16 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_U16.value) + return int(c.of.u16) + + +@dataclass +class U32(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for U32 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_U32 + ptr.contents.of.u32 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_U32.value) + return int(c.of.u32) + + +@dataclass +class U64(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(int) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, int): + raise TypeError("expected int for U64 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_U64 + ptr.contents.of.u64 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_U64.value) + return int(c.of.u64) + + +@dataclass +class F32(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(float) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, float): + raise TypeError("expected float for F32 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_F32 + ptr.contents.of.f32 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_F32.value) + return float(c.of.f32) + + +@dataclass +class F64(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(float) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, float): + raise TypeError("expected float for F64 type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_F64 + ptr.contents.of.f64 = val + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_F64.value) + return float(c.of.f64) + + +@dataclass +class Char(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(str) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, str) or len(val) != 1: + raise TypeError("expected single-character string for Char type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_CHAR + ptr.contents.of.character = ord(val) + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_CHAR.value) + return chr(c.of.character) + + + +@dataclass +class String(ValType): + def add_classes(self, s: Set[type]) -> None: + s.add(str) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, str): + raise TypeError("expected string type") + ptr.contents.kind = ffi.WASMTIME_COMPONENT_STRING + ptr.contents.of.string = ffi.str_to_capi(val) + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_STRING.value) + ret = ffi.to_str(c.of.string) + ffi.wasm_byte_vec_delete(byref(c.of.string)) + return ret + + +@dataclass +class ErrorContext(ValType): + def add_classes(self, s: Set[type]) -> None: + raise NotImplementedError("ErrorContext conversion not implemented yet") + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + raise NotImplementedError("ErrorContext conversion not implemented yet") + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + raise NotImplementedError("ErrorContext conversion not implemented yet") + + +class ListType(Managed["ctypes._Pointer[ffi.wasmtime_component_list_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_list_type_t]") -> None: + ffi.wasmtime_component_list_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_list_type_t]") -> "ListType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_list_type_t)): + raise TypeError("wrong pointer type") + ty: "ListType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def element(self) -> 'ValType': + """ + Returns the element type of this list type. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + ffi.wasmtime_component_list_type_element(self.ptr(), byref(valtype_ptr)) + return valtype_from_ptr(valtype_ptr) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ListType): + return False + return ffi.wasmtime_component_list_type_equal(self.ptr(), other.ptr()) + + def _is_bytes(self) -> bool: + return isinstance(self.element, U8) + + def add_classes(self, s: Set[type]) -> None: + if self._is_bytes(): + s.add(bytes) + else: + s.add(list) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + element = self.element + if self._is_bytes(): + if not isinstance(val, bytes): + raise TypeError("expected bytes value") + else: + if not isinstance(val, list): + raise TypeError("expected list value") + assert(isinstance(val, (bytes, list))) # here for mypy + raw = ffi.wasmtime_component_vallist_t() + ffi.wasmtime_component_vallist_new_uninit(raw, len(val)) + i = 0 + cleanup = True + try: + for e in val: + element.convert_to_c(store, e, ctypes.pointer(raw.data[i])) + i += 1 + ptr.contents.kind = ffi.WASMTIME_COMPONENT_LIST + ptr.contents.of.list = raw + cleanup = False + finally: + if not cleanup: + return + for j in range(i, len(val)): + raw.data[j].kind = ffi.WASMTIME_COMPONENT_BOOL + raw.data[j].of.boolean = False + ffi.wasmtime_component_vallist_delete(byref(raw)) + + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_LIST.value) + try: + ret = [] + element = self.element + for i in range(c.of.record.size): + raw_field = c.of.tuple.data[i] + ret.append(element.convert_from_c(raw_field)) + raw_field.kind = ffi.WASMTIME_COMPONENT_BOOL + raw_field.of.boolean = False + if self._is_bytes(): + return bytes(ret) + return ret + finally: + ffi.wasmtime_component_valtuple_delete(byref(c.of.tuple)) + + +class RecordType(Managed["ctypes._Pointer[ffi.wasmtime_component_record_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_record_type_t]") -> None: + ffi.wasmtime_component_record_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_record_type_t]") -> "RecordType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_record_type_t)): + raise TypeError("wrong pointer type") + ty: "RecordType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def fields(self) -> List[Tuple[str, 'ValType']]: + """ + Returns the fields of this record type. + """ + n = ffi.wasmtime_component_record_type_field_count(self.ptr()) + items = [] + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + valtype_ptr = ffi.wasmtime_component_valtype_t() + found = ffi.wasmtime_component_record_type_field_nth(self.ptr(), + i, + byref(name_ptr), + byref(name_len), + byref(valtype_ptr)) + assert(found) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + valtype = valtype_from_ptr(valtype_ptr) + items.append((name, valtype)) + return items + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RecordType): + return False + return ffi.wasmtime_component_record_type_equal(self.ptr(), other.ptr()) + + def add_classes(self, s: Set[type]) -> None: + s.add(Record) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + fields = self.fields + raw = ffi.wasmtime_component_valrecord_t() + ffi.wasmtime_component_valrecord_new_uninit(raw, len(fields)) + i = 0 + cleanup = True + try: + for name, ty in fields: + ty.convert_to_c(store, getattr(val, name), ctypes.pointer(raw.data[i].val)) + raw.data[i].name = ffi.str_to_capi(name) + i += 1 + ptr.contents.kind = ffi.WASMTIME_COMPONENT_RECORD + ptr.contents.of.record = raw + cleanup = False + finally: + if not cleanup: + return + for j in range(i, len(fields)): + raw.data[j].val.kind = ffi.WASMTIME_COMPONENT_BOOL + raw.data[j].val.of.boolean = False + ffi.wasmtime_component_valrecord_delete(byref(raw)) + + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_RECORD.value) + try: + ret = Record() + fields = self.fields + for i, (name, ty) in zip(range(c.of.record.size), fields): + raw_field = c.of.record.data[i] + raw_name = ffi.to_str(raw_field.name) + assert(raw_name == name) + val = ty.convert_from_c(raw_field.val) + setattr(ret, name, val) + raw_field.val.kind = ffi.WASMTIME_COMPONENT_BOOL + raw_field.val.of.boolean = False + return ret + finally: + ffi.wasmtime_component_valrecord_delete(c.of.record) + + +class Record: + def __eq__(self, other: Any) -> bool: + for key, value in self.__dict__.items(): + if not hasattr(other, key) or getattr(other, key) != value: + return False + return True + + +class TupleType(Managed["ctypes._Pointer[ffi.wasmtime_component_tuple_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_tuple_type_t]") -> None: + ffi.wasmtime_component_tuple_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_tuple_type_t]") -> "TupleType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_tuple_type_t)): + raise TypeError("wrong pointer type") + ty: "TupleType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def elements(self) -> List['ValType']: + """ + Returns the element types of this tuple type. + """ + n = ffi.wasmtime_component_tuple_type_types_count(self.ptr()) + items = [] + for i in range(n): + valtype_ptr = ffi.wasmtime_component_valtype_t() + found = ffi.wasmtime_component_tuple_type_types_nth(self.ptr(), + i, + byref(valtype_ptr)) + assert(found) + valtype = valtype_from_ptr(valtype_ptr) + items.append(valtype) + return items + + def __eq__(self, other: object) -> bool: + if not isinstance(other, TupleType): + return False + return ffi.wasmtime_component_tuple_type_equal(self.ptr(), other.ptr()) + + def add_classes(self, s: Set[type]) -> None: + s.add(tuple) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + elements = self.elements + if not isinstance(val, tuple): + raise TypeError("expected tuple type") + if len(val) != len(elements): + raise TypeError("tuple length mismatch") + raw = ffi.wasmtime_component_valtuple_t() + ffi.wasmtime_component_valtuple_new_uninit(raw, len(elements)) + i = 0 + cleanup = True + try: + for ty, element in zip(elements, val): + ty.convert_to_c(store, element, ctypes.pointer(raw.data[i])) + i += 1 + ptr.contents.kind = ffi.WASMTIME_COMPONENT_TUPLE + ptr.contents.of.tuple = raw + cleanup = False + finally: + if not cleanup: + return + for j in range(i, len(elements)): + raw.data[j].kind = ffi.WASMTIME_COMPONENT_BOOL + raw.data[j].of.boolean = False + ffi.wasmtime_component_valtuple_delete(byref(raw)) + + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_TUPLE.value) + try: + ret: List[Any] = [] + for i, ty in zip(range(c.of.record.size), self.elements): + raw_field = c.of.tuple.data[i] + ret.append(ty.convert_from_c(raw_field)) + raw_field.kind = ffi.WASMTIME_COMPONENT_BOOL + raw_field.of.boolean = False + return tuple(ret) + finally: + ffi.wasmtime_component_valtuple_delete(byref(c.of.tuple)) + + +@dataclass +class Variant: + tag: str + payload: Optional[Any] = None + + +case_test_cache: Set[type] = set() + + +class VariantLikeType: + @abstractmethod + def _cases(self) -> List[Tuple[str, Optional['ValType']]]: + pass + + def add_classes(self, s: Set[type]) -> None: + if self._tagged(): + s.add(Variant) + else: + for _, ty in self._cases(): + if ty is None: + s.add(object) + else: + ty.add_classes(s) + + def _tagged(self) -> bool: + t: Set[type] = set() + for _, ty in self._cases(): + case: Set[type] = set() + if ty is None: + case.add(object) + else: + ty.add_classes(case) + if len(case & t) != 0: + return True + t |= case + return False + + def _lower(self, store: Storelike, val: Any) -> Tuple[str, Optional['ctypes._Pointer[ffi.wasmtime_component_val_t]']]: + tagged = self._tagged() + if tagged and not isinstance(val, Variant): + raise TypeError("expected Variant type") + for name, ty in self._cases(): + if tagged: + if name != val.tag: + continue + elif ty is None: + if val is not None: + continue + else: + case_test_cache.clear() + ty.add_classes(case_test_cache) + if not isinstance(val, tuple(case_test_cache)): + continue + + if ty is None: + return (name, None) + raw = ffi.wasmtime_component_val_t() + if tagged: + payload = val.payload + else: + payload = val + ty.convert_to_c(store, payload, ctypes.pointer(raw)) + return (name, ffi.wasmtime_component_val_new(byref(raw))) + raise ValueError('value not valid for this variant') + + def _lift(self, tag: str, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> Any: + tagged = self._tagged() + for name, ty in self._cases(): + if name != tag: + continue + if ty is None: + if tagged: + return Variant(tag) + return None + payload = ty.convert_from_c(ptr.contents) + ptr.contents.kind = ffi.WASMTIME_COMPONENT_BOOL + ptr.contents.of.boolean = False + ffi.wasmtime_component_val_delete(ptr) + if tagged: + return Variant(tag, payload) + return payload + raise ValueError(f"tag {tag} not found in variant cases") + + +class VariantType(Managed["ctypes._Pointer[ffi.wasmtime_component_variant_type_t]"], ValType, VariantLikeType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_variant_type_t]") -> None: + ffi.wasmtime_component_variant_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_variant_type_t]") -> "VariantType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_variant_type_t)): + raise TypeError("wrong pointer type") + ty: "VariantType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def cases(self) -> List[Tuple[str, Optional['ValType']]]: + """ + Returns the cases of this variant type. + """ + n = ffi.wasmtime_component_variant_type_case_count(self.ptr()) + items = [] + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + has_payload = ctypes.c_bool() + valtype_ptr = ffi.wasmtime_component_valtype_t() + found = ffi.wasmtime_component_variant_type_case_nth(self.ptr(), + i, + byref(name_ptr), + byref(name_len), + byref(has_payload), + byref(valtype_ptr)) + assert(found) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + if has_payload.value: + valtype = valtype_from_ptr(valtype_ptr) + else: + valtype = None + items.append((name, valtype)) + return items + + def __eq__(self, other: object) -> bool: + if not isinstance(other, VariantType): + return False + return ffi.wasmtime_component_variant_type_equal(self.ptr(), other.ptr()) + + def _cases(self) -> List[Tuple[str, Optional['ValType']]]: + return self.cases + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + name, raw = self._lower(store, val) + ptr.contents.kind = ffi.WASMTIME_COMPONENT_VARIANT + ptr.contents.of.variant.discriminant = ffi.str_to_capi(name) + ptr.contents.of.variant.val = raw + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_VARIANT.value) + tag = ffi.to_str(c.of.variant.discriminant) + ffi.wasm_byte_vec_delete(byref(c.of.variant.discriminant)) + return self._lift(tag, c.of.variant.val) + + +class EnumType(Managed["ctypes._Pointer[ffi.wasmtime_component_enum_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_enum_type_t]") -> None: + ffi.wasmtime_component_enum_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_enum_type_t]") -> "EnumType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_enum_type_t)): + raise TypeError("wrong pointer type") + ty: "EnumType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def names_count(self) -> int: + """ + Returns the numter of names of this enum type. + """ + return ffi.wasmtime_component_enum_type_names_count(self.ptr()) + + def name(self, n: int) -> Optional[str]: + """ + Returns the nth name of this enum type. + """ + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + found = ffi.wasmtime_component_enum_type_names_nth(self.ptr(), + n, + byref(name_ptr), + byref(name_len)) + if found: + return ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + return None + + @property + def names(self) -> List[str]: + """ + Returns the names of this enum type. + """ + items = [] + for i in range(self.names_count): + name = self.name(i) + assert(name is not None) + items.append(name) + return items + + def __eq__(self, other: object) -> bool: + if not isinstance(other, EnumType): + return False + return ffi.wasmtime_component_enum_type_equal(self.ptr(), other.ptr()) + + def add_classes(self, s: Set[type]) -> None: + s.add(str) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if isinstance(val, str): + ptr.contents.kind = ffi.WASMTIME_COMPONENT_ENUM + ptr.contents.of.enumeration = ffi.str_to_capi(val) + else: + raise TypeError("expected str type") + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_ENUM.value) + ret = ffi.to_str(c.of.enumeration) + ffi.wasm_byte_vec_delete(byref(c.of.enumeration)) + return ret + + +class OptionType(Managed["ctypes._Pointer[ffi.wasmtime_component_option_type_t]"], ValType, VariantLikeType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_option_type_t]") -> None: + ffi.wasmtime_component_option_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_option_type_t]") -> "OptionType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_option_type_t)): + raise TypeError("wrong pointer type") + ty: "OptionType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def payload(self) -> 'ValType': + """ + Returns the payload type of this option type. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + ffi.wasmtime_component_option_type_ty(self.ptr(), byref(valtype_ptr)) + return valtype_from_ptr(valtype_ptr) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OptionType): + return False + return ffi.wasmtime_component_option_type_equal(self.ptr(), other.ptr()) + + def _cases(self) -> List[Tuple[str, Optional['ValType']]]: + return [('none', None), ('some', self.payload)] + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + _, raw = self._lower(store, val) + ptr.contents.kind = ffi.WASMTIME_COMPONENT_OPTION + ptr.contents.of.option = raw + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_OPTION.value) + if c.of.option: + tag = 'some' + else: + tag = 'none' + return self._lift(tag, c.of.option) + + + +class ResultType(Managed["ctypes._Pointer[ffi.wasmtime_component_result_type_t]"], ValType, VariantLikeType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_result_type_t]") -> None: + ffi.wasmtime_component_result_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_result_type_t]") -> "ResultType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_result_type_t)): + raise TypeError("wrong pointer type") + ty: "ResultType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def ok(self) -> Optional['ValType']: + """ + Returns the ok type of this result type, if any. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + has_ok = ffi.wasmtime_component_result_type_ok(self.ptr(), byref(valtype_ptr)) + if not has_ok: + return None + return valtype_from_ptr(valtype_ptr) + + @property + def err(self) -> Optional['ValType']: + """ + Returns the err type of this result type, if any. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + has_err = ffi.wasmtime_component_result_type_err(self.ptr(), byref(valtype_ptr)) + if not has_err: + return None + return valtype_from_ptr(valtype_ptr) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ResultType): + return False + return ffi.wasmtime_component_result_type_equal(self.ptr(), other.ptr()) + + def _cases(self) -> List[Tuple[str, Optional['ValType']]]: + return [('ok', self.ok), ('err', self.err)] + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + name, raw = self._lower(store, val) + ptr.contents.kind = ffi.WASMTIME_COMPONENT_RESULT + ptr.contents.of.result.is_ok = name == 'ok' + ptr.contents.of.result.val = raw + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_RESULT.value) + if c.of.result.is_ok: + tag = 'ok' + else: + tag = 'err' + return self._lift(tag, c.of.result.val) + + +class FlagsType(Managed["ctypes._Pointer[ffi.wasmtime_component_flags_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_flags_type_t]") -> None: + ffi.wasmtime_component_flags_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_flags_type_t]") -> "FlagsType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_flags_type_t)): + raise TypeError("wrong pointer type") + ty: "FlagsType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def names(self) -> List[str]: + """ + Returns the names of this flags type. + """ + n = ffi.wasmtime_component_flags_type_names_count(self.ptr()) + items = [] + for i in range(n): + name_ptr = ctypes.POINTER(ctypes.c_char)() + name_len = ctypes.c_size_t() + found = ffi.wasmtime_component_flags_type_names_nth(self.ptr(), + i, + byref(name_ptr), + byref(name_len)) + assert(found) + name = ctypes.string_at(name_ptr, name_len.value).decode('utf-8') + items.append(name) + return items + + def __eq__(self, other: object) -> bool: + if not isinstance(other, FlagsType): + return False + return ffi.wasmtime_component_flags_type_equal(self.ptr(), other.ptr()) + + def add_classes(self, s: Set[type]) -> None: + s.add(set) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if not isinstance(val, set): + raise TypeError("expected set type for Flags type") + for s in val: + if not isinstance(s, str): + raise TypeError("expected set of strings for Flags type") + + raw = ffi.wasmtime_component_valflags_t() + ffi.wasmtime_component_valflags_new_uninit(raw, len(val)) + for i, s in enumerate(val): + raw.data[i] = ffi.str_to_capi(s) + ptr.contents.kind = ffi.WASMTIME_COMPONENT_FLAGS + ptr.contents.of.flags = raw + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_FLAGS.value) + result = set() + for i in range(c.of.flags.size): + s = ffi.to_str(c.of.flags.data[i]) + result.add(s) + ffi.wasmtime_component_valflags_delete(byref(c.of.flags)) + return result + + +class FutureType(Managed["ctypes._Pointer[ffi.wasmtime_component_future_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_future_type_t]") -> None: + ffi.wasmtime_component_future_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_future_type_t]") -> "FutureType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_future_type_t)): + raise TypeError("wrong pointer type") + ty: "FutureType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def payload(self) -> 'ValType': + """ + Returns the payload type of this future type. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + ffi.wasmtime_component_future_type_ty(self.ptr(), byref(valtype_ptr)) + return valtype_from_ptr(valtype_ptr) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, FutureType): + return False + return ffi.wasmtime_component_future_type_equal(self.ptr(), other.ptr()) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + raise NotImplementedError("Future conversion not implemented yet") + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + raise NotImplementedError("conversion not implemented yet") + + +class StreamType(Managed["ctypes._Pointer[ffi.wasmtime_component_stream_type_t]"], ValType): + def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_component_stream_type_t]") -> None: + ffi.wasmtime_component_stream_type_delete(ptr) + + @classmethod + def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_component_stream_type_t]") -> "StreamType": + if not isinstance(ptr, POINTER(ffi.wasmtime_component_stream_type_t)): + raise TypeError("wrong pointer type") + ty: "StreamType" = cls.__new__(cls) + ty._set_ptr(ptr) + return ty + + @property + def payload(self) -> 'ValType': + """ + Returns the payload type of this stream type. + """ + valtype_ptr = ffi.wasmtime_component_valtype_t() + ffi.wasmtime_component_stream_type_ty(self.ptr(), byref(valtype_ptr)) + return valtype_from_ptr(valtype_ptr) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, StreamType): + return False + return ffi.wasmtime_component_stream_type_equal(self.ptr(), other.ptr()) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + raise NotImplementedError("Stream conversion not implemented yet") + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + raise NotImplementedError("conversion not implemented yet") + + +@dataclass +class OwnType(ValType): + ty: ResourceType + + def add_classes(self, s: Set[type]) -> None: + s.add(ResourceAny) + s.add(ResourceHost) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if isinstance(val, ResourceAny): + ptr.contents.kind = ffi.WASMTIME_COMPONENT_RESOURCE + ptr.contents.of.resource = val._consume() + elif isinstance(val, ResourceHost): + ptr.contents.kind = ffi.WASMTIME_COMPONENT_RESOURCE + ptr.contents.of.resource = val.to_any(store)._consume() + else: + raise TypeError("expected ResourceAny or ResourceHost for Own type") + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_RESOURCE.value) + return ResourceAny._from_ptr(ffi.take_pointer(c.of, 'resource')) + + +@dataclass +class BorrowType(ValType): + ty: ResourceType + + def add_classes(self, s: Set[type]) -> None: + s.add(ResourceAny) + s.add(ResourceHost) + + def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.wasmtime_component_val_t]') -> None: + if isinstance(val, ResourceAny): + ptr.contents.kind = ffi.WASMTIME_COMPONENT_RESOURCE + ptr.contents.of.resource = ffi.wasmtime_component_resource_any_clone(val.ptr()) + elif isinstance(val, ResourceHost): + ptr.contents.kind = ffi.WASMTIME_COMPONENT_RESOURCE + ptr.contents.of.resource = val.to_any(store)._consume() + else: + raise TypeError("expected ResourceAny or ResourceHost for Own type") + + def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: + assert(c.kind == ffi.WASMTIME_COMPONENT_RESOURCE.value) + return ResourceAny._from_ptr(ffi.take_pointer(c.of, 'resource')) + + +ComponentItem = Union[ + ComponentType, + ModuleType, + ComponentInstanceType, + ResourceType, + ValType, + FuncType, +] + + +def component_item_from_ptr(ptr: ffi.wasmtime_component_item_t) -> ComponentItem: + if ptr.kind == ffi.WASMTIME_COMPONENT_ITEM_COMPONENT.value: + return ComponentType._from_ptr(ptr.of.component) + elif ptr.kind == ffi.WASMTIME_COMPONENT_ITEM_MODULE.value: + return ModuleType._from_ptr(ptr.of.module) + elif ptr.kind == ffi.WASMTIME_COMPONENT_ITEM_COMPONENT_INSTANCE.value: + return ComponentInstanceType._from_ptr(ptr.of.component_instance) + elif ptr.kind == ffi.WASMTIME_COMPONENT_ITEM_RESOURCE.value: + return ResourceType._from_ptr(ptr.of.resource) + elif ptr.kind == ffi.WASMTIME_COMPONENT_ITEM_COMPONENT_FUNC.value: + return FuncType._from_ptr(ptr.of.component_func) + elif ptr.kind == ffi.WASMTIME_COMPONENT_ITEM_TYPE.value: + return valtype_from_ptr(ptr.of.type) + else: + ffi.wasmtime_component_item_delete(byref(ptr)) + raise TypeError("unknown component item kind") + + +def valtype_from_ptr(ptr: ffi.wasmtime_component_valtype_t) -> ValType: + if ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_BOOL.value: + return Bool() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_S8.value: + return S8() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_S16.value: + return S16() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_S32.value: + return S32() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_S64.value: + return S64() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_U8.value: + return U8() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_U16.value: + return U16() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_U32.value: + return U32() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_U64.value: + return U64() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_F32.value: + return F32() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_F64.value: + return F64() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_CHAR.value: + return Char() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_STRING.value: + return String() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_ERROR_CONTEXT.value: + return ErrorContext() + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_LIST.value: + return ListType._from_ptr(ptr.of.list) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_RECORD.value: + return RecordType._from_ptr(ptr.of.record) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_TUPLE.value: + return TupleType._from_ptr(ptr.of.tuple) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_VARIANT.value: + return VariantType._from_ptr(ptr.of.variant) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_ENUM.value: + return EnumType._from_ptr(ptr.of.enum_) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_OPTION.value: + return OptionType._from_ptr(ptr.of.option) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_RESULT.value: + return ResultType._from_ptr(ptr.of.result) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_FLAGS.value: + return FlagsType._from_ptr(ptr.of.flags) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_FUTURE.value: + return FutureType._from_ptr(ptr.of.future) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_STREAM.value: + return StreamType._from_ptr(ptr.of.stream) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_OWN.value: + return OwnType(ResourceType._from_ptr(ptr.of.own)) + elif ptr.kind == ffi.WASMTIME_COMPONENT_VALTYPE_BORROW.value: + return BorrowType(ResourceType._from_ptr(ptr.of.borrow)) + else: + ffi.wasmtime_component_valtype_delete(byref(ptr)) + raise TypeError("unknown component value type kind") From bfdae4db31f88ad140a3d6caf786cf2aa8370994 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Nov 2025 12:55:39 -0800 Subject: [PATCH 3/5] Update to latest dev branch of wasmtime --- ci/cbindgen.py | 5 +++++ tests/component/test_linker.py | 14 ++++++++++++++ wasmtime/_bindings.py | 18 ++++++++++++++++++ wasmtime/component/_linker.py | 12 ++++++++++++ 4 files changed, 49 insertions(+) diff --git a/ci/cbindgen.py b/ci/cbindgen.py index 4c2188ed..9e968382 100644 --- a/ci/cbindgen.py +++ b/ci/cbindgen.py @@ -189,7 +189,10 @@ def type_name(ty, ptr=False, typing=False): return "POINTER({})".format(type_name(ty, False, typing)) if isinstance(ty, c_ast.IdentifierType): + if ty.names == ['unsigned', 'char']: + return "int" if typing else "c_ubyte" assert(len(ty.names) == 1) + if ty.names[0] == "void": return "None" elif ty.names[0] == "_Bool": @@ -218,6 +221,8 @@ def type_name(ty, ptr=False, typing=False): return "float" if typing else "c_double" elif ty.names[0] == "size_t": return "int" if typing else "c_size_t" + elif ty.names[0] == "ptrdiff_t": + return "int" if typing else "c_ssize_t" elif ty.names[0] == "char": return "c_char" elif ty.names[0] == "int": diff --git a/tests/component/test_linker.py b/tests/component/test_linker.py index 2e23c98f..df0ac093 100644 --- a/tests/component/test_linker.py +++ b/tests/component/test_linker.py @@ -142,3 +142,17 @@ def test_shadow_func(self): linker.allow_shadowing = True with linker.root() as l: l.add_func('x', lambda: None) + + def test_define_unknown_imports_as_traps(self): + engine = Engine() + store = Store(engine) + component = Component(engine, """ + (component + (import "x" (func $x)) + ) + """) + linker = Linker(engine) + with self.assertRaises(WasmtimeError): + linker.instantiate(store, component) + linker.define_unknown_imports_as_traps(component) + linker.instantiate(store, component) diff --git a/wasmtime/_bindings.py b/wasmtime/_bindings.py index 93031b3b..c7afd6f3 100644 --- a/wasmtime/_bindings.py +++ b/wasmtime/_bindings.py @@ -1960,6 +1960,12 @@ def wasi_config_set_stdout_file(config: Any, path: Any) -> bool: def wasi_config_inherit_stdout(config: Any) -> None: return _wasi_config_inherit_stdout(config) # type: ignore +_wasi_config_set_stdout_custom = dll.wasi_config_set_stdout_custom +_wasi_config_set_stdout_custom.restype = None +_wasi_config_set_stdout_custom.argtypes = [POINTER(wasi_config_t), CFUNCTYPE(c_ssize_t, c_void_p, POINTER(c_ubyte), c_size_t), c_void_p, CFUNCTYPE(None, c_void_p)] +def wasi_config_set_stdout_custom(config: Any, callback: Any, data: Any, finalizer: Any) -> None: + return _wasi_config_set_stdout_custom(config, callback, data, finalizer) # type: ignore + _wasi_config_set_stderr_file = dll.wasi_config_set_stderr_file _wasi_config_set_stderr_file.restype = c_bool _wasi_config_set_stderr_file.argtypes = [POINTER(wasi_config_t), POINTER(c_char)] @@ -1972,6 +1978,12 @@ def wasi_config_set_stderr_file(config: Any, path: Any) -> bool: def wasi_config_inherit_stderr(config: Any) -> None: return _wasi_config_inherit_stderr(config) # type: ignore +_wasi_config_set_stderr_custom = dll.wasi_config_set_stderr_custom +_wasi_config_set_stderr_custom.restype = None +_wasi_config_set_stderr_custom.argtypes = [POINTER(wasi_config_t), CFUNCTYPE(c_ssize_t, c_void_p, POINTER(c_ubyte), c_size_t), c_void_p, CFUNCTYPE(None, c_void_p)] +def wasi_config_set_stderr_custom(config: Any, callback: Any, data: Any, finalizer: Any) -> None: + return _wasi_config_set_stderr_custom(config, callback, data, finalizer) # type: ignore + class wasi_dir_perms_flags(Enum): WASMTIME_WASI_DIR_PERMS_READ = 1 WASMTIME_WASI_DIR_PERMS_WRITE = 2 @@ -4660,6 +4672,12 @@ def wasmtime_component_linker_root(linker: Any) -> ctypes._Pointer: def wasmtime_component_linker_instantiate(linker: Any, context: Any, component: Any, instance_out: Any) -> ctypes._Pointer: return _wasmtime_component_linker_instantiate(linker, context, component, instance_out) # type: ignore +_wasmtime_component_linker_define_unknown_imports_as_traps = dll.wasmtime_component_linker_define_unknown_imports_as_traps +_wasmtime_component_linker_define_unknown_imports_as_traps.restype = POINTER(wasmtime_error_t) +_wasmtime_component_linker_define_unknown_imports_as_traps.argtypes = [POINTER(wasmtime_component_linker_t), POINTER(wasmtime_component_t)] +def wasmtime_component_linker_define_unknown_imports_as_traps(linker: Any, component: Any) -> ctypes._Pointer: + return _wasmtime_component_linker_define_unknown_imports_as_traps(linker, component) # type: ignore + _wasmtime_component_linker_delete = dll.wasmtime_component_linker_delete _wasmtime_component_linker_delete.restype = None _wasmtime_component_linker_delete.argtypes = [POINTER(wasmtime_component_linker_t)] diff --git a/wasmtime/component/_linker.py b/wasmtime/component/_linker.py index b95804e1..3aeede4d 100644 --- a/wasmtime/component/_linker.py +++ b/wasmtime/component/_linker.py @@ -91,6 +91,18 @@ def instantiate(self, store: Storelike, component: Component) -> Instance: raise WasmtimeError._from_ptr(err) return Instance._from_raw(instance) + def define_unknown_imports_as_traps(self, component: Component) -> None: + """ + Configures this linker to define any unknown imports of `component` as + traps which will error when invoked. + """ + sself._assert_not_locked() + err = ffi.wasmtime_component_linker_define_unknown_imports_as_traps( + self.ptr(), + component.ptr()) + if err: + raise WasmtimeError._from_ptr(err) + class LinkerInstance(Managed["ctypes._Pointer[ffi.wasmtime_component_linker_instance_t]"]): parent: Union[LinkerInstanceParent, None] From e29ca1de34b822307218b4f0053828868890e120 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Nov 2025 13:09:38 -0800 Subject: [PATCH 4/5] CI fixes --- wasmtime/component/_instance.py | 4 ++-- wasmtime/component/_linker.py | 2 +- wasmtime/component/_types.py | 33 +++++++++++++++------------------ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/wasmtime/component/_instance.py b/wasmtime/component/_instance.py index b0a4f879..036f77ab 100644 --- a/wasmtime/component/_instance.py +++ b/wasmtime/component/_instance.py @@ -1,6 +1,6 @@ from .. import _ffi as ffi, WasmtimeError, Storelike from ctypes import byref -from typing import Optional +from typing import Optional, Union from ._component import ExportIndex from ._func import Func @@ -41,7 +41,7 @@ def get_export_index(self, store: Storelike, name: str, instance: Optional[Expor return ExportIndex._from_ptr(ptr) return None - def get_func(self, store: Storelike, index: ExportIndex | str) -> Optional[Func]: + def get_func(self, store: Storelike, index: Union[ExportIndex, str]) -> Optional[Func]: """ Retrieves the function export for the given export index. diff --git a/wasmtime/component/_linker.py b/wasmtime/component/_linker.py index 3aeede4d..2c6611fa 100644 --- a/wasmtime/component/_linker.py +++ b/wasmtime/component/_linker.py @@ -96,7 +96,7 @@ def define_unknown_imports_as_traps(self, component: Component) -> None: Configures this linker to define any unknown imports of `component` as traps which will error when invoked. """ - sself._assert_not_locked() + self._assert_not_locked() err = ffi.wasmtime_component_linker_define_unknown_imports_as_traps( self.ptr(), component.ptr()) diff --git a/wasmtime/component/_types.py b/wasmtime/component/_types.py index d086f660..f50dff5d 100644 --- a/wasmtime/component/_types.py +++ b/wasmtime/component/_types.py @@ -502,12 +502,11 @@ def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.was ptr.contents.of.list = raw cleanup = False finally: - if not cleanup: - return - for j in range(i, len(val)): - raw.data[j].kind = ffi.WASMTIME_COMPONENT_BOOL - raw.data[j].of.boolean = False - ffi.wasmtime_component_vallist_delete(byref(raw)) + if cleanup: + for j in range(i, len(val)): + raw.data[j].kind = ffi.WASMTIME_COMPONENT_BOOL + raw.data[j].of.boolean = False + ffi.wasmtime_component_vallist_delete(byref(raw)) def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: @@ -584,12 +583,11 @@ def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.was ptr.contents.of.record = raw cleanup = False finally: - if not cleanup: - return - for j in range(i, len(fields)): - raw.data[j].val.kind = ffi.WASMTIME_COMPONENT_BOOL - raw.data[j].val.of.boolean = False - ffi.wasmtime_component_valrecord_delete(byref(raw)) + if cleanup: + for j in range(i, len(fields)): + raw.data[j].val.kind = ffi.WASMTIME_COMPONENT_BOOL + raw.data[j].val.of.boolean = False + ffi.wasmtime_component_valrecord_delete(byref(raw)) def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: @@ -673,12 +671,11 @@ def convert_to_c(self, store: Storelike, val: Any, ptr: 'ctypes._Pointer[ffi.was ptr.contents.of.tuple = raw cleanup = False finally: - if not cleanup: - return - for j in range(i, len(elements)): - raw.data[j].kind = ffi.WASMTIME_COMPONENT_BOOL - raw.data[j].of.boolean = False - ffi.wasmtime_component_valtuple_delete(byref(raw)) + if cleanup: + for j in range(i, len(elements)): + raw.data[j].kind = ffi.WASMTIME_COMPONENT_BOOL + raw.data[j].of.boolean = False + ffi.wasmtime_component_valtuple_delete(byref(raw)) def convert_from_c(self, c: 'ffi.wasmtime_component_val_t') -> Any: From 01a3b446d05e252b2662f4dc8dda2644071c3868 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Nov 2025 13:13:03 -0800 Subject: [PATCH 5/5] Python 3.9 compat --- wasmtime/component/_linker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wasmtime/component/_linker.py b/wasmtime/component/_linker.py index 2c6611fa..ebc0a64a 100644 --- a/wasmtime/component/_linker.py +++ b/wasmtime/component/_linker.py @@ -5,7 +5,7 @@ from ._instance import Instance from ._component import Component from ._resource_type import ResourceType -from typing import Union, Tuple, Callable, Optional, List, Any, Concatenate +from typing import Union, Tuple, Callable, Optional, List, Any from .._func import Slab from ._enter import catch_exceptions from ._types import ValType, FuncType @@ -15,7 +15,7 @@ ResourceDtor = Callable[[StoreContext, int], None] RESOURCE_DTORS: Slab[ResourceDtor] = Slab() -UserFunc = Callable[Concatenate[StoreContext, ...], Optional[Any]] +UserFunc = Callable[..., Optional[Any]] FUNCTIONS: Slab[UserFunc] = Slab()