# `Wasmex.Components`

This is the entry point to support for the [WebAssembly Component Model](https://component-model.bytecodealliance.org/).

The Component Model is a higher-level way to interact with WebAssembly modules that provides:
- Better type safety through interface types
- Standardized way to define imports and exports using WIT (WebAssembly Interface Types)
- WASI support for system interface capabilities

## Basic Usage

To use a WebAssembly component:

1. Start a component instance:
```elixir
# Using raw bytes
bytes = File.read!("path/to/component.wasm")
{:ok, pid} = Wasmex.Components.start_link(%{bytes: bytes})

# Using a file path
{:ok, pid} = Wasmex.Components.start_link(%{path: "path/to/component.wasm"})

# With WASI support
{:ok, pid} = Wasmex.Components.start_link(%{
  path: "path/to/component.wasm",
  wasi: %Wasmex.Wasi.WasiP2Options{}
})

# With imports (host functions the component can call)
{:ok, pid} = Wasmex.Components.start_link(%{
  bytes: bytes,
  imports: %{
    "host_function" => {:fn, &MyModule.host_function/1}
  }
})
```

2. Call exported functions:
```elixir
{:ok, result} = Wasmex.Components.call_function(pid, "exported_function", ["param1"])
```

## Component Interface Types

The component model supports the following WIT (WebAssembly Interface Type) types:

### Supported Types

- **Primitive Types**
  - Integers: `s8`, `s16`, `s32`, `s64`, `u8`, `u16`, `u32`, `u64`
  - Floats: `f32`, `f64`
  - `bool`
  - `string`
  - `char` (maps to Elixir strings with a single character)
    ```wit
    char
    ```
    ```elixir
    "A"  # or from a code point
    937  # Ω
    ```

- **Compound Types**
  - `record` (maps to Elixir maps with atom keys)
    ```wit
    record point { x: u32, y: u32 }
    ```
    ```elixir
    %{x: 1, y: 2}
    ```

  - `list<T>` (maps to Elixir lists)
    ```wit
    list<u32>
    ```
    ```elixir
    [1, 2, 3]
    ```

  - `tuple<T1, T2>` (maps to Elixir tuples)
    ```wit
    tuple<u32, string>
    ```
    ```elixir
    {1, "two"}
    ```

  - `option<T>` (maps to `:none` or `{:some, value}`)
    ```wit
    option<u32>
    ```
    ```elixir
    :none  # or
    {:some, 42}
    ```

  - `enum` (maps to Elixir atoms)
    ```wit
    enum size { s, m, l }
    ```
    ```elixir
    :s  # or :m or :l
    ```

  - `variant` (tagged unions, maps to atoms or tuples)
    ```wit
    variant filter { all, none, lt(u32) }
    ```
    ```elixir
    :all     # variant without payload
    :none    # variant without payload
    {:lt, 7} # variant with payload
    ```

  - `flags` (maps to Elixir maps with boolean values)
    ```wit
    flags permission { read, write, exec }
    ```
    ```elixir
    %{read: true, write: true, exec: false}
    # Note: When returned from WebAssembly, only the flags set to true are included
    # %{read: true, exec: true}
    ```

  - `result<T, E>` (maps to Elixir tuples with :ok/:error)
    ```wit
    result<u32, u32>
    ```
    ```elixir
    {:ok, 42}      # success case
    {:error, 404}  # error case
    ```

### Guest Resources

Guest-owned resources exported by a component can be constructed and called
with `Wasmex.Components.GuestResource`. It can generate an arity-aware API
from WIT:

```elixir
defmodule Counter do
  use Wasmex.Components.GuestResource,
    wit: File.read!("counter.wit"),
    resource: "counter"
end

{:ok, counter} = Counter.new(component_pid, 42)
{:ok, value} = Counter.get_value(counter)
:ok = Counter.drop(counter)
```

### Host Resources

Host-owned resources imported by a component can be implemented with
`Wasmex.Components.HostResource`:

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

  def new(initial), do: MyCounter.start(initial)
  def get_value(counter), do: MyCounter.value(counter)
  def drop(counter), do: MyCounter.stop(counter)
end

{:ok, component_pid} =
  Wasmex.Components.start_link(
    bytes: component,
    imports: CounterHost.imports()
  )
```

Constructors return an opaque Elixir term representing the resource. Methods
and the destructor receive that term. Borrowed handles remain live, while
owned handles transfer ownership to the receiving callback. `wit_path:`
resolves dependency packages from a standard `wit/deps` directory.

Guest-owned resource values passed through arbitrary freestanding component
functions are not yet supported.

Support for the Component Model should be considered beta quality.

## Options

The `start_link/1` function accepts the following options:

* `:bytes` - Raw WebAssembly component bytes (mutually exclusive with `:path`)
* `:path` - Path to a WebAssembly component file (mutually exclusive with `:bytes`)
* `:wasi` - Optional WASI configuration as `Wasmex.Wasi.WasiP2Options` struct for system interface capabilities
* `:imports` - Optional map of host functions that can be called by the WebAssembly component
  * Keys are function names as strings
  * Values are tuples of `{:fn, function}` where function is the host function to call
  * Modules generated with `Wasmex.Components.HostResource` expose
    `imports/0` definitions for host-owned resources

Additionally, any standard GenServer options (like `:name`) are supported.

### Examples

```elixir
# With raw bytes
{:ok, pid} = Wasmex.Components.start_link(%{
  bytes: File.read!("component.wasm"),
  name: MyComponent
})

# With WASI configuration
{:ok, pid} = Wasmex.Components.start_link(%{
  path: "component.wasm",
  wasi: %Wasmex.Wasi.WasiP2Options{
    allow_http: true
  }
})

# With host functions
{:ok, pid} = Wasmex.Components.start_link(%{
  path: "component.wasm",
  imports: %{
    "log" => {:fn, &IO.puts/1},
    "add" => {:fn, fn(a, b) -> a + b end}
  }
})
```

# `function_name_or_path`

```elixir
@type function_name_or_path() :: String.t() | atom() | [String.t() | atom()] | tuple()
```

# `call_function`

```elixir
@spec call_function(GenServer.server(), function_name_or_path(), [any()], timeout()) ::
  {:ok, any()} | {:error, any()}
```

Calls an exported component function.

`name_or_path` may be a function name or a path identifying an exported
interface function. Parameters and results use the Elixir representations
described in the component interface type documentation above.

The default timeout is 5 seconds. A timeout exits the calling process unless
it traps exits, just like `GenServer.call/3`. Wasmtime component calls cannot
currently be cancelled without invalidating the component instance, so a
timed-out call continues in the background. Its late result is discarded and
later operations on the same Store wait for it to finish. Use `:infinity` for
calls whose duration is intentionally unbounded.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `instance`

```elixir
@spec instance(GenServer.server()) :: Wasmex.Components.Instance.t()
```

Returns the low-level component instance owned by a component server.

Guest resource APIs accept either this value or the component server directly.

# `start_link`

Starts a new WebAssembly component instance.

## Options

  * `:bytes` - Raw WebAssembly component bytes (mutually exclusive with `:path`)
  * `:path` - Path to a WebAssembly component file (mutually exclusive with `:bytes`)
  * `:wasi` - Optional WASI configuration as `Wasmex.Wasi.WasiP2Options` struct
  * `:imports` - Optional map of host functions that can be called by the component
  * Any standard GenServer options (like `:name`)

## Returns

  * `{:ok, pid}` on success
  * `{:error, reason}` on failure

---

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