# `Wasmex.Components.HostResource`

Defines a host-owned WebAssembly component resource implemented in Elixir.

Given this imported WIT resource:

```wit
interface counters {
  resource counter {
    constructor(initial: u32);
    with-value: static func(value: u32) -> counter;
    increment: func() -> u32;
    take-other: func(other: counter) -> u32;
  }
}
```

implement its callbacks and pass the generated imports to the component:

```elixir
defmodule CounterHost do
  use Wasmex.Components.HostResource,
    wit_path: "wit",
    resource: "counter"

  def new(initial), do: start_counter(initial)
  def with_value(value), do: start_counter(value)
  def increment(counter), do: Agent.get_and_update(counter, &{&1 + 1, &1 + 1})

  # `other` is an owned argument, so this callback is now responsible for it.
  def take_other(counter, other) do
    value = Agent.get(counter, & &1) + Agent.get(other, & &1)
    Agent.stop(other)
    value
  end

  def drop(counter), do: Agent.stop(counter)

  defp start_counter(initial) do
    {:ok, counter} = Agent.start_link(fn -> initial end)
    counter
  end
end

{:ok, component} =
  Wasmex.Components.start_link(
    bytes: File.read!("component.wasm"),
    imports: CounterHost.imports()
  )
```

## Callback mapping

A resource is represented by any opaque Elixir term. A PID, reference, ETS
key, or struct containing those values works well when the resource has
mutable state.

* A WIT constructor maps to `new/arity` and returns the opaque term.
* A method maps to its snake-case name and receives the opaque term first.
* A static function maps to its snake-case name without a resource argument.
* A resource returned directly or inside a tuple, option, result, record,
  variant, or list is represented by an opaque term in the matching Elixir
  position.
* `drop/1` is called when the guest destroys an owned handle. It defaults to
  a no-op and should be overridden when the term owns external state.

Passing `borrow<T>` to a callback leaves the guest handle live. Passing
`own<T>` transfers ownership to the callback and removes the guest handle;
`drop/1` is not subsequently called for that handle. The callback must either
release the state or return it in a resource-typed result.

Callback exceptions and incompatible return values trap the active component
call. The component server itself remains alive. Wasmex releases any
partially lowered Wasmtime handles, but a callback that allocated external
state before returning an invalid value remains responsible for that state.

## Multiple resources and worlds

Merge resources imported from the same or different interfaces with:

```elixir
imports =
  Wasmex.Components.HostResource.merge_imports([
    CounterHost,
    LabelHost,
    %{
      "package:namespace/interface@version" => %{
        "freestanding-function" => {:fn, &MyHost.function/1}
      }
    }
  ])
```

Maps can therefore be included for freestanding imports that share an
interface with a generated resource.

Set `:world` when the WIT package contains multiple worlds. If multiple
imported interfaces contain the same resource name, select one with
`interface: "package:namespace/interface@version"`.

Use `wit: source` for a self-contained WIT package. Use `wit_path: path` for
a WIT file or directory. A directory may contain the standard `deps`
subdirectory, making `wit_path:` the best choice for packages that import
WASI or other dependency packages. Files used beneath the path are registered
as external compile resources, so changing them recompiles the host module.

User imports are linked after Wasmtime's built-in WASI interfaces and may
intentionally override them. For example, a module selecting
`interface: "wasi:io/error@0.2.12"` can implement that standard resource in
Elixir. The component and host WIT versions must match exactly.

# `merge_imports`

```elixir
@spec merge_imports([module() | map()]) :: map()
```

Deep-merges generated host-resource modules and ordinary import maps.

---

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