Skip to content

Instantly share code, notes, and snippets.

@simonw
Created November 5, 2024 22:17
Show Gist options
  • Save simonw/351cffbd254af5cbf329377fb95fcc13 to your computer and use it in GitHub Desktop.
Save simonw/351cffbd254af5cbf329377fb95fcc13 to your computer and use it in GitHub Desktop.

2024-11-05T22:10:15 conversation: 01jbz62jjqfyc0stmn60gd2qc6

Model: claude-3-5-sonnet-latest

Prompt:

files-to-prompt -e py wasmtime-py/tests -c
<documents>
<document index="1">
<source>./__init__.py</source>
<document_content>
import unittest

</document_content>
</document>
<document index="2">
<source>./test_config.py</source>
<document_content>
import unittest
from contextlib import closing

from wasmtime import *


class TestConfig(unittest.TestCase):
    def test_smoke(self):
        config = Config()
        config.debug_info = True
        config.wasm_threads = True
        config.wasm_tail_call = True
        config.wasm_reference_types = True
        config.wasm_simd = True
        config.wasm_bulk_memory = True
        config.wasm_multi_value = True
        config.wasm_multi_memory = True
        config.wasm_memory64 = True
        config.cranelift_debug_verifier = True
        config.strategy = "cranelift"
        config.strategy = "auto"
        config.cache = True
        config.parallel_compilation = False
        with self.assertRaises(WasmtimeError):
            config.cache = "./test.toml"
        with self.assertRaises(WasmtimeError):
            config.strategy = "nonexistent-strategy"
        config.cranelift_opt_level = "none"
        config.cranelift_opt_level = "speed_and_size"
        config.cranelift_opt_level = "speed"
        with self.assertRaises(WasmtimeError):
            config.cranelift_opt_level = "nonexistent-level"
        config.profiler = "none"
        with self.assertRaises(WasmtimeError):
            config.profiler = "nonexistent-profiler"
        config.consume_fuel = True
        config.wasm_relaxed_simd = True
        config.wasm_relaxed_simd_deterministic = True

        with closing(config) as config:
            pass

        config.close()

        with self.assertRaises(ValueError):
            Engine(config)

        with self.assertRaises(ValueError):
            config.cache = True

</document_content>
</document>
<document index="3">
<source>./test_engine.py</source>
<document_content>
import unittest

from wasmtime import *


class TestEngine(unittest.TestCase):
    def test_smoke(self):
        Engine()
        Engine(Config())

    def test_errors(self):
        with self.assertRaises(TypeError):
            Engine(3)  # type: ignore
        config = Config()
        Engine(config)
        with self.assertRaises(ValueError):
            Engine(config)

</document_content>
</document>
<document index="4">
<source>./test_func.py</source>
<document_content>
import unittest

from wasmtime import *


class TestFunc(unittest.TestCase):
    def test_smoke(self):
        store = Store()
        ty = FuncType([], [])
        func = Func(store, ty, lambda: None)
        func(store)
        self.assertTrue(isinstance(func.type(store), FuncType))

    def test_add(self):
        store = Store()
        ty = FuncType([ValType.i32(), ValType.i32()], [ValType.i32()])
        func = Func(store, ty, lambda a, b: a + b)
        self.assertEqual(func(store, 1, 2), 3)

    def test_calls(self):
        store = Store()
        ty = FuncType([ValType.i32()], [])
        func = Func(store, ty, lambda a: self.assertEqual(a, 1))
        func(store, 1)

        ty = FuncType([ValType.i64()], [])
        func = Func(store, ty, lambda a: self.assertEqual(a, 2))
        func(store, Val.i64(2))

        ty = FuncType([ValType.f32()], [])
        func = Func(store, ty, lambda a: self.assertEqual(a, 3.0))
        func(store, 3.0)

        ty = FuncType([ValType.f64()], [])
        func = Func(store, ty, lambda a: self.assertEqual(a, 4.0))
        func(store, 4.0)

    def test_multi_return(self):
        store = Store()
        ty = FuncType([], [ValType.i32(), ValType.i32()])
        func = Func(store, ty, lambda: [1, 2])
        self.assertEqual(func(store), [1, 2])

    def test_errors(self):
        store = Store()
        ty = FuncType([], [])
        with self.assertRaises(TypeError):
            Func(1, ty, lambda: None)  # type: ignore
        with self.assertRaises(TypeError):
            Func(store, 1, lambda: None)  # type: ignore
        func = Func(store, ty, lambda: None)
        with self.assertRaises(WasmtimeError):
            func(store, 2)

        ty = FuncType([ValType.i32()], [])
        func = Func(store, ty, lambda: None)
        with self.assertRaises(TypeError):
            func(store, 3.0)
        with self.assertRaises(TypeError):
            func(store, Val.i64(3))
        ty = FuncType([ValType.i32()], [])

        func = Func(store, ty, lambda x: x)
        with self.assertRaises(WasmtimeError, msg="produced results"):
            func(store, 1)

    def test_produce_wrong(self):
        store = Store()
        ty = FuncType([], [ValType.i32(), ValType.i32()])
        func = Func(store, ty, lambda: 1)
        with self.assertRaises(TypeError, msg="has no len"):
            func(store)
        func = Func(store, ty, lambda: [1, 2, 3])
        with self.assertRaises(WasmtimeError, msg="wrong number of results"):
            func(store)

    def test_host_exception(self):
        store = Store()
        ty = FuncType([], [])

        def do_raise():
            raise Exception("hello")

        func = Func(store, ty, do_raise)
        with self.assertRaises(Exception, msg="hello"):
            func(store)

    def test_type(self):
        store = Store()
        i32 = ValType.i32()
        i64 = ValType.i64()
        f32 = ValType.f32()
        f64 = ValType.f64()
        ty = FuncType([i32, i64, f32, f64], [f64, f32, i64, i32])

        def rev(*args):
            ret = list(args)
            ret.reverse()
            return ret

        func = Func(store, ty, rev)
        self.assertEqual(func(store, 1, 2, 3.0, 4.0), [4.0, 3.0, 2, 1])

    def test_access_caller(self):
        # Test that we get *something*
        store = Store()

        def runtest(caller):
            self.assertEqual(caller.get(''), None)
            self.assertEqual(caller.get('x'), None)
            self.assertEqual(caller.get('y'), None)

        Func(store, FuncType([], []), runtest, access_caller=True)(store)

        hit = {}

        # Test that `Caller` works and that it's invalidated
        def runtest2(caller):
            hit['yes'] = True
            hit['caller'] = caller

            self.assertTrue(caller.get('bar') is None)
            mem = caller.get('foo')
            self.assertTrue(isinstance(mem, Memory))

            self.assertEqual(mem.data_ptr(caller)[0], ord('f'))
            self.assertEqual(mem.data_ptr(caller)[1], ord('o'))
            self.assertEqual(mem.data_ptr(caller)[2], ord('o'))
            self.assertEqual(mem.data_ptr(caller)[3], 0)

        module = Module(store.engine, """
            (module
                (import "" "" (func))
                (memory (export "foo") 1)
                (start 0)
                (data (i32.const 0) "foo")
            )
        """)
        func = Func(store, FuncType([], []), runtest2, access_caller=True)
        Instance(store, module, [func])
        self.assertTrue(hit['yes'])
        self.assertTrue(hit['caller'].get('foo') is None)  # type: ignore

        # Test that `Caller` is invalidated even on exceptions
        hit2 = {}

        def runtest3(caller):
            hit2['caller'] = caller
            self.assertTrue(caller['foo'] is not None)
            raise WasmtimeError('foo')

        func = Func(store, FuncType([], []), runtest3, access_caller=True)
        with self.assertRaises(WasmtimeError, msg='foo'):
            Instance(store, module, [func])
        self.assertTrue(hit2['caller'].get('foo') is None)

</document_content>
</document>
<document index="5">
<source>./test_global.py</source>
<document_content>
import unittest

from wasmtime import *


class TestGlobal(unittest.TestCase):
    def test_new(self):
        store = Store()
        ty = GlobalType(ValType.i32(), True)
        g = Global(store, ty, Val.i32(1))
        Global(store, ty, Val.i32(1))
        self.assertEqual(g.type(store).content, ValType.i32())
        self.assertTrue(g.type(store).mutable)

        self.assertEqual(g.value(store), 1)
        g.set_value(store, Val.i32(2))
        self.assertEqual(g.value(store), 2)
        self.assertTrue(isinstance(g.type(store), GlobalType))

    def test_falsy(self):
        store = Store()
        ty = GlobalType(ValType.i64(), True)
        g = Global(store, ty, Val.i64(0))
        val = g.value(store)

        self.assertEqual(val, 0)
        self.assertTrue(isinstance(val, int))

    def test_errors(self):
        store = Store()
        ty = GlobalType(ValType.i32(), True)
        with self.assertRaises(TypeError):
            Global(store, ty, store)
        with self.assertRaises(TypeError):
            Global(store, 1, Val.i32(1))  # type: ignore
        with self.assertRaises(AttributeError):
            Global(1, ty, Val.i32(1))  # type: ignore

        g = Global(store, ty, Val.i32(1))
        with self.assertRaises(TypeError):
            g.set_value(store, g)

        ty = GlobalType(ValType.i32(), False)
        g = Global(store, ty, Val.i32(1))
        with self.assertRaises(WasmtimeError):
            g.set_value(store, 1)

</document_content>
</document>
<document index="6">
<source>./test_instance.py</source>
<document_content>
import unittest

from wasmtime import *


class TestInstance(unittest.TestCase):
    def test_smoke(self):
        store = Store()
        module = Module(store.engine, '(module)')
        Instance(store, module, [])

    def test_export_func(self):
        store = Store()
        module = Module(store.engine, '(module (func (export "")))')
        instance = Instance(store, module, [])
        self.assertEqual(len(instance.exports(store)), 1)
        extern = instance.exports(store).by_index[0]
        assert(isinstance(extern, Func))
        assert(isinstance(extern.type(store), FuncType))

        extern(store)

        assert(instance.exports(store)[''] is not None)
        with self.assertRaises(KeyError):
            instance.exports(store)['x']
        with self.assertRaises(IndexError):
            instance.exports(store).by_index[100]
        assert(instance.exports(store).get('x') is None)

    def test_export_global(self):
        store = Store()
        module = Module(
            store.engine, '(module (global (export "") i32 (i32.const 3)))')
        instance = Instance(store, module, [])
        self.assertEqual(len(instance.exports(store)), 1)
        extern = instance.exports(store).by_index[0]
        assert(isinstance(extern, Global))
        self.assertEqual(extern.value(store), 3)
        assert(isinstance(extern.type(store), GlobalType))

    def test_export_memory(self):
        store = Store()
        module = Module(store.engine, '(module (memory (export "") 1))')
        instance = Instance(store, module, [])
        self.assertEqual(len(instance.exports(store)), 1)
        extern = instance.exports(store).by_index[0]
        assert(isinstance(extern, Memory))
        self.assertEqual(extern.size(store), 1)

    def test_export_table(self):
        store = Store()
        module = Module(store.engine, '(module (table (export "") 1 funcref))')
        instance = Instance(store, module, [])
        self.assertEqual(len(instance.exports(store)), 1)
        extern = instance.exports(store).by_index[0]
        assert(isinstance(extern, Table))

    def test_multiple_exports(self):
        store = Store()
        module = Module(store.engine, """
            (module
                (func (export "a"))
                (func (export "b"))
                (global (export "c") i32 (i32.const 0))
            )
        """)
        instance = Instance(store, module, [])
        exports = instance.exports(store)
        self.assertEqual(len(exports), 3)
        assert isinstance(exports.by_index[0], Func)
        assert isinstance(exports.by_index[1], Func)
        assert isinstance(exports.by_index[2], Global)
        # Test that exports acts like a normal map
        assert "a" in exports
        assert "b" in exports
        assert "d" not in exports
        assert set(exports) == {"a", "b", "c"}
        assert set(exports.values()) == set(exports.by_index)
        assert exports.get("d", 7) == 7
        assert isinstance(exports.get("b", 7), Func)

    def test_import_func(self):
        store = Store()
        module = Module(store.engine, """
            (module
                (import "" "" (func))
                (start 0)
            )
        """)
        hit = []
        func = Func(store, FuncType([], []), lambda: hit.append(True))
        Instance(store, module, [func])
        assert(len(hit) == 1)
        Instance(store, module, [func])
        assert(len(hit) == 2)

    def test_import_global(self):
        store = Store()
        module = Module(store.engine, """
            (module
                (import "" "" (global (mut i32)))
                (func (export "") (result i32)
                    global.get 0)
                (func (export "update")
                    i32.const 5
                    global.set 0)
            )
        """)
        g = Global(store, GlobalType(ValType.i32(), True), 2)
        instance = Instance(store, module, [g])
        f = instance.exports(store).by_index[0]
        assert(isinstance(f, Func))

        self.assertEqual(f(store), 2)
        g.set_value(store, 4)
        self.assertEqual(f(store), 4)

        instance2 = Instance(store, module, [g])
        f2 = instance2.exports(store).by_index[0]
        assert(isinstance(f2, Func))
        self.assertEqual(f(store), 4)
        self.assertEqual(f2(store), 4)

        update = instance.exports(store).by_index[1]
        assert(isinstance(update, Func))
        update(store)
        self.assertEqual(f(store), 5)
        self.assertEqual(f2(store), 5)

    def test_import_memory(self):
        store = Store()
        module = Module(store.engine, """
            (module
                (import "" "" (memory 1))
            )
        """)
        m = Memory(store, MemoryType(Limits(1, None)))
        Instance(store, module, [m])

    def test_import_table(self):
        store = Store()
        module = Module(store.engine, """
            (module
                (table (export "") 1 funcref)
            )
        """)
        table = Instance(store, module, []).exports(store).by_index[0]

        module = Module(store.engine, """
            (module
                (import "" "" (table 1 funcref))
            )
        """)
        Instance(store, module, [table])

    def test_invalid(self):
        store = Store()
        with self.assertRaises(AttributeError):
            Instance(store, 1, [])  # type: ignore
        with self.assertRaises(TypeError):
            Instance(store, Module(store.engine, '(module (import "" "" (func)))'), [1])  # type: ignore

        val = Func(store, FuncType([], []), lambda: None)
        module = Module(store.engine, '(module (import "" "" (func)))')
        Instance(store, module, [val])
        with self.assertRaises(WasmtimeError):
            Instance(store, module, [])
        with self.assertRaises(WasmtimeError):
            Instance(store, module, [val, val])

        module = Module(store.engine, '(module (import "" "" (global i32)))')
        with self.assertRaises(WasmtimeError):
            Instance(store, module, [val])

    def test_start_trap(self):
        store = Store()
        module = Module(store.engine, '(module (func unreachable) (start 0))')
        with self.assertRaises(Trap):
            Instance(store, module, [])

</document_content>
</document>
<document index="7">
<source>./test_linker.py</source>
<document_content>
import unittest

from wasmtime import *


class TestLinker(unittest.TestCase):
    def test_define(self):
        store = Store()
        linker = Linker(store.engine)
        linker.allow_shadowing = False

        func = Func(store, FuncType([], []), lambda: None)
        linker.define(store, "", "a", func)

        g = Global(store, GlobalType(ValType.i32(), False), Val.i32(0))
        linker.define(store, "", "c", g)

        mem = Memory(store, MemoryType(Limits(1, None)))
        linker.define(store, "", "e", mem)

        module = Module(store.engine, """
            (module (table (export "") 1 funcref))
        """)
        table = Instance(store, module, []).exports(store).by_index[0]
        linker.define(store, "", "g", table)

        with self.assertRaises(WasmtimeError):
            linker.define(store, "", "a", func)
        linker.allow_shadowing = True
        linker.define(store, "", "a", func)

        with self.assertRaises(TypeError):
            linker.define(store, "", "", 2)  # type: ignore
        with self.assertRaises(AttributeError):
            linker.define(store, 2, "", func)  # type: ignore
        with self.assertRaises(AttributeError):
            linker.define(store, "", 2, func)  # type: ignore

    def test_define_instance(self):
        store = Store()
        linker = Linker(store.engine)
        with self.assertRaises(TypeError):
            linker.define_instance("x", 2)  # type: ignore

        module = Module(store.engine, "(module)")
        linker.define_instance(store, "a", Instance(store, module, []))

        module = Module(store.engine, "(module (func (export \"foo\")))")
        instance = Instance(store, module, [])
        linker.define_instance(store, "b", instance)
        with self.assertRaises(WasmtimeError):
            linker.define_instance(store, "b", instance)
        linker.allow_shadowing = True
        linker.define_instance(store, "b", instance)

    def test_define_wasi(self):
        linker = Linker(Engine())
        linker.define_wasi()

    def test_instantiate(self):
        store = Store()
        linker = Linker(store.engine)

        module = Module(store.engine, "(module (func (export \"foo\")))")
        instance = Instance(store, module, [])
        linker.define_instance(store, "x", instance)

        func = Func(store, FuncType([], []), lambda: None)
        linker.define(store, "y", "z", func)

        module = Module(store.engine, """
            (module
                (import "x" "foo" (func))
                (import "y" "z" (func))
            )
        """)
        linker.instantiate(store, module)

        module = Module(store.engine, """
            (module
                (import "x" "foo" (func))
                (import "y" "z" (global i32))
            )
        """)
        with self.assertRaises(WasmtimeError):
            linker.instantiate(store, module)

        module = Module(store.engine, """
            (module
                (func unreachable)
                (start 0)
            )
        """)
        with self.assertRaises(Trap):
            linker.instantiate(store, module)

        module = Module(store.engine, "(module)")
        linker.instantiate(store, module)

    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):
            linker.instantiate(Store(), 3)  # type: ignore

    def test_module(self):
        store = Store()
        linker = Linker(store.engine)
        module = Module(store.engine, """
            (module
                (func (export "f"))
            )
        """)
        linker.define_module(store, "foo", module)
        module = Module(store.engine, """
            (module
                (import "foo" "f" (func))
            )
        """)
        linker.instantiate(store, module)

    def test_get_default(self):
        store = Store()
        linker = Linker(store.engine)
        linker.get_default(store, "foo")(store)

    def test_get_one_by_name(self):
        store = Store()
        linker = Linker(store.engine)
        with self.assertRaises(WasmtimeError):
            linker.get(store, "foo", "bar")
        module = Module(store.engine, """
            (module
                (func (export "f"))
            )
        """)
        linker.define_module(store, "foo", module)
        assert(isinstance(linker.get(store, "foo", "f"), Func))

    def test_define_func(self):
        engine = Engine()
        linker = Linker(engine)
        called = {}
        called['hits'] = 0

        def call():
            called['hits'] += 1

        linker.define_func('a', 'b', FuncType([], []), call)
        module = Module(engine, """
            (module
                (import "a" "b" (func))
                (start 0)
            )
        """)
        assert(called['hits'] == 0)
        linker.instantiate(Store(engine), module)
        assert(called['hits'] == 1)
        linker.instantiate(Store(engine), module)
        assert(called['hits'] == 2)

</document_content>
</document>
<document index="8">
<source>./test_memory.py</source>
<document_content>
import unittest

from wasmtime import *


class TestMemory(unittest.TestCase):
    def test_new(self):
        store = Store()
        ty = MemoryType(Limits(1, None))
        assert(not ty.is_64)
        memory = Memory(store, ty)
        self.assertEqual(memory.type(store).limits, Limits(1, None))
        self.assertEqual(memory.size(store), 1)
        self.assertTrue(memory.grow(store, 1))
        self.assertEqual(memory.size(store), 2)
        self.assertTrue(memory.grow(store, 0))
        self.assertEqual(memory.size(store), 2)
        with self.assertRaises(TypeError):
            memory.grow(store, '')  # type: ignore
        with self.assertRaises(WasmtimeError):
            memory.grow(store, -1)
        self.assertEqual(memory.data_ptr(store)[0], 0)
        self.assertEqual(memory.data_len(store), 65536 * 2)
        self.assertTrue(isinstance(memory.type(store), MemoryType))

    def test_grow(self):
        store = Store()
        ty = MemoryType(Limits(1, 2))
        memory = Memory(store, ty)
        assert(memory.grow(store, 1) == 1)
        assert(memory.grow(store, 0) == 2)
        with self.assertRaises(WasmtimeError):
            memory.grow(store, 1)

    def test_errors(self):
        store = Store()
        ty = MemoryType(Limits(1, 2))
        with self.assertRaises(AttributeError):
            Memory(1, ty)  # type: ignore
        with self.assertRaises(AttributeError):
            Memory(store, 1)  # type: ignore

    def test_large(self):
        ty = MemoryType(Limits(0x100000000, None), is_64=True)
        assert(ty.limits.min == 0x100000000)
        assert(ty.limits.max is None)
        assert(ty.is_64)
        ty = MemoryType(Limits(0x100000000, 0x100000000), is_64=True)
        assert(ty.limits.min == 0x100000000)
        assert(ty.limits.max == 0x100000000)

        with self.assertRaises(WasmtimeError):
            MemoryType(Limits(0x100000000, None))
        with self.assertRaises(WasmtimeError):
            MemoryType(Limits(1, 0x100000000))

    def test_slices(self):
        store = Store()
        ty = MemoryType(Limits(1, None))
        memory = Memory(store, ty)
        memory.grow(store, 2)
        data_ptr = memory.data_ptr(store)
        ba = bytearray([i for i in range(200)])
        size_bytes = memory.data_len(store)
        # happy cases
        offset = 2048
        ba_size = len(ba)
        # write with start and ommit stop
        memory.write(store, ba, offset)
        # check write success byte by byte, whole is asserted with read
        self.assertEqual(data_ptr[offset], 0)
        self.assertEqual(data_ptr[offset + 1], 1)
        self.assertEqual(data_ptr[offset + 199], 199)
        # read while and assert whole area
        out = memory.read(store, offset, offset + ba_size)
        self.assertEqual(ba, out)
        self.assertEqual(len(memory.read(store, -10)), 10)
        # write with start and stop
        memory.write(store, ba, offset + ba_size)
        out = memory.read(store, offset + ba_size, offset + ba_size + ba_size)
        self.assertEqual(ba, out)
        # assert old
        self.assertEqual(data_ptr[offset], 0)
        self.assertEqual(data_ptr[offset + 1], 1)
        self.assertEqual(data_ptr[offset + 199], 199)
        # assert new
        self.assertEqual(data_ptr[offset + ba_size], 0)
        self.assertEqual(data_ptr[offset + ba_size + 1], 1)
        self.assertEqual(data_ptr[offset + ba_size + 199], 199)
        # edge cases
        # empty slices
        self.assertEqual(len(memory.read(store, 0, 0)), 0)
        self.assertEqual(len(memory.read(store, offset, offset)), 0)
        self.assertEqual(len(memory.read(store, offset, offset - 1)), 0)
        # out of bound access returns empty array similar to list slice
        self.assertEqual(len(memory.read(store, size_bytes + 1)), 0)
        # write empty
        self.assertEqual(memory.write(store, bytearray(0), offset), 0)
        self.assertEqual(memory.write(store, bytearray(b""), offset), 0)
        with self.assertRaises(IndexError):
            memory.write(store, ba, size_bytes)
        with self.assertRaises(IndexError):
            memory.write(store, ba, size_bytes - ba_size + 1)
        self.assertEqual(memory.write(store, ba, -ba_size), ba_size)
        out = memory.read(store, -ba_size)
        self.assertEqual(ba, out)

</document_content>
</document>
<document index="9">
<source>./test_module.py</source>
<document_content>
import unittest
import tempfile

from wasmtime import *


class TestModule(unittest.TestCase):
    def test_smoke(self):
        Module(Engine(), '(module)')
        Module(Engine(), bytes(b'\0asm\x01\0\0\0'))
        Module(Engine(), bytearray(b'\0asm\x01\0\0\0'))

    def test_invalid(self):
        with self.assertRaises(AttributeError):
            Module.validate(1, b'')  # type: ignore
        with self.assertRaises(TypeError):
            Module.validate(Store(), 2)  # type: ignore
        with self.assertRaises(TypeError):
            Module(1, b'')  # type: ignore
        with self.assertRaises(TypeError):
            Module(Engine(), 2)  # type: ignore
        with self.assertRaises(WasmtimeError):
            Module(Engine(), b'')
        with self.assertRaises(WasmtimeError):
            Module(Engine(), b'\x00')

    def test_validate(self):
        engine = Engine()
        Module.validate(engine, b'\0asm\x01\0\0\0')
        with self.assertRaises(WasmtimeError):
            Module.validate(engine, b'')

    def test_imports(self):
        store = Store()
        module = Module(store.engine, '(module)')
        self.assertEqual(module.imports, [])

        module = Module(store.engine, """
            (module
                (import "" "" (func))
                (import "a" "bcd" (global i32))
                (import "" "" (memory 1))
                (import "" "x" (table 1 funcref))
            )
        """)
        imports = module.imports
        self.assertEqual(len(imports), 4)
        self.assertEqual(imports[0].module, "")
        self.assertEqual(imports[0].name, "")
        ty = imports[0].type
        assert(isinstance(ty, FuncType))
        self.assertEqual(ty.params, [])
        self.assertEqual(ty.results, [])

        self.assertEqual(imports[1].module, "a")
        self.assertEqual(imports[1].name, "bcd")
        ty = imports[1].type
        assert(isinstance(ty, GlobalType))
        self.assertEqual(ty.content, ValType.i32())
        self.assertFalse(ty.mutable)

        self.assertEqual(imports[2].module, "")
        self.assertEqual(imports[2].name, "")
        ty = imports[2].type
        assert(isinstance(ty, MemoryType))
        self.assertEqual(ty.limits, Limits(1, None))

        self.assertEqual(imports[3].module, "")
        self.assertEqual(imports[3].name, "x")
        ty = imports[3].type
        assert(isinstance(ty, TableType))
        self.assertEqual(ty.limits, Limits(1, None))
        self.assertEqual(ty.element, ValType.funcref())

    def test_exports(self):
        store = Store()
        module = Module(store.engine, '(module)')
        self.assertEqual(module.exports, [])

        module = Module(store.engine, """
            (module
                (func (export "a") (param i32 f32) (result f64)
                    f64.const 0)
                (global (export "") (mut i32) (i32.const 1))
                (memory (export "mem") 1)
                (table (export "table") 1 funcref)
            )
        """)
        exports = module.exports
        self.assertEqual(len(exports), 4)
        self.assertEqual(exports[0].name, "a")
        ty = exports[0].type
        assert(isinstance(ty, FuncType))
        self.assertEqual(ty.params, [ValType.i32(), ValType.f32()])
        self.assertEqual(ty.results, [ValType.f64()])

        self.assertEqual(exports[1].name, "")
        ty = exports[1].type
        assert(isinstance(ty, GlobalType))
        self.assertEqual(ty.content, ValType.i32())
        self.assertTrue(ty.mutable)

        self.assertEqual(exports[2].name, "mem")
        ty = exports[2].type
        assert(isinstance(ty, MemoryType))
        self.assertEqual(ty.limits, Limits(1, None))

        self.assertEqual(exports[3].name, "table")
        ty = exports[3].type
        assert(isinstance(ty, TableType))
        self.assertEqual(ty.limits, Limits(1, None))
        self.assertEqual(ty.element, ValType.funcref())

    def test_serialize(self):
        engine = Engine()
        module = Module(engine, '(module)')
        encoded = module.serialize()
        module = Module.deserialize(engine, encoded)
        assert(len(module.imports) == 0)
        assert(len(module.exports) == 0)
        with tempfile.TemporaryDirectory() as d:
            path = d + '/module.bin'
            with open(path, 'wb') as f:
                f.write(encoded)
            module = Module.deserialize_file(engine, path)
            assert(len(module.imports) == 0)
            assert(len(module.exports) == 0)

            # Run the destructor for `Module` which has an mmap to the file
            # which prevents deletion on Windows.
            del module

</document_content>
</document>
<document index="10">
<source>./test_refs.py</source>
<document_content>
import unittest
from typing import cast

from wasmtime import *


def ref_types_store():
    config = Config()
    config.wasm_reference_types = True
    engine = Engine(config)
    return Store(engine)


def compile_and_instantiate(wat):
    store = ref_types_store()
    module = Module(store.engine, wat)
    return (Instance(store, module, []), store)


class SetHitOnDrop:
    def __init__(self, obj):
        obj['hit'] = False
        self.obj = obj

    def __del__(self):
        self.obj['hit'] = True


class TestExternRef(unittest.TestCase):
    def test_smoke(self):
        (instance, store) = compile_and_instantiate(
            """
            (module
                 (func (export "f") (param externref) (result externref)
                     local.get 0
                 )
                 (func (export "null_externref") (result externref)
                     ref.null extern
                 )
            )
            """
        )

        null_externref = instance.exports(store).get("null_externref")
        self.assertEqual(null_externref(store), None)

        f = instance.exports(store).get("f")
        externs = [42, True, False, None, "Hello", {"x": 1}, [12, 13, 14], Config()]

        for extern in externs:
            # We can create an externref for the given extern data.
            ref = Val.externref(extern)

            # And the externref's value is our extern data.
            self.assertEqual(ref.value, extern)

            # And we can round trip the externref through Wasm and still get our
            # extern data.
            result = f(store, ref)
            self.assertEqual(result, extern)

    def test_int_to_externref(self):
        wat = """
            (module
                 (import "env" "int_to_ref" (func $int_to_ref (param $a externref) (result externref)))
                 (export "test" (func $int_to_ref))
            )
            """
        config = Config()
        config.wasm_reference_types = True
        engine = Engine(config)
        store = Store(engine)
        module = Module(store.engine, wat)
        linker = Linker(engine)
        ftype = FuncType([ValType.externref()], [ValType.externref()])
        linker.define_func("env", "int_to_ref", ftype, lambda x: x)
        instance = linker.instantiate(store, module)
        f: Func
        f = cast(Func, instance.exports(store).get("test"))
        f(store, 5)
        f = cast(Func, instance.exports(store).get("test"))
        f(store, 5.7)

    def test_externref_tables(self):
        store = ref_types_store()
        ty = TableType(ValType.externref(), Limits(10, None))
        table = Table(store, ty, "init")

        for i in range(0, 10):
            self.assertEqual(table.get(store, i), "init")

        table.grow(store, 2, "grown")

        for i in range(0, 10):
            self.assertEqual(table.get(store, i), "init")
        for i in range(10, 12):
            self.assertEqual(table.get(store, i), "grown")

        table.set(store, 7, "lucky")

        for i in range(0, 7):
            self.assertEqual(table.get(store, i), "init")
        self.assertEqual(table.get(store, 7), "lucky")
        for i in range(8, 10):
            self.assertEqual(table.get(store, i), "init")
        for i in range(10, 12):
            self.assertEqual(table.get(store, i), "grown")

    def test_externref_in_global(self):
        store = ref_types_store()
        ty = GlobalType(ValType.externref(), True)
        g = Global(store, ty, Val.externref("hello"))
        self.assertEqual(g.value(store), "hello")
        g.set_value(store, "goodbye")
        self.assertEqual(g.value(store), "goodbye")

    def test_dtor_global(self):
        obj = {}  # type: ignore
        store = ref_types_store()
        ty = GlobalType(ValType.externref(), True)
        g = Global(store, ty, Val.externref(SetHitOnDrop(obj)))
        assert(not obj['hit'])
        g.set_value(store, None)
        assert(obj['hit'])

    def test_dtor_func(self):
        (instance, store) = compile_and_instantiate(
            """
            (module
                 (func (export "f") (param externref))
            )
            """
        )

        f = instance.exports(store).get("f")
        obj = {}  # type: ignore
        f(store, SetHitOnDrop(obj))
        store.gc()
        assert(obj['hit'])


class TestFuncRef(unittest.TestCase):
    def test_smoke(self):
        (instance, store) = compile_and_instantiate(
            """
            (module
                 (func (export \"f\") (param funcref) (result funcref)
                     local.get 0
                 )
                 (func (export "null_funcref") (result funcref)
                     ref.null func
                 )
            )
            """
        )

        null_funcref = instance.exports(store).get("null_funcref")
        self.assertEqual(null_funcref(store), None)

        f = instance.exports(store).get("f")

        ty = FuncType([], [ValType.i32()])
        g = Func(store, ty, lambda: 42)

        # We can create a funcref.
        ref_g_val = Val.funcref(g)

        # And the funcref's points to `g`.
        g2 = ref_g_val.as_funcref()
        if isinstance(g2, Func):
            self.assertEqual(g2(store), 42)
        else:
            self.fail("g2 is not a funcref: g2 = %r" % g2)

        # And we can round trip the funcref through Wasm.
        g3 = f(store, ref_g_val)
        if isinstance(g3, Func):
            self.assertEqual(g3(store), 42)
        else:
            self.fail("g3 is not a funcref: g3 = %r" % g3)

</document_content>
</document>
<document index="11">
<source>./test_store.py</source>
<document_content>
import unittest

from wasmtime import *


class TestStore(unittest.TestCase):
    def test_smoke(self):
        Store()
        Store(Engine())

        with Store() as store:
            pass

        store = Store()
        store.close()
        store.close()
        with self.assertRaises(ValueError):
            store.set_epoch_deadline(1)

    def test_errors(self):
        with self.assertRaises(TypeError):
            Store(3)  # type: ignore

    def test_interrupt_handle(self):
        config = Config()
        config.epoch_interruption = True
        engine = Engine(config)
        engine.increment_epoch()
        store = Store(engine)
        store.set_epoch_deadline(1)

    def test_interrupt_wasm(self):
        config = Config()
        config.epoch_interruption = True
        engine = Engine(config)
        store = Store(engine)
        store.set_epoch_deadline(1)

        module = Module(store.engine, """
            (import "" "hit" (func $hit))
            (import "" "interrupt" (func $interrupt))
            (func $start
                call $hit
                call $interrupt
                (loop br 0))
            (start $start)
        """)
        interrupt = Func(store, FuncType([], []), lambda: engine.increment_epoch())

        was_hit = False

        def hit_callback():
            nonlocal was_hit
            was_hit = True
        hit = Func(store, FuncType([], []), hit_callback)

        with self.assertRaises(Trap):
            Instance(store, module, [hit, interrupt])
        self.assertTrue(was_hit)

    def test_fuel(self):
        store = Store()

        with self.assertRaises(WasmtimeError):
            store.set_fuel(1)
        with self.assertRaises(WasmtimeError):
            store.get_fuel()

        config = Config()
        config.consume_fuel = True
        store = Store(Engine(config))
        store.set_fuel(1)
        assert(store.get_fuel() == 1)
        store.set_fuel(2)
        assert(store.get_fuel() == 2)
        store.set_fuel(0)
        assert(store.get_fuel() == 0)

    def test_limits(self):
        store = Store()
        Memory(store, MemoryType(Limits(1, None)))

        store = Store()
        store.set_limits(memory_size=0)
        with self.assertRaises(WasmtimeError):
            Memory(store, MemoryType(Limits(1, None)))
        store.set_limits(memory_size=100000)
        Memory(store, MemoryType(Limits(1, None)))

        store = Store()
        store.set_limits(table_elements=1)
        Table(store, TableType(ValType.funcref(), Limits(1, None)), None)
        with self.assertRaises(WasmtimeError):
            Table(store, TableType(ValType.funcref(), Limits(2, None)), None)

        store = Store()
        store.set_limits(memory_size=200000)
        mem = Memory(store, MemoryType(Limits(1, None)))
        mem.grow(store, 1)
        with self.assertRaises(WasmtimeError):
            mem.grow(store, 100)

</document_content>
</document>
<document index="12">
<source>./test_table.py</source>
<document_content>
import unittest

from wasmtime import *


class TestTable(unittest.TestCase):
    def test_new(self):
        store = Store()
        module = Module(store.engine, """
            (module (table (export "") 1 funcref))
        """)
        table = Instance(store, module, []).exports(store).by_index[0]
        assert(isinstance(table, Table))
        assert(isinstance(table.type(store), TableType))
        self.assertEqual(table.type(store).limits, Limits(1, None))
        self.assertEqual(table.size(store), 1)

        ty = TableType(ValType.funcref(), Limits(1, 2))
        store = Store()
        func = Func(store, FuncType([], []), lambda: {})
        Table(store, ty, func)

    def test_grow(self):
        ty = TableType(ValType.funcref(), Limits(1, 2))
        store = Store()
        table = Table(store, ty, None)
        self.assertEqual(table.size(store), 1)

        # type errors
        with self.assertRaises(TypeError):
            table.grow(store, 'x', None)  # type: ignore
        with self.assertRaises(TypeError):
            table.grow(store, 2, 'x')

        # growth works
        table.grow(store, 1, None)
        self.assertEqual(table.size(store), 2)

        # can't grow beyond max
        with self.assertRaises(WasmtimeError):
            table.grow(store, 1, None)

    def test_get(self):
        ty = TableType(ValType.funcref(), Limits(1, 2))
        store = Store()
        table = Table(store, ty, None)
        self.assertEqual(table.get(store, 0), None)
        self.assertEqual(table.get(store, 1), None)

        called = {}
        called['hit'] = False

        def set_called():
            called['hit'] = True
        func = Func(store, FuncType([], []), set_called)
        table.grow(store, 1, func)
        assert(not called['hit'])
        f = table.get(store, 1)
        assert(isinstance(f, Func))
        f(store)
        assert(called['hit'])

    def test_set(self):
        ty = TableType(ValType.funcref(), Limits(1, 2))
        store = Store()
        table = Table(store, ty, None)
        func = Func(store, FuncType([], []), lambda: {})
        table.set(store, 0, func)
        with self.assertRaises(WasmtimeError):
            table.set(store, 1, func)

</document_content>
</document>
<document index="13">
<source>./test_trap.py</source>
<document_content>
import unittest

from wasmtime import *


class TestTrap(unittest.TestCase):
    def test_new(self):
        trap = Trap('x')
        self.assertEqual(trap.message, u'x')

    def test_frames(self):
        store = Store()
        module = Module(store.engine, """
            (module $module
                (func (export "init")
                    call $foo)
                (func $foo
                    call $bar)
                (func $bar
                    unreachable)
            )
        """)
        i = Instance(store, module, [])
        with self.assertRaises(Trap) as exn:
            e = i.exports(store).by_index[0]
            assert(isinstance(e, Func))
            e(store)
        trap = exn.exception

        frames = trap.frames
        self.assertEqual(len(frames), 3)
        self.assertEqual(frames[0].func_index, 2)
        self.assertEqual(frames[1].func_index, 1)
        self.assertEqual(frames[2].func_index, 0)

        self.assertEqual(frames[0].func_name, 'bar')
        self.assertEqual(frames[1].func_name, 'foo')
        self.assertEqual(frames[2].func_name, None)

        self.assertEqual(frames[0].module_name, 'module')
        self.assertEqual(frames[1].module_name, 'module')
        self.assertEqual(frames[2].module_name, 'module')

        self.assertEqual(str(trap), """\
error while executing at wasm backtrace:
    0:   0x2d - module!bar
    1:   0x28 - module!foo
    2:   0x23 - module!<wasm function 0>

Caused by:
    wasm trap: wasm `unreachable` instruction executed\
""")
        self.assertEqual(trap.trap_code, TrapCode.UNREACHABLE)

    def test_frames_no_module(self):
        store = Store()
        module = Module(store.engine, """
            (module
                (func (export "init") unreachable)
            )
        """)
        i = Instance(store, module, [])
        with self.assertRaises(Trap) as exn:
            e = i.exports(store).by_index[0]
            assert(isinstance(e, Func))
            e(store)
        trap = exn.exception

        frames = trap.frames
        self.assertEqual(len(frames), 1)
        self.assertEqual(frames[0].func_index, 0)
        self.assertEqual(frames[0].func_name, None)
        self.assertEqual(frames[0].module_name, None)

    def test_wasi_exit(self):
        linker = Linker(Engine())
        linker.define_wasi()
        module = Module(linker.engine, """
            (module
                (import "wasi_snapshot_preview1" "proc_exit" (func $exit (param i32)))
                (memory (export "memory") 1)
                (func (export "exit") (param i32)
                    local.get 0
                    call $exit)
            )
        """)
        store = Store(linker.engine)
        store.set_wasi(WasiConfig())
        instance = linker.instantiate(store, module)
        exit = instance.exports(store)["exit"]
        assert(isinstance(exit, Func))

        with self.assertRaises(ExitTrap) as exn:
            exit(store, 0)
        self.assertEqual(exn.exception.code, 0)
        self.assertRegex(str(exn.exception), 'Exited with i32 exit status 0')

        with self.assertRaises(ExitTrap) as exn:
            exit(store, 1)
        self.assertEqual(exn.exception.code, 1)

</document_content>
</document>
<document index="14">
<source>./test_types.py</source>
<document_content>
import unittest

from wasmtime import FuncType, ValType


class TestTypes(unittest.TestCase):
    def test_valtypes(self):
        ValType.i32()
        ValType.i64()
        ValType.f32()
        ValType.f64()

    def test_new(self):
        FuncType([], [])
        FuncType([ValType.i32()], [ValType.i64()])

</document_content>
</document>
<document index="15">
<source>./test_value.py</source>
<document_content>
import unittest

from wasmtime import *


class TestValue(unittest.TestCase):
    def test_i32(self):
        with self.assertRaises(TypeError):
            Val.i32('')  # type: ignore
        with self.assertRaises(TypeError):
            Val.i32(1.2)  # type: ignore

        i = Val.i32(1)
        self.assertEqual(i.as_i32(), 1)
        i = Val.i32(0xffffffff)
        self.assertEqual(i.as_i32(), -1)
        i = Val.i32(0x800000000)
        self.assertEqual(i.as_i32(), 0)

        self.assertEqual(None, i.as_i64())
        self.assertEqual(None, i.as_f32())
        self.assertEqual(None, i.as_f64())
        self.assertEqual(i.type, ValType.i32())

    def test_i64(self):
        with self.assertRaises(TypeError):
            Val.i64('')  # type: ignore
        with self.assertRaises(TypeError):
            Val.i64(1.2)  # type: ignore

        i = Val.i64(1)
        self.assertEqual(i.as_i64(), 1)
        i = Val.i64(0xffffffff)
        self.assertEqual(i.as_i64(), 0xffffffff)
        i = Val.i64(0x800000000)
        self.assertEqual(i.as_i64(), 0x800000000)
        i = Val.i64(0xffffffffffffffff)
        self.assertEqual(i.as_i64(), -1)
        i = Val.i64(0x80000000000000000)
        self.assertEqual(i.as_i64(), 0)

        self.assertEqual(None, i.as_i32())
        self.assertEqual(None, i.as_f32())
        self.assertEqual(None, i.as_f64())
        self.assertEqual(i.type, ValType.i64())

    def test_f32(self):
        with self.assertRaises(TypeError):
            Val.f32('')  # type: ignore
        with self.assertRaises(TypeError):
            Val.f32(1)

        i = Val.f32(1.0)
        self.assertEqual(i.as_f32(), 1.0)
        self.assertEqual(None, i.as_i64())
        self.assertEqual(None, i.as_i32())
        self.assertEqual(None, i.as_f64())
        self.assertEqual(i.type, ValType.f32())

    def test_f64(self):
        with self.assertRaises(TypeError):
            Val.f64('')  # type: ignore
        with self.assertRaises(TypeError):
            Val.f64(1)

        i = Val.f64(1.0)
        self.assertEqual(i.as_f64(), 1.0)
        self.assertEqual(None, i.as_i32())
        self.assertEqual(None, i.as_i64())
        self.assertEqual(None, i.as_f32())
        self.assertEqual(i.type, ValType.f64())

</document_content>
</document>
<document index="16">
<source>./test_wasi.py</source>
<document_content>
import unittest
import tempfile

from wasmtime import *
from pathlib import Path


class TestWasi(unittest.TestCase):
    def test_config(self):
        config = WasiConfig()
        config.argv = ['a', 'b']
        config.inherit_argv()
        config.env = [['a', 'b']]
        config.inherit_env()

        with tempfile.NamedTemporaryFile() as f:
            config.stdin_file = f.name
            config.stdin_file = Path(f.name)
            config.inherit_stdin()
            config.stdout_file = f.name
            config.stdout_file = Path(f.name)
            config.inherit_stdout()
            config.stderr_file = f.name
            config.stderr_file = Path(f.name)
            config.inherit_stderr()

        with self.assertRaises(WasmtimeError):
            config.stdin_file = 'somewhere-over-the-rainboat'
        with self.assertRaises(WasmtimeError):
            config.stdout_file = 'some-directory/without-a-rainbow'
        with self.assertRaises(WasmtimeError):
            config.stderr_file = 'some-directory/without-a-rainbow'
        config.preopen_dir('wasmtime', 'other')

    def test_preview1(self):
        linker = Linker(Engine())
        linker.define_wasi()

        module = Module(linker.engine, """
            (module
                (import "wasi_snapshot_preview1" "random_get"
                    (func (param i32 i32) (result i32)))
            )
        """)

        store = Store(linker.engine)
        store.set_wasi(WasiConfig())
        linker.instantiate(store, module)

    def preopen_nonexistent(self):
        config = WasiConfig()
        with self.assertRaises(WasmtimeError):
            config.preopen_dir('/path/to/nowhere', '/')

</document_content>
</document>
<document index="17">
<source>./test_wat2wasm.py</source>
<document_content>
import unittest

from wasmtime import *


class TestWat2Wasm(unittest.TestCase):
    def test_wat2wasm(self):
        wasm = wat2wasm('(module)')
        self.assertEqual(wasm, b'\0asm\x01\0\0\0')

    def test_errors(self):
        with self.assertRaises(WasmtimeError):
            wat2wasm('x')

</document_content>
</document>
<document index="18">
<source>./codegen/__init__.py</source>
<document_content>
# The `codegen` directory here is intended to test the bindings generator for
# components in Python. Each file represents a distinct test where an input
# wasm file is bound and then the generated bindings are imported dynamically.
#
# This structure is done so a general `pytest` will execute everything,
# generating bindings during test collection and otherwise setting up everything
# to be naturally checked with mypy and other tests configured.

from wasmtime import wat2wasm
from wasmtime.bindgen import generate
from pathlib import Path
import os


# Helper function to generate bindings for the `wat` specified into the
# `generated` sub-folder. After calling this method the bindings can be
# imported with:
#
#   from .generated.name import Name
#
# and then used to type-check everything.
def bindgen(name: str, wat: str) -> None:
    files = generate(name, wat2wasm(wat))
    root = Path(__file__).parent.joinpath('generated')
    dst = root.joinpath(name)
    for name, contents in files.items():
        # If the file already has the desired contents then skip writing. This
        # is an attempt to fix CI issues on windows.
        file = dst.joinpath(name)
        if file.exists():
            with open(file, 'rb') as f:
                if f.read() == contents:
                    continue

        # Write the contents to a temporary file and then attempt to atomically
        # replace the previous file, if any, with the new contents. This
        # is done to hopefully fix an apparent issue in `pytest` where it seems
        # that there are multiple threads of the python interpreter, perhaps for
        # pytest itself, mypy, and flake8, and overwriting files in-place causes
        # issues are partial files may be seen.
        tmp_file = file.with_suffix('.tmp')
        if not file.parent.exists():
            file.parent.mkdir(parents=True)
        tmp_file.write_bytes(contents)
        os.replace(tmp_file, file)


REALLOC = """
    (global $last (mut i32) (i32.const 1000))
    (func $realloc (export "realloc")
        (param $old_ptr i32)
        (param $old_size i32)
        (param $align i32)
        (param $new_size i32)
        (result i32)

        (local $ret i32)

        ;; Test if the old pointer is non-null
        local.get $old_ptr
        if
            ;; If the old size is bigger than the new size then
            ;; this is a shrink and transparently allow it
            local.get $old_size
            local.get $new_size
            i32.gt_u
            if
                local.get $old_ptr
                return
            end

            ;; otherwise fall through to allocate a new chunk which will later
            ;; copy data over
        end

        ;; align up `$last`
        (global.set $last
            (i32.and
                (i32.add
                    (global.get $last)
                    (i32.add
                        (local.get $align)
                        (i32.const -1)))
                (i32.xor
                    (i32.add
                        (local.get $align)
                        (i32.const -1))
                    (i32.const -1))))

        ;; save the current value of `$last` as the return value
        global.get $last
        local.set $ret

        ;; bump our pointer
        (global.set $last
            (i32.add
                (global.get $last)
                (local.get $new_size)))

        ;; while `memory.size` is less than `$last`, grow memory
        ;; by one page
        (loop $loop
            (if
                (i32.lt_u
                    (i32.mul (memory.size) (i32.const 65536))
                    (global.get $last))
                (then
                    i32.const 1
                    memory.grow
                    ;; test to make sure growth succeeded
                    i32.const -1
                    i32.eq
                    if unreachable end

                    br $loop)))


        ;; ensure anything necessary is set to valid data by spraying a bit
        ;; pattern that is invalid
        local.get $ret
        i32.const 0xde
        local.get $new_size
        memory.fill

        ;; If the old pointer is present then that means this was a reallocation
        ;; of an existing chunk which means the existing data must be copied.
        local.get $old_ptr
        if
            local.get $ret          ;; destination
            local.get $old_ptr      ;; source
            local.get $old_size     ;; size
            memory.copy
        end

        local.get $ret
    )
"""

</document_content>
</document>
<document index="19">
<source>./codegen/test_bare_funcs.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (import "foo-import" (func $foo-import (param "a" s32) (result s32)))

        (core func $foo-import-lowered (canon lower (func $foo-import)))

        (core module $m
            (import "" "foo" (func $foo (param i32) (result i32)))

            (func (export "foo") (param i32) (result i32)
                (call $foo (local.get 0))
            )
        )

        (core instance $i (instantiate $m
            (with "" (instance
                (export "foo" (func $foo-import-lowered))
            ))
        ))

        (func $foo-export-lifted (param "a" s32) (result s32) (canon lift (core func $i "foo")))

        (export "foo-export" (func $foo-export-lifted))
    )
"""
bindgen('bare_funcs', module)

from .generated.bare_funcs import Root, RootImports, imports


class Host(imports.Host):
    def foo_import(self, a):
        return a + 1


def test_bindings():
    store = Store()
    bindings = Root(store, RootImports(host=Host()))
    assert 101 == bindings.foo_export(store, 100)

</document_content>
</document>
<document index="20">
<source>./codegen/test_empty.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component)
"""
bindgen('empty', module)

from .generated.empty import Root


def test_bindings(tmp_path):
    Root(Store())

</document_content>
</document>
<document index="21">
<source>./codegen/test_empty_import.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (import "host" (instance))
    )
"""
bindgen('empty_import', module)

from .generated.empty_import import Root
from .generated.empty_import.imports import RootImports


def test_bindings(tmp_path) -> None:
    Root(Store(), RootImports(host={}))

</document_content>
</document>
<document index="22">
<source>./codegen/test_export_resources.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
(component
  (core module $core-mod
    (import "[export]component:basicresource/my-interface-name" "[resource-drop]demo-resource-class" (func $resource-drop (param i32)))
    (import "[export]component:basicresource/my-interface-name" "[resource-new]demo-resource-class" (func $resource-new (param i32) (result i32)))
    (import "[export]component:basicresource/my-interface-name" "[resource-rep]demo-resource-class" (func $resource-rep (param i32) (result i32)))
    (func $core-create-demo-resource (param i32 i32) (result i32)
      unreachable
    )
    (func $core-demo-resource-greet (param i32 i32 i32) (result i32)
      unreachable
    )
    (func $core-cabi-realloc (param i32 i32 i32 i32) (result i32)
      unreachable
    )
    (memory (;0;) 0)
    (export "component:basicresource/my-interface-name#[constructor]demo-resource-class" (func $core-create-demo-resource))
    (export "component:basicresource/my-interface-name#[method]demo-resource-class.greet" (func $core-demo-resource-greet))
    (export "memory" (memory 0))
    (export "cabi_realloc" (func $core-cabi-realloc))
  )
  (type $demo-resource-type (resource (rep i32)))
  (core func $core-resource-drop (canon resource.drop $demo-resource-type))
  (core func $core-resource-rep (canon resource.rep $demo-resource-type))
  (core func $core-resource-new (canon resource.new $demo-resource-type))
  (core instance $canon-instance
    (export "[resource-drop]demo-resource-class" (func $core-resource-drop))
    (export "[resource-new]demo-resource-class" (func $core-resource-new))
    (export "[resource-rep]demo-resource-class" (func $core-resource-rep))
  )
  (core instance $core-instance (instantiate $core-mod
      (with "[export]component:basicresource/my-interface-name" (instance $canon-instance))
    )
  )
  (alias core export $core-instance "memory" (core memory (;0;)))
  (alias core export $core-instance "cabi_realloc" (core func $cabi-realloc))
  (type $constructor-type (func (param "name" string) (result (own $demo-resource-type))))
  (alias core export $core-instance "component:basicresource/my-interface-name#[constructor]demo-resource-class" (core func $core-constructor))
  (func $lift-demo-resource-constructor (type $constructor-type) (canon lift (core func $core-constructor) (memory 0) (realloc $cabi-realloc) string-encoding=utf8))
  (type $greet-type (func (param "self" (borrow $demo-resource-type)) (param "greeting" string) (result string)))
  (alias core export $core-instance "component:basicresource/my-interface-name#[method]demo-resource-class.greet" (core func $core-greet))
  (func $lift-demo-resource-greet (type $greet-type) (canon lift (core func $core-greet) (memory 0) (realloc $cabi-realloc) string-encoding=utf8))
  (component $comp-api
    (import "import-type-demo-resource-class" (type $demo-resource (sub resource)))
    (type $constructor-type (func (param "name" string) (result (own $demo-resource))))
    (import "import-constructor-demo-resource-class" (func $constructor-import (type $constructor-type)))
    (type $greet-type (func (param "self" (borrow $demo-resource)) (param "greeting" string) (result string)))
    (import "import-method-demo-resource-class-greet" (func $greet-import (type $greet-type)))
    (export $demo-resource-export "demo-resource-class" (type $demo-resource))
    (type $constructor-type-export (func (param "name" string) (result (own $demo-resource-export))))
    (export "[constructor]demo-resource-class" (func $constructor-import) (func (type $constructor-type-export)))
    (type $greet-type-export (func (param "self" (borrow $demo-resource-export)) (param "greeting" string) (result string)))
    (export "[method]demo-resource-class.greet" (func $greet-import) (func (type $greet-type-export)))
  )
  (instance $api-instance (instantiate $comp-api
      (with "import-constructor-demo-resource-class" (func $lift-demo-resource-constructor))
      (with "import-method-demo-resource-class-greet" (func $lift-demo-resource-greet))
      (with "import-type-demo-resource-class" (type $demo-resource-type))
    )
  )
  (export "component:basicresource/my-interface-name" (instance $api-instance))
)
"""

bindgen("export_resources", module)

from .generated.export_resources import Root
from .generated.export_resources import my_interface_name


def test_bindings():
    store = Store()
    root = Root(store)
    interface = root.my_interface_name()
    # We can't test round tripping until support for resource imports
    # is added.  For now, we can check that the structure of the
    # generated code looks right.
    assert hasattr(interface, "DemoResourceClass")
    assert hasattr(my_interface_name, "DemoResourceClass")
    resource_cls = my_interface_name.DemoResourceClass
    assert resource_cls.greet.__annotations__ == {
        "caller": Store,
        "greeting": str,
        "return": str,
    }

</document_content>
</document>
<document index="23">
<source>./codegen/test_external_types.py</source>
<document_content>
from . import bindgen, REALLOC
from wasmtime import Store

module = """
(component $OuterComp

   (type $types
        (instance
            (type $runtime-value (variant
                (case "id" string) (case "id2" string)))
            (export $runtime-value-export "runtime-value"
                (type (eq $runtime-value)))
        )
    )
    (import "types" (instance $types (type $types)))
    (alias export $types "runtime-value" (type $runtime-value-export))

    (import "host" (instance $inst
        (alias outer $OuterComp 1 (type $runtime-value))
        (export $export "runtime-value" (type (eq $runtime-value)))
        (export "some-fn" (func (param "v" $export) (result $export)))
    ))

    (core module $libc
        (memory (export "mem") 1)
        {}
    )
    (core instance $libc (instantiate $libc))

    (core module $mod
        (import "libc" "mem" (memory 1))
        (import "" "lowered-fn-import"
            (func $lowered-fn (param i32 i32 i32 i32)))

        (func (export "core-fn") (param i32 i32 i32) (result i32)
            (call $lowered-fn
                (local.get 0) (local.get 1) (local.get 2) (local.get 2))
            (local.get 2))
    )

    (core func $lowered-fn
        (canon lower (func $inst "some-fn") (memory $libc "mem")
            (realloc (func $libc "realloc"))))

    (core instance $inst
        (instantiate $mod
            (with "libc" (instance $libc))
            (with "" (instance
                (export "lowered-fn-import" (func $lowered-fn))
             ))
        )
    )

    (type $runtime-value (variant (case "id" string) (case "id2" string)))
    (func $lifted-core-fn (param "a" $runtime-value) (result $runtime-value)
        (canon lift (core func $inst "core-fn") (memory $libc "mem")
            (realloc (func $libc "realloc"))))

    (instance (export "e")
        (export "runtime-value" (type $runtime-value))
        (export "some-fn" (func $lifted-core-fn))
    )

)
""".format(REALLOC)
bindgen('external_types', module)

from .generated.external_types import Root, RootImports, imports
from .generated.external_types.imports import host
from .generated.external_types import e


class Host(imports.HostHost):
    def some_fn(self, v: host.RuntimeValue) -> host.RuntimeValue:
        return v


def test_bindings(tmp_path):
    store = Store()
    wasm = Root(store, RootImports(None, host=Host()))

    exports = wasm.e()
    rt_id = exports.some_fn(store, e.RuntimeValueId('1234'))
    assert rt_id == e.RuntimeValueId('1234')

</document_content>
</document>
<document index="24">
<source>./codegen/test_keywords.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (import "false" (instance $i
            (type $c1 (variant (case "break" s32) (case "class" s64) (case "true" s64)))
            (export $c1' "none" (type (eq $c1)))
            (export "as" (func (param "import" $c1') (result s64)))

            (type $r1 (record (field "else" u8) (field "not" u8) (field "except" u8)))
            (export $r1' "true" (type (eq $r1)))
            (export "lambda" (func (param "def" $r1') (result u32)))
        ))

        (core func $as (canon lower (func $i "as")))
        (core func $lambda (canon lower (func $i "lambda")))

        (core module $m
            (import "" "as" (func $as (param i32 i64) (result i64)))
            (import "" "lambda" (func $lambda (param i32 i32 i32) (result i32)))

            (func (export "await") (result i32)
                i32.const 100)

            (func (export "as") (param i32 i64) (result i64)
                (call $as (local.get 0) (local.get 1)))

            (func (export "lambda") (param i32 i32 i32) (result i32)
                (call $lambda (local.get 0) (local.get 1) (local.get 2)))
        )

        (core instance $i (instantiate $m
            (with "" (instance
                (export "as" (func $as))
                (export "lambda" (func $lambda))
            ))
        ))

        (type $c1 (variant (case "break" s32) (case "class" s64) (case "true" s64)))
        (type $r1 (record (field "else" u8) (field "not" u8) (field "except" u8)))

        (func $await-export (result u8) (canon lift (core func $i "await")))
        (func $as-export (param "import" $c1) (result s64)
            (canon lift (core func $i "as")))
        (func $lambda-export (param "def" $r1) (result u32)
            (canon lift (core func $i "lambda")))

        (instance (export "for")
            (export "none" (type $c1))
            (export "true" (type $r1))
            (export "await" (func $await-export))
            (export "as" (func $as-export))
            (export "lambda" (func $lambda-export))
        )
    )
"""
bindgen('keywords', module)

from .generated.keywords import Root, RootImports, imports
from .generated.keywords import for_
from .generated.keywords.imports import false


class Host(imports.HostFalse):
    def as_(self, import_):
        if isinstance(import_, false.None_Break):
            return import_.value + 1
        if isinstance(import_, false.None_Class):
            return import_.value + 2
        if isinstance(import_, false.None_True_):
            return import_.value + 3
        else:
            raise ValueError("Invalid input value!")

    def lambda_(self, def_):
        return def_.else_ + def_.not_ + def_.except_


def test_bindings():
    store = Store()
    bindings = Root(store, RootImports(false=Host()))
    assert 100 == bindings.for_().await_(store)
    assert 101 == bindings.for_().as_(store, for_.None_Break(100))
    assert 102 == bindings.for_().as_(store, for_.None_Class(100))
    assert 103 == bindings.for_().as_(store, for_.None_True_(100))
    assert 24 == bindings.for_().lambda_(store, for_.True_(7, 8, 9))

</document_content>
</document>
<document index="25">
<source>./codegen/test_lists.py</source>
<document_content>
from . import bindgen, REALLOC
from wasmtime import Store
from typing import List

module = """
    (component
        (import "host" (instance $i
            (export "strings" (func (param "a" string) (result string)))
            (export "bytes" (func (param "a" (list u8)) (result (list u8))))
            (export "ints" (func (param "a" (list u32)) (result (list u32))))
            (export "string-list" (func (param "a" (list string)) (result (list string))))
        ))

        (core module $libc
            (memory (export "mem") 1)
            {}
        )
        (core instance $libc (instantiate $libc))

        (core func $strings (canon lower (func $i "strings")
            (memory $libc "mem") (realloc (func $libc "realloc"))))
        (core func $bytes (canon lower (func $i "bytes")
            (memory $libc "mem") (realloc (func $libc "realloc"))))
        (core func $ints (canon lower (func $i "ints")
            (memory $libc "mem") (realloc (func $libc "realloc"))))
        (core func $string-list (canon lower (func $i "string-list")
            (memory $libc "mem") (realloc (func $libc "realloc"))))

        (core module $m
            (import "libc" "mem" (memory 1))
            (import "" "strings" (func $strings (param i32 i32 i32)))
            (import "" "bytes" (func $bytes (param i32 i32 i32)))
            (import "" "ints" (func $ints (param i32 i32 i32)))
            (import "" "string-list" (func $string-list (param i32 i32 i32)))

            (func (export "strings") (param i32 i32) (result i32)
                (call $strings (local.get 0) (local.get 1) (i32.const 8))
                i32.const 8)
            (func (export "bytes") (param i32 i32) (result i32)
                (call $bytes (local.get 0) (local.get 1) (i32.const 8))
                i32.const 8)
            (func (export "ints") (param i32 i32) (result i32)
                (call $ints (local.get 0) (local.get 1) (i32.const 8))
                i32.const 8)
            (func (export "string-list") (param i32 i32) (result i32)
                (call $string-list (local.get 0) (local.get 1) (i32.const 8))
                i32.const 8)
        )

        (core instance $i (instantiate $m
            (with "libc" (instance $libc))
            (with "" (instance
                (export "strings" (func $strings))
                (export "bytes" (func $bytes))
                (export "ints" (func $ints))
                (export "string-list" (func $string-list))
            ))
        ))

        (func (export "strings") (param "a" string) (result string)
            (canon lift (core func $i "strings")
                (memory $libc "mem") (realloc (func $libc "realloc"))))
        (func (export "bytes") (param "a" (list u8)) (result (list u8))
            (canon lift (core func $i "bytes")
                (memory $libc "mem") (realloc (func $libc "realloc"))))
        (func (export "ints") (param "a" (list u32)) (result (list u32))
            (canon lift (core func $i "ints")
                (memory $libc "mem") (realloc (func $libc "realloc"))))
        (func (export "string-list") (param "a" (list string)) (result (list string))
            (canon lift (core func $i "string-list")
                (memory $libc "mem") (realloc (func $libc "realloc"))))
    )
""".format(REALLOC)
bindgen('lists', module)

from .generated.lists import Root, RootImports, imports


class Host(imports.HostHost):
    def strings(self, a: str) -> str:
        return a

    def bytes(self, a: bytes) -> bytes:
        return a

    def ints(self, a: List[int]) -> List[int]:
        return a

    def string_list(self, a: List[str]) -> List[str]:
        return a


def test_bindings():
    store = Store()
    wasm = Root(store, RootImports(host=Host()))

    assert wasm.strings(store, '') == ''
    assert wasm.strings(store, 'a') == 'a'
    assert wasm.strings(store, 'hello world') == 'hello world'
    assert wasm.strings(store, 'hello ⚑ world') == 'hello ⚑ world'

    assert wasm.bytes(store, b'') == b''
    assert wasm.bytes(store, b'a') == b'a'
    assert wasm.bytes(store, b'\x01\x02') == b'\x01\x02'

    assert wasm.ints(store, []) == []
    assert wasm.ints(store, [1]) == [1]
    assert wasm.ints(store, [1, 2, 100, 10000]) == [1, 2, 100, 10000]

    assert wasm.string_list(store, []) == []
    assert wasm.string_list(store, ['']) == ['']
    assert wasm.string_list(store, ['a', 'b', '', 'd', 'hello']) == ['a', 'b', '', 'd', 'hello']

</document_content>
</document>
<document index="26">
<source>./codegen/test_many_arguments.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (import "host" (instance $i
            (export "many-arguments" (func
                (param "a1" u64)
                (param "a2" u64)
                (param "a3" u64)
                (param "a4" u64)
                (param "a5" u64)
                (param "a6" u64)
                (param "a7" u64)
                (param "a8" u64)
                (param "a9" u64)
                (param "a10" u64)
                (param "a11" u64)
                (param "a12" u64)
                (param "a13" u64)
                (param "a14" u64)
                (param "a15" u64)
                (param "a16" u64)
            ))
        ))
        (core module $m
            (import "" "" (func $f (param
                i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64
            )))

            (func (export "")
                (param
                    i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64
                )
                local.get 0
                local.get 1
                local.get 2
                local.get 3
                local.get 4
                local.get 5
                local.get 6
                local.get 7
                local.get 8
                local.get 9
                local.get 10
                local.get 11
                local.get 12
                local.get 13
                local.get 14
                local.get 15
                call $f
            )
        )
        (core func $f (canon lower (func $i "many-arguments")))

        (core instance $i (instantiate $m
            (with "" (instance (export "" (func $f))))
        ))

        (func (export "many-arguments")
                (param "a1" u64)
                (param "a2" u64)
                (param "a3" u64)
                (param "a4" u64)
                (param "a5" u64)
                (param "a6" u64)
                (param "a7" u64)
                (param "a8" u64)
                (param "a9" u64)
                (param "a10" u64)
                (param "a11" u64)
                (param "a12" u64)
                (param "a13" u64)
                (param "a14" u64)
                (param "a15" u64)
                (param "a16" u64)
            (canon lift (core func $i "")))
    )
"""
bindgen('many_arguments', module)

from .generated.many_arguments import Root, RootImports, imports


class MyImports(imports.HostHost):
    def many_arguments(self,
                       a1: int,
                       a2: int,
                       a3: int,
                       a4: int,
                       a5: int,
                       a6: int,
                       a7: int,
                       a8: int,
                       a9: int,
                       a10: int,
                       a11: int,
                       a12: int,
                       a13: int,
                       a14: int,
                       a15: int,
                       a16: int) -> None:
        assert(a1 == 1)
        assert(a2 == 2)
        assert(a3 == 3)
        assert(a4 == 4)
        assert(a5 == 5)
        assert(a6 == 6)
        assert(a7 == 7)
        assert(a8 == 8)
        assert(a9 == 9)
        assert(a10 == 10)
        assert(a11 == 11)
        assert(a12 == 12)
        assert(a13 == 13)
        assert(a14 == 14)
        assert(a15 == 15)
        assert(a16 == 16)


def test_bindings():
    store = Store()
    wasm = Root(store, RootImports(MyImports()))
    wasm.many_arguments(store, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)

</document_content>
</document>
<document index="27">
<source>./codegen/test_records.py</source>
<document_content>
from . import bindgen
from typing import Tuple
from wasmtime import Store

module = """
    (component
        (type $tuple (tuple u8 u32))

        (type $flag1 (flags "a" "b"))
        (type $flag2 (flags "a" "b" "c"))
        (type $flag8 (flags "a1" "a2" "a3" "a4" "a5" "a6" "a7" "a8"))
        (type $flag16 (flags
            "a1" "a2" "a3" "a4" "a5" "a6" "a7" "a8" "a9" "a10" "a11" "a12" "a13"
            "a14" "a15" "a16"
        ))
        (type $flag32 (flags
            "a1" "a2" "a3" "a4" "a5" "a6" "a7" "a8" "a9" "a10" "a11" "a12" "a13"
            "a14" "a15" "a16" "a17" "a18" "a19" "a20" "a21" "a22" "a23" "a24"
            "a25" "a26" "a27" "a28" "a29" "a30" "a31" "a32"
        ))

        (type $r1 (record (field "a" u8) (field "b" $flag1)))

        (import "host" (instance $i
            (export "multiple-results" (func (result (tuple u8 u16))))
            (export "swap" (func (param "a" $tuple) (result $tuple)))

            (export $f1 "flag1" (type (eq $flag1)))
            (export $f2 "flag2" (type (eq $flag2)))
            (export $f8 "flag8" (type (eq $flag8)))
            (export $f16 "flag16" (type (eq $flag16)))
            (export $f32 "flag32" (type (eq $flag32)))

            (export "roundtrip-flag1" (func (param "a" $f1) (result $f1)))
            (export "roundtrip-flag2" (func (param "a" $f2) (result $f2)))
            (export "roundtrip-flag8" (func (param "a" $f8) (result $f8)))
            (export "roundtrip-flag16" (func (param "a" $f16) (result $f16)))
            (export "roundtrip-flag32" (func (param "a" $f32) (result $f32)))

            (type $r1 (record (field "a" u8) (field "b" $f1)))
            (export $r1' "r1" (type (eq $r1)))
            (export "roundtrip-r1" (func (param "a" $r1') (result $r1')))
        ))

        (core module $libc
            (memory (export "mem") 1)
        )
        (core instance $libc (instantiate $libc))

        (core func $multi (canon lower (func $i "multiple-results") (memory $libc "mem")))
        (core func $swap (canon lower (func $i "swap") (memory $libc "mem")))
        (core func $r-flag1 (canon lower (func $i "roundtrip-flag1")))
        (core func $r-flag2 (canon lower (func $i "roundtrip-flag2")))
        (core func $r-flag8 (canon lower (func $i "roundtrip-flag8")))
        (core func $r-flag16 (canon lower (func $i "roundtrip-flag16")))
        (core func $r-flag32 (canon lower (func $i "roundtrip-flag32")))
        (core func $r-r1 (canon lower (func $i "roundtrip-r1") (memory $libc "mem")))

        (core module $m
            (import "" "r-flag1" (func $r-flag1 (param i32) (result i32)))
            (import "" "r-flag2" (func $r-flag2 (param i32) (result i32)))
            (import "" "r-flag8" (func $r-flag8 (param i32) (result i32)))
            (import "" "r-flag16" (func $r-flag16 (param i32) (result i32)))
            (import "" "r-flag32" (func $r-flag32 (param i32) (result i32)))
            (import "" "multi" (func $multi (param i32)))
            (import "" "swap" (func $swap (param i32 i32 i32)))
            (import "" "r-r1" (func $r-r1 (param i32 i32 i32)))

            (import "libc" "mem" (memory 1))

            (func (export "multi") (result i32)
                (call $multi (i32.const 100))
                i32.const 100)

            (func (export "swap") (param i32 i32) (result i32)
                (call $swap (local.get 0) (local.get 1) (i32.const 100))
                i32.const 100)

            (func (export "r-flag1") (param i32) (result i32)
                (call $r-flag1 (local.get 0)))
            (func (export "r-flag2") (param i32) (result i32)
                (call $r-flag2 (local.get 0)))
            (func (export "r-flag8") (param i32) (result i32)
                (call $r-flag8 (local.get 0)))
            (func (export "r-flag16") (param i32) (result i32)
                (call $r-flag16 (local.get 0)))
            (func (export "r-flag32") (param i32) (result i32)
                (call $r-flag32 (local.get 0)))
            (func (export "r-r1") (param i32 i32) (result i32)
                (call $r-r1 (local.get 0) (local.get 1) (i32.const 100))
                i32.const 100)
        )

        (core instance $i (instantiate $m
            (with "libc" (instance $libc))
            (with "" (instance
                (export "multi" (func $multi))
                (export "swap" (func $swap))
                (export "r-flag1" (func $r-flag1))
                (export "r-flag2" (func $r-flag2))
                (export "r-flag8" (func $r-flag8))
                (export "r-flag16" (func $r-flag16))
                (export "r-flag32" (func $r-flag32))
                (export "r-r1" (func $r-r1))
            ))
        ))

        (func $multiple-results (result (tuple u8 u16))
            (canon lift (core func $i "multi") (memory $libc "mem")))
        (func $swap (param "a" $tuple) (result $tuple)
            (canon lift (core func $i "swap") (memory $libc "mem")))
        (func $roundtrip-flag1 (param "a" $flag1) (result $flag1)
            (canon lift (core func $i "r-flag1")))
        (func $roundtrip-flag2  (param "a" $flag2) (result $flag2)
            (canon lift (core func $i "r-flag2")))
        (func $roundtrip-flag8 (param "a" $flag8) (result $flag8)
            (canon lift (core func $i "r-flag8")))
        (func $roundtrip-flag16 (param "a" $flag16) (result $flag16)
            (canon lift (core func $i "r-flag16")))
        (func $roundtrip-flag32 (param "a" $flag32) (result $flag32)
            (canon lift (core func $i "r-flag32")))
        (func $roundtrip-r1 (param "a" $r1) (result $r1)
            (canon lift (core func $i "r-r1") (memory $libc "mem")))

        (instance (export "e")
            (export "flag1" (type $flag1))
            (export "flag2" (type $flag2))
            (export "flag8" (type $flag8))
            (export "flag16" (type $flag16))
            (export "flag32" (type $flag32))
            (export "r1" (type $r1))

            (export "multiple-results" (func $multiple-results))
            (export "swap" (func $swap))
            (export "roundtrip-flag1" (func $roundtrip-flag1))
            (export "roundtrip-flag2" (func $roundtrip-flag2))
            (export "roundtrip-flag8" (func $roundtrip-flag8))
            (export "roundtrip-flag16" (func $roundtrip-flag16))
            (export "roundtrip-flag32" (func $roundtrip-flag32))
            (export "roundtrip-r1" (func $roundtrip-r1))
        )
    )
"""
bindgen('records', module)

from .generated.records import Root, RootImports, imports
from .generated.records.exports.e import Flag1, Flag2, Flag8, Flag16, Flag32, R1
from .generated.records.imports import host


class Host(imports.HostHost):
    def multiple_results(self) -> Tuple[int, int]:
        return 1, 2

    def swap(self, tuple: Tuple[int, int]) -> Tuple[int, int]:
        a, b = tuple
        return b, a

    def roundtrip_flag1(self, f: host.Flag1) -> host.Flag1:
        return f

    def roundtrip_flag2(self, f: host.Flag2) -> host.Flag2:
        return f

    def roundtrip_flag8(self, f: host.Flag8) -> host.Flag8:
        return f

    def roundtrip_flag16(self, f: host.Flag16) -> host.Flag16:
        return f

    def roundtrip_flag32(self, f: host.Flag32) -> host.Flag32:
        return f

    def roundtrip_r1(self, f: host.R1) -> host.R1:
        return f


def test_bindings():
    store = Store()
    bindings = Root(store, RootImports(host=Host()))

    assert bindings.e().multiple_results(store) == (1, 2)
    assert bindings.e().swap(store, (3, 4)) == (4, 3)

    assert bindings.e().roundtrip_flag1(store, Flag1(0)) == Flag1(0)
    for f1 in Flag1:
        assert bindings.e().roundtrip_flag1(store, f1) == f1
    assert bindings.e().roundtrip_flag2(store, Flag2(0)) == Flag2(0)
    for f2 in Flag2:
        assert bindings.e().roundtrip_flag2(store, f2) == f2
    assert bindings.e().roundtrip_flag8(store, Flag8(0)) == Flag8(0)
    for f8 in Flag8:
        assert bindings.e().roundtrip_flag8(store, f8) == f8
    assert bindings.e().roundtrip_flag16(store, Flag16(0)) == Flag16(0)
    for f16 in Flag16:
        assert bindings.e().roundtrip_flag16(store, f16) == f16
    assert bindings.e().roundtrip_flag32(store, Flag32(0)) == Flag32(0)
    for f32 in Flag32:
        assert bindings.e().roundtrip_flag32(store, f32) == f32

    r = bindings.e().roundtrip_r1(store, R1(8, Flag1(0)))
    assert r.a == 8
    assert r.b == Flag1(0)

    r = bindings.e().roundtrip_r1(store, R1(a=100, b=Flag1.A | Flag1.B))
    assert r.a == 100
    assert r.b == Flag1.A | Flag1.B

</document_content>
</document>
<document index="28">
<source>./codegen/test_scalars.py</source>
<document_content>
from . import bindgen
import math
from wasmtime import Store

module = """
    (component
        (import "host" (instance $i
            (export "roundtrip-u8" (func (param "a" u8) (result u8)))
            (export "roundtrip-s8" (func (param "a" s8) (result s8)))
            (export "roundtrip-u16" (func (param "a" u16) (result u16)))
            (export "roundtrip-s16" (func (param "a" s16) (result s16)))
            (export "roundtrip-u32" (func (param "a" u32) (result u32)))
            (export "roundtrip-s32" (func (param "a" s32) (result s32)))
            (export "roundtrip-u64" (func (param "a" u64) (result u64)))
            (export "roundtrip-s64" (func (param "a" s64) (result s64)))
            (export "roundtrip-float32" (func (param "a" float32) (result float32)))
            (export "roundtrip-float64" (func (param "a" float64) (result float64)))
            (export "roundtrip-char" (func (param "a" char) (result char)))
            (export "roundtrip-bool" (func (param "a" bool) (result bool)))
        ))
        (core module $m
            (import "" "roundtrip-u8" (func $u8 (param i32) (result i32)))
            (import "" "roundtrip-s8" (func $s8 (param i32) (result i32)))
            (import "" "roundtrip-u16" (func $u16 (param i32) (result i32)))
            (import "" "roundtrip-s16" (func $s16 (param i32) (result i32)))
            (import "" "roundtrip-u32" (func $u32 (param i32) (result i32)))
            (import "" "roundtrip-s32" (func $s32 (param i32) (result i32)))
            (import "" "roundtrip-u64" (func $u64 (param i64) (result i64)))
            (import "" "roundtrip-s64" (func $s64 (param i64) (result i64)))

            (import "" "roundtrip-float32" (func $float32 (param f32) (result f32)))
            (import "" "roundtrip-float64" (func $float64 (param f64) (result f64)))

            (import "" "roundtrip-char" (func $char (param i32) (result i32)))
            (import "" "roundtrip-bool" (func $bool (param i32) (result i32)))

            (func (export "roundtrip-u8") (param i32) (result i32)
                local.get 0 call $u8)
            (func (export "roundtrip-s8") (param i32) (result i32)
                local.get 0 call $s8)
            (func (export "roundtrip-u16") (param i32) (result i32)
                local.get 0 call $u16)
            (func (export "roundtrip-s16") (param i32) (result i32)
                local.get 0 call $s16)
            (func (export "roundtrip-u32") (param i32) (result i32)
                local.get 0 call $u32)
            (func (export "roundtrip-s32") (param i32) (result i32)
                local.get 0 call $s32)
            (func (export "roundtrip-u64") (param i64) (result i64)
                local.get 0 call $u64)
            (func (export "roundtrip-s64") (param i64) (result i64)
                local.get 0 call $s64)

            (func (export "roundtrip-float32") (param f32) (result f32)
                local.get 0 call $float32)
            (func (export "roundtrip-float64") (param f64) (result f64)
                local.get 0 call $float64)

            (func (export "roundtrip-char") (param i32) (result i32)
                local.get 0 call $char)
            (func (export "roundtrip-bool") (param i32) (result i32)
                local.get 0 call $bool)
        )
        (core func $u8 (canon lower (func $i "roundtrip-u8")))
        (core func $s8 (canon lower (func $i "roundtrip-s8")))
        (core func $u16 (canon lower (func $i "roundtrip-u16")))
        (core func $s16 (canon lower (func $i "roundtrip-s16")))
        (core func $u32 (canon lower (func $i "roundtrip-u32")))
        (core func $s32 (canon lower (func $i "roundtrip-s32")))
        (core func $u64 (canon lower (func $i "roundtrip-u64")))
        (core func $s64 (canon lower (func $i "roundtrip-s64")))
        (core func $float32 (canon lower (func $i "roundtrip-float32")))
        (core func $float64 (canon lower (func $i "roundtrip-float64")))
        (core func $char (canon lower (func $i "roundtrip-char")))
        (core func $bool (canon lower (func $i "roundtrip-bool")))

        (core instance $i (instantiate $m
            (with "" (instance
                (export "roundtrip-u8" (func $u8))
                (export "roundtrip-s8" (func $s8))
                (export "roundtrip-u16" (func $u16))
                (export "roundtrip-s16" (func $s16))
                (export "roundtrip-u32" (func $u32))
                (export "roundtrip-s32" (func $s32))
                (export "roundtrip-u64" (func $u64))
                (export "roundtrip-s64" (func $s64))
                (export "roundtrip-float32" (func $float32))
                (export "roundtrip-float64" (func $float64))
                (export "roundtrip-char" (func $char))
                (export "roundtrip-bool" (func $bool))
            ))
        ))

        (func (export "roundtrip-u8") (param "a" u8) (result u8)
            (canon lift (core func $i "roundtrip-u8")))
        (func (export "roundtrip-s8") (param "a" s8) (result s8)
            (canon lift (core func $i "roundtrip-s8")))
        (func (export "roundtrip-u16") (param "a" u16) (result u16)
            (canon lift (core func $i "roundtrip-u16")))
        (func (export "roundtrip-s16") (param "a" s16) (result s16)
            (canon lift (core func $i "roundtrip-s16")))
        (func (export "roundtrip-u32") (param "a" u32) (result u32)
            (canon lift (core func $i "roundtrip-u32")))
        (func (export "roundtrip-s32") (param "a" s32) (result s32)
            (canon lift (core func $i "roundtrip-s32")))
        (func (export "roundtrip-u64") (param "a" u64) (result u64)
            (canon lift (core func $i "roundtrip-u64")))
        (func (export "roundtrip-s64") (param "a" s64) (result s64)
            (canon lift (core func $i "roundtrip-s64")))
        (func (export "roundtrip-float32") (param "a" float32) (result float32)
            (canon lift (core func $i "roundtrip-float32")))
        (func (export "roundtrip-float64") (param "a" float64) (result float64)
            (canon lift (core func $i "roundtrip-float64")))
        (func (export "roundtrip-char") (param "a" char) (result char)
            (canon lift (core func $i "roundtrip-char")))
        (func (export "roundtrip-bool") (param "a" bool) (result bool)
            (canon lift (core func $i "roundtrip-bool")))
    )
"""
bindgen('scalars', module)

from .generated.scalars import Root, RootImports, imports


class Host(imports.HostHost):
    def roundtrip_u8(self, val: int) -> int:
        assert val >= 0
        assert val <= (1 << 8) - 1
        return val

    def roundtrip_s8(self, val: int) -> int:
        assert val >= -(1 << (8 - 1))
        assert val <= (1 << (8 - 1)) - 1
        return val

    def roundtrip_u16(self, val: int) -> int:
        assert val >= 0
        assert val <= (1 << 16) - 1
        return val

    def roundtrip_s16(self, val: int) -> int:
        assert val >= -(1 << (16 - 1))
        assert val <= (1 << (16 - 1)) - 1
        return val

    def roundtrip_u32(self, val: int) -> int:
        assert val >= 0
        assert val <= (1 << 32) - 1
        return val

    def roundtrip_s32(self, val: int) -> int:
        assert val >= -(1 << (32 - 1))
        assert val <= (1 << (32 - 1)) - 1
        return val

    def roundtrip_u64(self, val: int) -> int:
        assert val >= 0
        assert val <= (1 << 64) - 1
        return val

    def roundtrip_s64(self, val: int) -> int:
        assert val >= -(1 << (64 - 1))
        assert val <= (1 << (64 - 1)) - 1
        return val

    def roundtrip_float32(self, a: float) -> float:
        return a

    def roundtrip_float64(self, a: float) -> float:
        return a

    def roundtrip_char(self, a: str) -> str:
        return a

    def roundtrip_bool(self, a: bool) -> bool:
        return a


def test_bindings():
    store = Store()
    bindings = Root(store, RootImports(host=Host()))

    assert bindings.roundtrip_u8(store, 0) == 0
    assert bindings.roundtrip_u8(store, (1 << 8) - 1) == (1 << 8) - 1
    assert bindings.roundtrip_u16(store, 0) == 0
    assert bindings.roundtrip_u16(store, (1 << 16) - 1) == (1 << 16) - 1
    assert bindings.roundtrip_u32(store, 0) == 0
    assert bindings.roundtrip_u32(store, (1 << 32) - 1) == (1 << 32) - 1
    assert bindings.roundtrip_u64(store, 0) == 0
    assert bindings.roundtrip_u64(store, (1 << 64) - 1) == (1 << 64) - 1

    assert bindings.roundtrip_s8(store, 0) == 0
    assert bindings.roundtrip_s8(store, (1 << (8 - 1)) - 1) == (1 << (8 - 1)) - 1
    assert bindings.roundtrip_s8(store, -(1 << (8 - 1))) == -(1 << (8 - 1))
    assert bindings.roundtrip_s16(store, 0) == 0
    assert bindings.roundtrip_s16(store, (1 << (16 - 1)) - 1) == (1 << (16 - 1)) - 1
    assert bindings.roundtrip_s16(store, -(1 << (16 - 1))) == -(1 << (16 - 1))
    assert bindings.roundtrip_s32(store, 0) == 0
    assert bindings.roundtrip_s32(store, (1 << (32 - 1)) - 1) == (1 << (32 - 1)) - 1
    assert bindings.roundtrip_s32(store, -(1 << (32 - 1))) == -(1 << (32 - 1))
    assert bindings.roundtrip_s64(store, 0) == 0
    assert bindings.roundtrip_s64(store, (1 << (64 - 1)) - 1) == (1 << (64 - 1)) - 1
    assert bindings.roundtrip_s64(store, -(1 << (64 - 1))) == -(1 << (64 - 1))

    inf = float('inf')
    assert bindings.roundtrip_float32(store, 1.0) == 1.0
    assert bindings.roundtrip_float32(store, inf) == inf
    assert bindings.roundtrip_float32(store, -inf) == -inf
    assert math.isnan(bindings.roundtrip_float32(store, float('nan')))

    assert bindings.roundtrip_float64(store, 1.0) == 1.0
    assert bindings.roundtrip_float64(store, inf) == inf
    assert bindings.roundtrip_float64(store, -inf) == -inf
    assert math.isnan(bindings.roundtrip_float64(store, float('nan')))

    assert bindings.roundtrip_char(store, 'a') == 'a'
    assert bindings.roundtrip_char(store, ' ') == ' '
    assert bindings.roundtrip_char(store, '🚩') == '🚩'

    assert bindings.roundtrip_bool(store, True)
    assert not bindings.roundtrip_bool(store, False)

</document_content>
</document>
<document index="29">
<source>./codegen/test_simple_export.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (core module $m
            (func (export "get") (result i32)
                i32.const 100)
        )

        (core instance $i (instantiate $m))

        (func (export "get") (result u8) (canon lift (core func $i "get")))
    )
"""
bindgen('simple_export', module)

from .generated.simple_export import Root


def test_bindings():
    store = Store()
    bindings = Root(store)
    result = bindings.get(store)
    assert result == 100

</document_content>
</document>
<document index="30">
<source>./codegen/test_simple_import.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (import "host" (instance $host
            (export "thunk" (func))
        ))

        (core module $m
            (import "host" "thunk" (func $thunk))

            (start $thunk)
        )

        (core func $thunk (canon lower (func $host "thunk")))
        (core instance $i (instantiate $m
            (with "host" (instance (export "thunk" (func $thunk))))
        ))
    )
"""
bindgen('simple_import', module)

from .generated.simple_import import Root, RootImports, imports


class Host(imports.HostHost):
    def thunk(self):
        self.hit = True


def test_bindings():
    store = Store()
    host = Host()
    Root(store, RootImports(host=host))

    assert host.hit

</document_content>
</document>
<document index="31">
<source>./codegen/test_two_exports.py</source>
<document_content>
from . import bindgen
from wasmtime import Store

module = """
    (component
        (import "i" (instance $i
          (export "f1" (func))
          (export "f2" (func))
        ))

        (core func $f1 (canon lower (func $i "f1")))
        (core func $f2 (canon lower (func $i "f2")))

        (func $f1' (canon lift (core func $f1)))
        (func $f2' (canon lift (core func $f2)))

        (instance (export "i1") (export "f1" (func $f1')))
        (instance (export "i2") (export "f2" (func $f2')))
    )
"""
bindgen('two_exports', module)

from .generated.two_exports import Root, RootImports, imports


class Host(imports.HostI):
    def f1(self) -> None:
        self.f1_hit = True

    def f2(self) -> None:
        self.f2_hit = True


def test_bindings():
    store = Store()
    host = Host()
    wasm = Root(store, RootImports(i=host))

    wasm.i1().f1(store)
    assert(host.f1_hit)
    wasm.i2().f2(store)
    assert(host.f2_hit)

</document_content>
</document>
<document index="32">
<source>./codegen/test_variants.py</source>
<document_content>
from . import bindgen
from wasmtime import Store
from typing import Optional

module = """
    (component
        (import "host" (instance $i
            (type $e1 (enum "a" "b"))

            (type $c1 (variant (case "a" s32) (case "b" s64)))
            (type $c2 (variant (case "a" s32) (case "b" float32)))
            (type $c3 (variant (case "a" s32) (case "b" float64)))
            (type $c4 (variant (case "a" s64) (case "b" float32)))
            (type $c5 (variant (case "a" s64) (case "b" float64)))
            (type $c6 (variant (case "a" float32) (case "b" float64)))

            (type $z1 (variant (case "a" s32) (case "b")))
            (type $z2 (variant (case "a" s64) (case "b")))
            (type $z3 (variant (case "a" float32) (case "b")))
            (type $z4 (variant (case "a" float64) (case "b")))

            (type $all-integers (variant
                (case "bool" bool)
                (case "u8" u8)
                (case "u16" u16)
                (case "u32" u32)
                (case "u64" u64)
                (case "s8" s8)
                (case "s16" s16)
                (case "s32" s32)
                (case "s64" s64)
            ))
            (type $all-floats (variant (case "f32" float32) (case "f64" float64)))
            (type $duplicated-s32 (variant
                (case "c1" s32)
                (case "c2" s32)
                (case "c3" s32)
            ))
            (type $distinguished (variant (case "s32" s32) (case "float32" float32)))
            (export $distinguished' "distinguished" (type (eq $distinguished)))

            (type $nested-union (variant
                (case "d" $distinguished')
                (case "s32" s32)
                (case "float32" float32)
            ))
            (type $option-in-union (variant (case "o" (option s32)) (case "i" s32)))

            (export $e1' "e1" (type (eq $e1)))

            (export $c1' "c1" (type (eq $c1)))
            (export $c2' "c2" (type (eq $c2)))
            (export $c3' "c3" (type (eq $c3)))
            (export $c4' "c4" (type (eq $c4)))
            (export $c5' "c5" (type (eq $c5)))
            (export $c6' "c6" (type (eq $c6)))
            (type $casts (tuple $c1' $c2' $c3' $c4' $c5' $c6'))
            (export $casts' "casts" (type (eq $casts)))

            (export $z1' "z1" (type (eq $z1)))
            (export $z2' "z2" (type (eq $z2)))
            (export $z3' "z3" (type (eq $z3)))
            (export $z4' "z4" (type (eq $z4)))
            (type $zeros (tuple $z1' $z2' $z3' $z4'))
            (export $zeros' "zeros" (type (eq $zeros)))

            (export $all-integers' "all-integers" (type (eq $all-integers)))
            (export $all-floats' "all-floats" (type (eq $all-floats)))
            (export $duplicated-s32' "duplicated-s32" (type (eq $duplicated-s32)))
            (export $nested-union' "nested-union" (type (eq $nested-union)))
            (export $option-in-union' "option-in-union" (type (eq $option-in-union)))

            (export "roundtrip-option" (func (param "a" (option float32)) (result (option u8))))
            (export "roundtrip-result" (func
                (param "a" (result u32 (error float32)))
                (result (result float64 (error u8)))
            ))
            (export "roundtrip-enum" (func (param "a" $e1') (result $e1')))
            (export "variant-casts" (func (param "a" $casts') (result $casts')))
            (export "variant-zeros" (func (param "a" $zeros') (result $zeros')))

            (export "add-one-all-integers" (func (param "a" $all-integers') (result $all-integers')))
            (export "add-one-all-floats" (func (param "a" $all-floats') (result $all-floats')))
            (export "add-one-duplicated-s32" (func (param "a" $duplicated-s32') (result $duplicated-s32')))
            (export "add-one-distinguished" (func (param "a" $distinguished') (result $distinguished')))
            (export "add-one-nested-union" (func (param "a" $nested-union') (result $nested-union')))
            (export "add-one-option-in-union" (func (param "a" $option-in-union') (result $option-in-union')))
            (export "add-one-option-in-option" (func (param "a" (option (option s32))) (result (option (option s32)))))
        ))

        (core module $libc (memory (export "m") 1))
        (core instance $libc (instantiate $libc))

        (core func $r-opt (canon lower (func $i "roundtrip-option") (memory $libc "m")))
        (core func $r-result (canon lower (func $i "roundtrip-result") (memory $libc "m")))
        (core func $r-enum (canon lower (func $i "roundtrip-enum")))
        (core func $v-casts (canon lower (func $i "variant-casts") (memory $libc "m")))
        (core func $v-zeros (canon lower (func $i "variant-zeros") (memory $libc "m")))
        (core func $a-int (canon lower (func $i "add-one-all-integers") (memory $libc "m")))
        (core func $a-float (canon lower (func $i "add-one-all-floats") (memory $libc "m")))
        (core func $a-dup (canon lower (func $i "add-one-duplicated-s32") (memory $libc "m")))
        (core func $a-dist (canon lower (func $i "add-one-distinguished") (memory $libc "m")))
        (core func $a-nest (canon lower (func $i "add-one-nested-union") (memory $libc "m")))
        (core func $a-oinu (canon lower (func $i "add-one-option-in-union") (memory $libc "m")))
        (core func $a-oino (canon lower (func $i "add-one-option-in-option") (memory $libc "m")))

        (core module $m
            (import "libc" "m" (memory 1))
            (import "" "r-opt" (func $r-opt (param i32 f32 i32)))
            (import "" "r-result" (func $r-result (param i32 i32 i32)))
            (import "" "r-enum" (func $r-enum (param i32) (result i32)))
            (import "" "v-casts" (func $v-casts
                (param i32 i64 i32 i32 i32 i64 i32 i64 i32 i64 i32 i64 i32)
            ))
            (import "" "v-zeros" (func $v-zeros
                (param i32 i32 i32 i64 i32 f32 i32 f64 i32)
            ))
            (import "" "a-int" (func $a-int (param i32 i64 i32)))
            (import "" "a-float" (func $a-float (param i32 i64 i32)))
            (import "" "a-dup" (func $a-dup (param i32 i32 i32)))
            (import "" "a-dist" (func $a-dist (param i32 i32 i32)))
            (import "" "a-nest" (func $a-nest (param i32 i32 i32 i32)))
            (import "" "a-oinu" (func $a-oinu (param i32 i32 i32 i32)))
            (import "" "a-oino" (func $a-oino (param i32 i32 i32 i32)))

            (func (export "r-opt") (param i32 f32) (result i32)
                (call $r-opt (local.get 0) (local.get 1) (i32.const 100))
                i32.const 100)
            (func (export "r-result") (param i32 i32) (result i32)
                (call $r-result (local.get 0) (local.get 1) (i32.const 100))
                i32.const 100)
            (func (export "r-enum") (param i32) (result i32)
                (call $r-enum (local.get 0)))
            (func (export "v-casts")
                (param i32 i64 i32 i32 i32 i64 i32 i64 i32 i64 i32 i64)
                (result i32)
                local.get 0
                local.get 1
                local.get 2
                local.get 3
                local.get 4
                local.get 5
                local.get 6
                local.get 7
                local.get 8
                local.get 9
                local.get 10
                local.get 11
                i32.const 80
                call $v-casts
                i32.const 80)
            (func (export "v-zeros")
                (param i32 i32 i32 i64 i32 f32 i32 f64)
                (result i32)
                local.get 0
                local.get 1
                local.get 2
                local.get 3
                local.get 4
                local.get 5
                local.get 6
                local.get 7
                i32.const 80
                call $v-zeros
                i32.const 80)

            (func (export "a-int") (param i32 i64) (result i32)
                (call $a-int (local.get 0) (local.get 1) (i32.const 80))
                i32.const 80)
            (func (export "a-float") (param i32 i64) (result i32)
                (call $a-float (local.get 0) (local.get 1) (i32.const 80))
                i32.const 80)
            (func (export "a-dup") (param i32 i32) (result i32)
                (call $a-dup (local.get 0) (local.get 1) (i32.const 80))
                i32.const 80)
            (func (export "a-dist") (param i32 i32) (result i32)
                (call $a-dist (local.get 0) (local.get 1) (i32.const 80))
                i32.const 80)
            (func (export "a-nest") (param i32 i32 i32) (result i32)
                (call $a-nest (local.get 0) (local.get 1) (local.get 2) (i32.const 80))
                i32.const 80)
            (func (export "a-oinu") (param i32 i32 i32) (result i32)
                (call $a-oinu (local.get 0) (local.get 1) (local.get 2) (i32.const 80))
                i32.const 80)
            (func (export "a-oino") (param i32 i32 i32) (result i32)
                (call $a-oino (local.get 0) (local.get 1) (local.get 2) (i32.const 80))
                i32.const 80)
        )

        (core instance $i (instantiate $m
            (with "libc" (instance $libc))
            (with "" (instance
                (export "r-opt" (func $r-opt))
                (export "r-result" (func $r-result))
                (export "r-enum" (func $r-enum))
                (export "v-casts" (func $v-casts))
                (export "v-zeros" (func $v-zeros))
                (export "a-int" (func $a-int))
                (export "a-float" (func $a-float))
                (export "a-dup" (func $a-dup))
                (export "a-dist" (func $a-dist))
                (export "a-nest" (func $a-nest))
                (export "a-oinu" (func $a-oinu))
                (export "a-oino" (func $a-oino))
            ))
        ))

        (type $e1 (enum "a" "b"))

        (type $c1 (variant (case "a" s32) (case "b" s64)))
        (type $c2 (variant (case "a" s32) (case "b" float32)))
        (type $c3 (variant (case "a" s32) (case "b" float64)))
        (type $c4 (variant (case "a" s64) (case "b" float32)))
        (type $c5 (variant (case "a" s64) (case "b" float64)))
        (type $c6 (variant (case "a" float32) (case "b" float64)))
        (type $casts (tuple $c1 $c2 $c3 $c4 $c5 $c6))

        (type $z1 (variant (case "a" s32) (case "b")))
        (type $z2 (variant (case "a" s64) (case "b")))
        (type $z3 (variant (case "a" float32) (case "b")))
        (type $z4 (variant (case "a" float64) (case "b")))
        (type $zeros (tuple $z1 $z2 $z3 $z4))

        (type $all-integers (variant
            (case "bool" bool)
            (case "u8" u8)
            (case "u16" u16)
            (case "u32" u32)
            (case "u64" u64)
            (case "s8" s8)
            (case "s16" s16)
            (case "s32" s32)
            (case "s64" s64)
        ))
        (type $all-floats (variant (case "f32" float32) (case "f64" float64)))
        (type $duplicated-s32 (variant
            (case "c1" s32)
            (case "c2" s32)
            (case "c3" s32)
        ))
        (type $distinguished (variant (case "s32" s32) (case "float32" float32)))
        (type $nested-union (variant
            (case "d" $distinguished)
            (case "s32" s32)
            (case "float32" float32)
        ))
        (type $option-in-union (variant (case "o" (option s32)) (case "i" s32)))

        (func $roundtrip-option (param "a" (option float32)) (result (option u8))
            (canon lift (core func $i "r-opt") (memory $libc "m")))
        (func $roundtrip-result
            (param "a" (result u32 (error float32)))
            (result (result float64 (error u8)))
            (canon lift (core func $i "r-result") (memory $libc "m")))
        (func $roundtrip-enum (param "a" $e1) (result $e1)
            (canon lift (core func $i "r-enum")))
        (func $variant-casts (param "a" $casts) (result $casts)
            (canon lift (core func $i "v-casts") (memory $libc "m")))
        (func $variant-zeros (param "a" $zeros) (result $zeros)
            (canon lift (core func $i "v-zeros") (memory $libc "m")))

        (func $add-one-all-integers (param "a" $all-integers) (result $all-integers)
            (canon lift (core func $i "a-int") (memory $libc "m")))
        (func $add-one-all-floats (param "a" $all-floats) (result $all-floats)
            (canon lift (core func $i "a-float") (memory $libc "m")))
        (func $add-one-duplicated-s32 (param "a" $duplicated-s32) (result $duplicated-s32)
            (canon lift (core func $i "a-dup") (memory $libc "m")))
        (func $add-one-distinguished (param "a" $distinguished) (result $distinguished)
            (canon lift (core func $i "a-dist") (memory $libc "m")))
        (func $add-one-nested-union (param "a" $nested-union) (result $nested-union)
            (canon lift (core func $i "a-nest") (memory $libc "m")))
        (func $add-one-option-in-union (param "a" $option-in-union) (result $option-in-union)
            (canon lift (core func $i "a-oinu") (memory $libc "m")))
        (func $add-one-option-in-option (param "a" (option (option s32))) (result (option (option s32)))
            (canon lift (core func $i "a-oino") (memory $libc "m")))

        (instance (export "e")
            (export "e1" (type $e1))

            (export "c1" (type $c1))
            (export "c2" (type $c2))
            (export "c3" (type $c3))
            (export "c4" (type $c4))
            (export "c5" (type $c5))
            (export "c6" (type $c6))
            (export "casts" (type $casts))

            (export "z1" (type $z1))
            (export "z2" (type $z2))
            (export "z3" (type $z3))
            (export "z4" (type $z4))
            (export "zeros" (type $zeros))

            (export "all-integers" (type $all-integers))
            (export "all-floats" (type $all-floats))
            (export "duplicated-s32" (type $duplicated-s32))
            (export "distinguished" (type $distinguished))
            (export "nested-union" (type $nested-union))
            (export "option-in-union" (type $option-in-union))

            (export "roundtrip-option" (func $roundtrip-option))
            (export "roundtrip-result" (func $roundtrip-result))
            (export "roundtrip-enum" (func $roundtrip-enum))
            (export "variant-casts" (func $variant-casts))
            (export "variant-zeros" (func $variant-zeros))
            (export "add-one-all-integers" (func $add-one-all-integers))
            (export "add-one-all-floats" (func $add-one-all-floats))
            (export "add-one-duplicated-s32" (func $add-one-duplicated-s32))
            (export "add-one-distinguished" (func $add-one-distinguished))
            (export "add-one-nested-union" (func $add-one-nested-union))
            (export "add-one-option-in-union" (func $add-one-option-in-union))
            (export "add-one-option-in-option" (func $add-one-option-in-option))
        )
    )
"""
bindgen('variants', module)

from .generated.variants import Root, RootImports, imports
from .generated.variants import e
from .generated.variants.imports import host
from .generated.variants.types import Result, Ok, Err, Some


class Host(imports.HostHost):
    def roundtrip_option(self, a: Optional[float]) -> Optional[int]:
        if a:
            return int(a)
        return None

    def roundtrip_result(self, a: Result[int, float]) -> Result[float, int]:
        if isinstance(a, Ok):
            return Ok(float(a.value))
        return Err(int(a.value))

    def roundtrip_enum(self, a: host.E1) -> host.E1:
        return a

    def variant_casts(self, a: host.Casts) -> host.Casts:
        return a

    def variant_zeros(self, a: host.Zeros) -> host.Zeros:
        return a

    def add_one_all_integers(self, num: host.AllIntegers) -> host.AllIntegers:
        # Bool
        if isinstance(num, host.AllIntegersBool):
            assert num.value in (True, False)
            return host.AllIntegersBool(not num.value)
        # The unsigned numbers
        elif isinstance(num, host.AllIntegersU8):
            lower_limit = 0
            upper_limit = 2**8
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersU8((num.value + 1) % upper_limit)
        elif isinstance(num, host.AllIntegersU16):
            lower_limit = 0
            upper_limit = 2**16
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersU16((num.value + 1) % upper_limit)
        elif isinstance(num, host.AllIntegersU32):
            lower_limit = 0
            upper_limit = 2**32
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersU32((num.value + 1) % upper_limit)
        elif isinstance(num, host.AllIntegersU64):
            lower_limit = 0
            upper_limit = 2**64
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersU64((num.value + 1) % upper_limit)
        # The signed numbers
        elif isinstance(num, host.AllIntegersS8):
            lower_limit = -2**7
            upper_limit = 2**7
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersS8(num.value + 1)
        elif isinstance(num, host.AllIntegersS16):
            lower_limit = -2**15
            upper_limit = 2**15
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersS16(num.value + 1)
        elif isinstance(num, host.AllIntegersS32):
            lower_limit = -2**31
            upper_limit = 2**31
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersS32(num.value + 1)
        elif isinstance(num, host.AllIntegersS64):
            lower_limit = -2**63
            upper_limit = 2**63
            assert lower_limit <= num.value < upper_limit
            return host.AllIntegersS64(num.value + 1)
        else:
            raise ValueError("Invalid input value!")

    def add_one_all_floats(self, num: host.AllFloats) -> host.AllFloats:
        if isinstance(num, host.AllFloatsF32):
            return host.AllFloatsF32(num.value + 1)
        if isinstance(num, host.AllFloatsF64):
            return host.AllFloatsF64(num.value + 1)
        else:
            raise ValueError("Invalid input value!")

    def add_one_duplicated_s32(self, num: host.DuplicatedS32) -> host.DuplicatedS32:
        if isinstance(num, host.DuplicatedS32C1):
            return host.DuplicatedS32C1(num.value + 1)
        if isinstance(num, host.DuplicatedS32C2):
            return host.DuplicatedS32C2(num.value + 1)
        if isinstance(num, host.DuplicatedS32C3):
            return host.DuplicatedS32C3(num.value + 1)
        else:
            raise ValueError("Invalid input value!")

    def add_one_distinguished(self, a: host.Distinguished) -> host.Distinguished:
        a.value += 1
        return a

    def add_one_nested_union(self, a: host.NestedUnion) -> host.NestedUnion:
        if isinstance(a, host.NestedUnionD):
            a.value.value += 1
            return host.NestedUnionD(a.value)
        if isinstance(a, host.NestedUnionS32):
            return host.NestedUnionS32(a.value + 1)
        if isinstance(a, host.NestedUnionFloat32):
            return host.NestedUnionFloat32(a.value + 1)
        else:
            raise ValueError("Invalid input value!")

    def add_one_option_in_union(self, a: host.OptionInUnion) -> host.OptionInUnion:
        if isinstance(a, host.OptionInUnionO):
            if a.value is None:
                return host.OptionInUnionO(None)
            else:
                return host.OptionInUnionO(a.value + 1)
        if isinstance(a, host.OptionInUnionI):
            return host.OptionInUnionI(a.value + 1)
        else:
            raise ValueError("Invalid input value!")

    def add_one_option_in_option(self, a: Optional[Some[Optional[int]]]) -> Optional[Some[Optional[int]]]:
        if isinstance(a, Some):
            if a.value is None:
                return Some(None)
            else:
                return Some(a.value + 1)
        if a is None:
            return None
        else:
            raise ValueError("Invalid input value!")


def test_bindings():
    store = Store()
    wasm = Root(store, RootImports(host=Host()))

    exports = wasm.e()
    assert exports.roundtrip_option(store, 1.) == 1
    assert exports.roundtrip_option(store, None) is None
    assert exports.roundtrip_option(store, 2.) == 2

    assert exports.roundtrip_result(store, Ok(2)) == Ok(2)
    assert exports.roundtrip_result(store, Ok(4)) == Ok(4)
    assert exports.roundtrip_result(store, Err(5)) == Err(5)

    assert exports.roundtrip_enum(store, e.E1.A) == e.E1.A
    assert exports.roundtrip_enum(store, e.E1.B) == e.E1.B

    a1, a2, a3, a4, a5, a6 = exports.variant_casts(store, (
        e.C1A(1),
        e.C2A(2),
        e.C3A(3),
        e.C4A(4),
        e.C5A(5),
        e.C6A(6.),
    ))
    assert a1 == e.C1A(1)
    assert a2 == e.C2A(2)
    assert a3 == e.C3A(3)
    assert a4 == e.C4A(4)
    assert a5 == e.C5A(5)
    assert a6 == e.C6A(6.)

    b1, b2, b3, b4, b5, b6 = exports.variant_casts(store, (
        e.C1B(1),
        e.C2B(2),
        e.C3B(3),
        e.C4B(4),
        e.C5B(5),
        e.C6B(6.),
    ))
    assert b1 == e.C1B(1)
    assert b2 == e.C2B(2)
    assert b3 == e.C3B(3)
    assert b4 == e.C4B(4)
    assert b5 == e.C5B(5)
    assert b6 == e.C6B(6.)

    z1, z2, z3, z4 = exports.variant_zeros(store, (
        e.Z1A(1),
        e.Z2A(2),
        e.Z3A(3.),
        e.Z4A(4.),
    ))
    assert z1 == e.Z1A(1)
    assert z2 == e.Z2A(2)
    assert z3 == e.Z3A(3.)
    assert z4 == e.Z4A(4.)

    # All-Integers
    # Booleans
    assert exports.add_one_all_integers(store, e.AllIntegersBool(False)) == e.AllIntegersBool(True)
    assert exports.add_one_all_integers(store, e.AllIntegersBool(True)) == e.AllIntegersBool(False)
    # Unsigned integers
    assert exports.add_one_all_integers(store, e.AllIntegersU8(0)) == e.AllIntegersU8(1)
    assert exports.add_one_all_integers(store, e.AllIntegersU8(2**8 - 1)) == e.AllIntegersU8(0)
    assert exports.add_one_all_integers(store, e.AllIntegersU16(0)) == e.AllIntegersU16(1)
    assert exports.add_one_all_integers(store, e.AllIntegersU16(2**16 - 1)) == e.AllIntegersU16(0)
    assert exports.add_one_all_integers(store, e.AllIntegersU32(0)) == e.AllIntegersU32(1)
    assert exports.add_one_all_integers(store, e.AllIntegersU32(2**32 - 1)) == e.AllIntegersU32(0)
    assert exports.add_one_all_integers(store, e.AllIntegersU64(0)) == e.AllIntegersU64(1)
    assert exports.add_one_all_integers(store, e.AllIntegersU64(2**64 - 1)) == e.AllIntegersU64(0)
    # Signed integers
    assert exports.add_one_all_integers(store, e.AllIntegersS8(0)) == e.AllIntegersS8(1)
    assert exports.add_one_all_integers(store, e.AllIntegersS8(2**7 - 2)) == e.AllIntegersS8(2**7 - 1)
    assert exports.add_one_all_integers(store, e.AllIntegersS8(-8)) == e.AllIntegersS8(-7)
    assert exports.add_one_all_integers(store, e.AllIntegersS16(0)) == e.AllIntegersS16(1)
    assert exports.add_one_all_integers(store, e.AllIntegersS16(2**15 - 2)) == e.AllIntegersS16(2**15 - 1)
    assert exports.add_one_all_integers(store, e.AllIntegersS16(-8)) == e.AllIntegersS16(-7)
    assert exports.add_one_all_integers(store, e.AllIntegersS32(0)) == e.AllIntegersS32(1)
    assert exports.add_one_all_integers(store, e.AllIntegersS32(2**31 - 2)) == e.AllIntegersS32(2**31 - 1)
    assert exports.add_one_all_integers(store, e.AllIntegersS32(-8)) == e.AllIntegersS32(-7)
    assert exports.add_one_all_integers(store, e.AllIntegersS64(0)) == e.AllIntegersS64(1)
    assert exports.add_one_all_integers(store, e.AllIntegersS64(2**63 - 2)) == e.AllIntegersS64(2**63 - 1)
    assert exports.add_one_all_integers(store, e.AllIntegersS64(-8)) == e.AllIntegersS64(-7)

    assert exports.add_one_all_floats(store, e.AllFloatsF32(0.0)) == e.AllFloatsF32(1.0)
    assert exports.add_one_all_floats(store, e.AllFloatsF64(0.0)) == e.AllFloatsF64(1.0)

    assert exports.add_one_duplicated_s32(store, e.DuplicatedS32C1(0)) == e.DuplicatedS32C1(1)
    assert exports.add_one_duplicated_s32(store, e.DuplicatedS32C2(1)) == e.DuplicatedS32C2(2)
    assert exports.add_one_duplicated_s32(store, e.DuplicatedS32C3(2)) == e.DuplicatedS32C3(3)

    assert exports.add_one_distinguished(store, e.DistinguishedS32(1)) == e.DistinguishedS32(2)
    assert exports.add_one_distinguished(store, e.DistinguishedFloat32(2.)) == e.DistinguishedFloat32(3.)

    assert exports.add_one_nested_union(store, e.NestedUnionD(e.DistinguishedS32(1))) == e.NestedUnionD(e.DistinguishedS32(2))
    assert exports.add_one_nested_union(store, e.NestedUnionD(e.DistinguishedFloat32(2.))) == e.NestedUnionD(e.DistinguishedFloat32(3.))
    assert exports.add_one_nested_union(store, e.NestedUnionS32(3)) == e.NestedUnionS32(4)
    assert exports.add_one_nested_union(store, e.NestedUnionFloat32(4.)) == e.NestedUnionFloat32(5.)

    assert exports.add_one_option_in_union(store, e.OptionInUnionO(1)) == e.OptionInUnionO(2)
    assert exports.add_one_option_in_union(store, e.OptionInUnionO(None)) == e.OptionInUnionO(None)
    assert exports.add_one_option_in_union(store, e.OptionInUnionI(1)) == e.OptionInUnionI(2)

    assert exports.add_one_option_in_option(store, Some(1)) == Some(2)
    assert exports.add_one_option_in_option(store, Some(None)) == Some(None)
    assert exports.add_one_option_in_option(store, None) is None

</document_content>
</document>
<document index="33">
<source>./bindgen/__init__.py</source>
<document_content>
import sys
import pytest

# componentize-py requires Python 3.10
if sys.version_info < (3, 10):
    pytest.skip("skipping componentize-py tests", allow_module_level=True)

</document_content>
</document>
<document index="34">
<source>./bindgen/conftest.py</source>
<document_content>
"""Fixtures to define test suites for generated code Python guest code.

These tests work by allowing you to write a WIT file, implement the guest
code in Python via componentize-py, and then test the generated Python
bindings. To add a new test, first create the needed fixtures:

* Create a new sub directory.
* Within that directory create a `.wit` file.
* Create an `app.py` file in that directory implementing the guest code.

Then to write the test itself:

* Create a `test_<name>.py` in the same directory.
* Use the `bindgest_testcase` in your test to create the wasm component
  and generate python bindings for this component.

## Example

Given this directory:

```
bare_funcs/
├── app.py          <-- guest code implementation
├── barefuncs       <-- componentize-py bindings
│   ├── __init__.py
│   └── types.py
├── component.wit   <-- test .wit file
└── test_mycomp.py  <-- pytest test case of bindings
```

With a `component.wit` file of:

```wit
package component:barefuncs;

world barefuncs {
  export foo: func(a: s32) -> s32;
}
```

And guest code of:

```python
class Barefuncs:
    def foo(self, a: int) -> int:
        return a + 1
```

You can write a testcase for this using:

```python
from pathlib import Path


def test_bare_funcs(bindgen_testcase):
    testcase = bindgen_testcase(
        guest_code_dir=Path(__file__).parent,
        world_name='barefuncs',
    )
    store, root = generate_bindings(testcase)
    assert root.foo(store, 10) == 11
```

"""
from pathlib import Path
from dataclasses import dataclass, field
import importlib
import tempfile
import subprocess
import shutil

from pytest import fixture

import wasmtime
from wasmtime.bindgen import generate


TEST_ROOT = Path(__file__).parent
BINDGEN_DIR = TEST_ROOT / 'generated'


@dataclass
class BindgenTestCase:
    guest_code_dir: Path
    world_name: str
    wit_filename: str = 'component.wit'
    app_dir: Path = field(init=False)
    app_name: str = field(init=False, default='app', repr=False)

    def __post_init__(self):
        self.app_dir = Path(self.guest_code_dir).resolve()

    @property
    def wit_full_path(self):
        return self.guest_code_dir.joinpath(self.wit_filename)

    @property
    def testsuite_name(self):
        # The name of the directory that contains the
        # guest Python code is used as the identifier for
        # package names, etc.
        return self.guest_code_dir.name


def generate_bindings(guest_code_dir: Path,
                      world_name: str,
                      wit_filename: str = 'component.wit'):
    tc = BindgenTestCase(
            guest_code_dir=guest_code_dir,
            world_name=world_name,
            wit_filename=wit_filename)
    return _generate_bindings(tc)


def _generate_bindings(testcase: BindgenTestCase):
    wit_path = testcase.wit_full_path
    componentize_py = shutil.which('componentize-py')
    if componentize_py is None:
        raise RuntimeError("Could not find componentize-py executable.")
    with tempfile.NamedTemporaryFile('w') as f:
        output_wasm = str(f.name + '.wasm')
        subprocess.run([
            componentize_py, '-d', str(wit_path), '-w', testcase.world_name,
            'componentize', '--stub-wasi', testcase.app_name,
            '-o', output_wasm
        ], check=True, cwd=testcase.guest_code_dir)
        # Once we've done that now generate the python bindings.
        testsuite_name = testcase.testsuite_name
        with open(output_wasm, 'rb') as out:
            # Mapping of filename -> content_bytes
            results = generate(testsuite_name, out.read())
        for filename, contents in results.items():
            path = BINDGEN_DIR / testsuite_name / filename
            path.parent.mkdir(parents=True, exist_ok=True)
            path.write_bytes(contents)
    # Return an instantiated module for the caller to test.
    pkg = importlib.import_module(f'.generated.{testsuite_name}',
                                  package=__package__)
    store = wasmtime.Store()
    root = pkg.Root(store)
    return store, root


@fixture
def bindgen_testcase():
    return generate_bindings

</document_content>
</document>
<document index="35">
<source>./bindgen/export_resources/app.py</source>
<document_content>
import sys
from types import ModuleType


class MyInterfaceName:
    def interface_func(self, foo: str) -> str:
        return f"hello {foo}"


# componentize-py expects that resources within an interface are defined
# as a class in a separate module that matches the interface name.
#
# Normally, you'd want to go the more typical route of running
#
#   componentize-py -d component.wit -w testworld bindings .
#
# to generate the types and protocols to help you write guest code,
# and then split the code into multiple files, but we're taking a
# shortcut here so we can write all the guest code in a single file.
class DemoResourceClass:
    def __init__(self, name: str) -> None:
        self.name = name

    def greet(self, greeting: str) -> str:
        return f'{greeting}, {self.name}!'


mod = ModuleType("my_interface_name")
mod.DemoResourceClass = DemoResourceClass
sys.modules['my_interface_name'] = mod

</document_content>
</document>
<document index="36">
<source>./bindgen/export_resources/test_export_resources.py</source>
<document_content>
from pathlib import Path


def test_bare_funcs(bindgen_testcase):
    store, root = bindgen_testcase(
        guest_code_dir=Path(__file__).parent,
        world_name='testworld',
    )
    interface = root.my_interface_name()
    instance = interface.DemoResourceClass(store, 'myname')
    result = instance.greet(store, 'Hello there')
    assert result == 'Hello there, myname!'

</document_content>
</document>
<document index="37">
<source>./bindgen/bare_funcs/app.py</source>
<document_content>
class Barefuncs:
    def foo(self, a):
        return a + 1

</document_content>
</document>
<document index="38">
<source>./bindgen/bare_funcs/test_bare_funcs.py</source>
<document_content>
from pathlib import Path


def test_bare_funcs(bindgen_testcase):
    store, root = bindgen_testcase(
        guest_code_dir=Path(__file__).parent,
        world_name='barefuncs',
    )
    assert root.foo(store, 10) == 11

</document_content>
</document>
<document index="39">
<source>./bindgen/list_types/app.py</source>
<document_content>
from typing import List


class Lists:
    def strings(self, a: str) -> str:
        return a

    def bytes(self, a: bytes) -> bytes:
        return a

    def ints(self, a: List[int]) -> List[int]:
        return a

    def string_list(self, a: List[str]) -> List[str]:
        return a

</document_content>
</document>
<document index="40">
<source>./bindgen/list_types/test_lists.py</source>
<document_content>
from pathlib import Path


def test_lists(bindgen_testcase):
    store, root = bindgen_testcase(
        guest_code_dir=Path(__file__).parent,
        world_name='lists',
    )
    assert root.strings(store, '') == ''
    assert root.strings(store, 'a') == 'a'
    assert root.strings(store, 'hello world') == 'hello world'
    assert root.strings(store, 'hello ⚑ world') == 'hello ⚑ world'

    assert root.bytes(store, b'') == b''
    assert root.bytes(store, b'a') == b'a'
    assert root.bytes(store, b'\x01\x02') == b'\x01\x02'

    assert root.ints(store, []) == []
    assert root.ints(store, [1]) == [1]
    assert root.ints(store, [1, 2, 100, 10000]) == [1, 2, 100, 10000]

    assert root.string_list(store, []) == []
    assert root.string_list(store, ['']) == ['']
    assert root.string_list(
        store, ['a', 'b', '', 'd', 'hello']
    ) == ['a', 'b', '', 'd', 'hello']

</document_content>
</document>
</documents>

System:

write detailed usage documentation including realistic examples

Response:

Based on the test files, I'll provide comprehensive documentation for the wasmtime Python bindings:

Wasmtime Python Bindings Documentation

The wasmtime Python package provides bindings to the Wasmtime WebAssembly runtime. It allows you to instantiate and execute WebAssembly modules from Python.

Basic Usage

Engine and Store

from wasmtime import Engine, Store

# Create an engine
engine = Engine()

# Create a store 
store = Store(engine)

The Engine handles compilation settings and caching. The Store holds runtime state for instances.

Loading Modules

from wasmtime import Module

# From WAT text format
module = Module(engine, '(module)')

# From binary Wasm
with open('module.wasm', 'rb') as f:
    module = Module(engine, f.read())

Functions

from wasmtime import FuncType, ValType, Func

# Create function type
func_type = FuncType([ValType.i32(), ValType.i32()], [ValType.i32()])

# Create function
def add(a: int, b: int) -> int:
    return a + b

func = Func(store, func_type, add)

# Call function
result = func(store, 1, 2) # Returns 3

Memory

from wasmtime import MemoryType, Memory, Limits

# Create memory type with initial 1 page size
mem_type = MemoryType(Limits(1, None))

# Create memory instance
memory = Memory(store, mem_type)

# Get/set memory data
data_ptr = memory.data_ptr(store)
data_len = memory.data_len(store)

# Grow memory
memory.grow(store, 1) # Grow by 1 page

Tables

from wasmtime import TableType, Table, ValType

# Create table type for function references
table_type = TableType(ValType.funcref(), Limits(1, None))

# Create table
func = Func(store, FuncType([], []), lambda: None)
table = Table(store, table_type, func)

# Get/set elements
elem = table.get(store, 0)
table.set(store, 0, func)

Globals

from wasmtime import GlobalType, Global, Val

# Create mutable global type
global_type = GlobalType(ValType.i32(), True)

# Create global instance
global_inst = Global(store, global_type, Val.i32(1))

# Get/set value
value = global_inst.value(store)
global_inst.set_value(store, Val.i32(2))

Instances

from wasmtime import Instance, Module

# Create instance from module
module = Module(engine, '(module)')
instance = Instance(store, module, [])

# Access exports
exports = instance.exports(store)
func = exports['function_name'] 
mem = exports['memory']

WASI Support

from wasmtime import WasiConfig

# Configure WASI
config = WasiConfig()
config.inherit_argv()
config.inherit_env()
config.inherit_stdin()
config.inherit_stdout()
config.inherit_stderr()
config.preopen_dir('/', '/')

# Set WASI on store
store.set_wasi(config)

Error Handling

The bindings use custom exception types:

  • WasmtimeError: General runtime errors
  • Trap: WebAssembly trap exceptions
  • ExitTrap: WASI program exit
try:
    instance = Instance(store, module, [])
except WasmtimeError as e:
    print(f"Error instantiating module: {e}")

Resource Management

Resources are automatically cleaned up when Python objects are garbage collected, but can be explicitly closed:

store = Store()
store.close()

module = Module(engine, '(module)')
module.close() 

This documentation covers the core functionality. The bindings also support more advanced features like:

  • Component model and interface types
  • Resource types and references
  • Custom linking and importing
  • Memory management controls
  • Execution limits and interruption

Let me know if you would like me to expand on any of these topics!

2024-11-05T22:12:16

Prompt:

write a detailed section about memory management and one about execution limits

Response:

Here are detailed sections on memory management and execution limits in the Wasmtime Python bindings:

Memory Management

WebAssembly Memory

from wasmtime import Memory, MemoryType, Limits

Creating and Configuring Memory

store = Store()

# Create memory type with initial and maximum pages (64KB per page)
mem_type = MemoryType(Limits(
    minimum=1,  # 1 page (64KB) initial size
    maximum=10  # Optional maximum of 10 pages (640KB)
))

# Create memory instance
memory = Memory(store, mem_type)

Accessing Memory Data

# Get raw pointer to memory data
data_ptr = memory.data_ptr(store)

# Get total length in bytes
data_len = memory.data_len(store)

# Read/write memory using slices
memory.write(store, bytes_data, offset)
read_data = memory.read(store, offset, length)

# Memory size in pages
current_pages = memory.size(store)

Growing Memory

# Grow by specified number of pages
success = memory.grow(store, pages=1)  

# Growth can fail if it would exceed maximum
if not success:
    print("Failed to grow memory")

# Growth beyond type limits raises error
try:
    memory.grow(store, 1000)
except WasmtimeError:
    print("Growth exceeds maximum")

Memory Limits

store = Store()

# Set memory size limit in bytes
store.set_limits(memory_size=1024 * 1024)  # 1MB limit

# Will raise WasmtimeError if module tries to exceed limit
try:
    Memory(store, MemoryType(Limits(20))) # 20 pages > 1MB
except WasmtimeError:
    print("Memory allocation exceeds store limit")

Table Memory

# Limit table elements
store.set_limits(table_elements=1000)

try:
    table = Table(store, 
                 TableType(ValType.funcref(), Limits(2000)),
                 None)
except WasmtimeError:
    print("Table size exceeds limit")

Execution Limits and Controls

Fuel-based Limits

Fuel allows metering execution by counting instructions:

# Enable fuel consumption in config
config = Config() 
config.consume_fuel = True
engine = Engine(config)
store = Store(engine)

# Add fuel to store
store.set_fuel(1000000)  # 1M units of fuel

# Get remaining fuel
remaining = store.get_fuel()

# Execution fails when fuel runs out
try:
    # ... execute wasm ...
except Trap as e:
    print("Out of fuel!")

Interruption

Support interrupting long-running Wasm code:

# Enable epoch interruption
config = Config()
config.epoch_interruption = True
engine = Engine(config)
store = Store(engine)

# Set deadline in epochs
store.set_epoch_deadline(1)

# Increment epoch to trigger interrupt
engine.increment_epoch()

# Example of interrupting infinite loop
module = Module(engine, """
    (module 
        (func (export "loop")
            (loop br 0)  ;; infinite loop
        )
    )
""")

try:
    instance = Instance(store, module, [])
    instance.exports(store)["loop"](store)
except Trap:
    print("Execution interrupted!")

Resource Limits

Control various resource limits per store:

store = Store()

# Set memory limits
store.set_limits(
    memory_size=100000,     # Max total memory in bytes
    table_elements=10000,   # Max table elements
)

# Growth operations will fail if they exceed limits
try:
    memory.grow(store, too_many_pages)
except WasmtimeError:
    print("Growth exceeds store memory limit")

try: 
    table.grow(store, too_many_elements, None)
except WasmtimeError:
    print("Growth exceeds store table limit")

Best Practices

  1. Always set appropriate limits to prevent resource exhaustion:

    store.set_limits(
        memory_size=reasonable_size,
        table_elements=reasonable_count
    )
  2. Use fuel for untrusted code:

    config.consume_fuel = True
    store.set_fuel(max_instructions)
  3. Enable interruption for long-running operations:

    config.epoch_interruption = True
    store.set_epoch_deadline(deadline)
  4. Catch and handle resource errors:

    try:
        result = instance.exports(store)["function"](store)
    except Trap as e:
        if "fuel" in str(e):
            handle_out_of_fuel()
        elif "interrupted" in str(e):
            handle_interruption()
    except WasmtimeError as e:
        handle_resource_error()

These mechanisms provide fine-grained control over WebAssembly execution resources and help ensure safe execution of potentially untrusted or resource-intensive code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment