# `Wasmex.Instance`

Instantiates a Wasm module and allows calling exported functions on it.

In the majority of cases, you will not need to use this module directly
but use the main module `Wasmex` instead.
This module expects to be executed within GenServer context which `Wasmex` sets up.

# `t`

```elixir
@type t() :: %Wasmex.Instance{reference: reference(), resource: binary()}
```

# `call_exported_function`

```elixir
@spec call_exported_function(
  Wasmex.StoreOrCaller.t(),
  t(),
  binary(),
  [any()],
  GenServer.from(),
  non_neg_integer() | nil
) :: :ok | {:error, binary()}
```

Calls a function the given `name` exported by the Wasm `instance` with the given `params`.

The Wasm function will be invoked asynchronously. An `:ok` response to this function call indicates
that execution of an async Wasm function call was scheduled. Once that Wasm function call was executed
and finished, a reply message will be send to the process indicated by the `from` argument.

The result is either `{:ok, results}` or `{:error, reason}`.
A BadArg exception may be thrown when given unexpected input data.

## Implementation Details

Behind the scenes, the NIF submits the call to the Store's bounded executor.
Each Store processes one operation at a time and yields cooperatively while WebAssembly runs.
If `timeout` is set and the deadline is reached, Wasmex interrupts the WebAssembly call,
discards its result, and releases the Store for subsequent operations.

The `from` argument is expected to be as given by `c:GenServer.handle_call/3`.
The NIF uses this `from` tuple to send a message with the result of this Wasm function call.
If the receiving process is no longer waiting, the result is discarded.

## Function parameters

Parameters for Wasm functions are automatically casted to Wasm values.
Note that WebAssembly only knows number datatypes (floats and integers of various sizes).

You can pass arbitrary data to WebAssembly by writing that data into an instances `Wasmex.Memory`.
The `memory/2` function returns the instances memory.

# `function_export_exists`

```elixir
@spec function_export_exists(Wasmex.StoreOrCaller.t(), t(), binary()) :: boolean()
```

Whether the Wasm `instance` exports a function with the given `name`.

## Example

    iex> %{store: store, module: module} = TestHelper.wasm_module()
    iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
    iex> Wasmex.Instance.function_export_exists(store, instance, "sum")
    true
    iex> Wasmex.Instance.function_export_exists(store, instance, "does_not_exist")
    false

# `get_global_value`

```elixir
@spec get_global_value(Wasmex.StoreOrCaller.t(), t(), binary()) ::
  {:ok, number()} | {:error, binary()}
```

Reads the value of an exported global.

## Examples

    iex> wat = "(module
    ...>          (global $answer i32 (i32.const 42))
    ...>          (export \"answer\" (global $answer))
    ...>        )"
    iex> {:ok, store} = Wasmex.Store.new()
    iex> {:ok, module} = Wasmex.Module.compile(store, wat)
    iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
    iex> Wasmex.Instance.get_global_value(store, instance, "answer")
    {:ok, 42}
    iex> Wasmex.Instance.get_global_value(store, instance, "not_a_global")
    {:error, "exported global `not_a_global` not found"}

# `memory`

```elixir
@spec memory(Wasmex.StoreOrCaller.t(), t()) ::
  {:ok, Wasmex.Memory.t()} | {:error, binary()}
```

Returns the `Wasmex.Memory` of the Wasm `instance`.

## Example

    iex> %{store: store, module: module} = TestHelper.wasm_module()
    iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
    iex> {:ok, %Wasmex.Memory{}} = Wasmex.Instance.memory(store, instance)

# `new`

```elixir
@spec new(
  Wasmex.StoreOrCaller.t(),
  Wasmex.Module.t(),
  %{optional(binary()) =&gt; (... -&gt; any())},
  [%{optional(binary()) =&gt; Wasmex.Module.t()}] | []
) :: {:ok, t()} | {:error, binary()}
```

Instantiates a Wasm module with the given imports.

Returns the instantiated Wasm instance.

The `import` parameter is a nested map of Wasm namespaces.
Each namespace consists of a name and a map of function names to function signatures.

The `links` parameter is a list of name-module pairs that are dynamically linked to the instance.

Function signatures are a tuple of the form `{:fn, arg_types, return_types, callback}`.
Where `arg_types` and `return_types` are lists of `:i32`, `:i64`, `:f32`, `:f64`, `:v128`.

Each `callback` function receives a `context` map as the first argument followed by the arguments specified in its signature.
`context` has the following keys:

  * `:memory` - The default exported `Wasmex.Memory` of the Wasm instance
  * `:caller` - The caller of the Wasm instance which MUST be used instead of a `Wasmex.Store` in all Wasmex functions called from within the callback. Failure to do so will result in a deadlock. The `caller` MUST NOT be used outside of the callback.

## Example

This example instantiates a Wasm module with one namespace `env` having
three imported functions `imported_sum3`, `imported_sumf`, and `imported_void`.

The imported function `imported_sum3` takes three `:i32` (32 bit integer) arguments and returns a `:i32` number.
Its implementation is defined by the callback function `fn _context, a, b, c -> a + b + c end`.

    iex> %{store: store, module: module} = TestHelper.wasm_module()
    iex> imports = %{
    ...>   "env" =>
    ...>     %{
    ...>       "imported_sum3" => {:fn, [:i32, :i32, :i32], [:i32], fn _context, a, b, c -> a + b + c end},
    ...>       "imported_sumf" => {:fn, [:f32, :f32], [:f32], fn _context, a, b -> a + b end},
    ...>       "imported_void" => {:fn, [], [], fn _context -> nil end}
    ...>     }
    ...> }
    ...> links = []
    iex> {:ok, %Wasmex.Instance{}} = Wasmex.Instance.new(store, module, imports, links)

# `set_global_value`

```elixir
@spec set_global_value(Wasmex.StoreOrCaller.t(), t(), binary(), number()) ::
  {:ok, number()} | {:error, binary()}
```

Sets the value of an exported mutable global.

## Examples

    iex> wat = "(module
    ...>          (global $count (mut i32) (i32.const 0))
    ...>          (export \"count\" (global $count))
    ...>        )"
    iex> {:ok, store} = Wasmex.Store.new()
    iex> {:ok, module} = Wasmex.Module.compile(store, wat)
    iex> {:ok, instance} = Wasmex.Instance.new(store, module, %{})
    iex> Wasmex.Instance.set_global_value(store, instance, "count", 1)
    :ok
    iex> Wasmex.Instance.get_global_value(store, instance, "count")
    {:ok, 1}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
