wasmer-pack 0.7.1

A code generator that lets you treat WebAssembly modules like native dependencies.
Documentation
'''
Bindings to the {{interface_name}} library.
'''

from pathlib import Path
from typing import Optional, Any

from wasmer import Store, Module, wasi # type: ignore

{%- for lib in libraries %}
from .{{lib.ident}}.bindings import (
    {{lib.class_name}} as _{{lib.class_name}},
    {%- for imp in lib.imports %}
    add_{{imp.ident}}_to_imports as _{{lib.ident}}__add_{{imp.ident}}_to_imports,
    {{imp.class_name}} as _{{lib.ident}}__{{imp.class_name}},
    {%- endfor %}
)
{%- endfor %}

class Bindings:
    """
    Instantiate bindings to the various libraries in this package.
    """

    def __init__(self, store: Store):
        self._store = store
        self._cache: dict[str, Module] = {}

    def _get_module(self, filename: str) -> Module:
        if filename in self._cache:
            return self._cache[filename]

        wasm = Path(__file__).parent.joinpath(filename).read_bytes()
        module = Module(self._store, wasm)
        self._cache[filename] = module
        return module

    {% for lib in libraries -%}
    def {{lib.ident}}(
        self,
        {%- if lib.wasi %}
        env: Optional[wasi.Environment] = None,
        {%- endif %}
        {%- for imp in lib.imports %}
        {{imp.ident}}: _{{lib.ident}}__{{imp.class_name}},
        {%- endfor %}
        module: Optional[Module] = None,
    ) -> _{{lib.class_name}}:
        """
        Instantiate the "{{lib.ident}}" library.

        {%- if lib.wasi %}
        :param env: A pre-initialized WASI environment. If not specified, a
                     default value will be used.
        {%- endif %}
        {%- for imp in lib.imports %}
        :param {{imp.ident}}: An implementation of the "{{imp.interface_name}}" interface.
        {%- endfor %}
        :param module: A user-specified WebAssembly module to use instead of the
                       one bundled with this package.
        """

        filename = "{{lib.ident}}/{{lib.module_filename}}"
        if not module:
            module = self._get_module(filename)

        imports: dict[str, Any] = {}

        wrapper = None

        def get_export(item_name: str):
            assert wrapper is not None
            return getattr(wrapper.instance.exports, item_name)

        {%- for imp in lib.imports %}
        _{{lib.ident}}__add_{{imp.ident}}_to_imports(self._store, imports, {{imp.ident}}, get_export)
        {%- endfor %}

        {%- if lib.wasi %}
        version = wasi.get_version(module, strict=True)
        assert version is not None, f'"{filename}" is not a valid WASI executable'
        if not env:
            env = wasi.StateBuilder("{{lib.ident}}").finalize()
        wasi_imports = env.generate_imports(self._store, version)
        imports.update(wasi_imports)
        {%- endif %}

        wrapper = _{{lib.class_name}}(self._store, imports, module)
        return wrapper
    {% endfor %}