# `ExCubecl`
[🔗](https://github.com/ohhi-vn/ex_cubecl/blob/v0.4.0/lib/ex_cubecl.ex#L15)

ExCubecl — GPU compute runtime for Elixir.

Provides GPU buffer management, kernel execution, async command submission,
and pipeline orchestration via CubeCL (Rust NIFs).

## Quick start

    # Check availability
    ExCubecl.available?()

    # Create a buffer from a list
    {:ok, buf} = ExCubecl.buffer([1.0, 2.0, 3.0], [3], :f32)

    # Inspect
    {:ok, shape} = ExCubecl.shape(buf)   # [3]
    {:ok, dtype} = ExCubecl.dtype(buf)   # "f32"
    {:ok, size}  = ExCubecl.size(buf)    # 12  (bytes)

    # Read back
    {:ok, binary} = ExCubecl.read(buf)

    # Buffers are automatically freed when the Elixir term is garbage collected.
    # No manual free is needed.

## Kernel execution

    {:ok, out} = ExCubecl.buffer([0.0, 0.0, 0.0], [3], :f32)
    ExCubecl.run_kernel("elementwise_add", [buf_a, buf_b], out)

## Async commands

    {:ok, cmd} = ExCubecl.submit("some_command")
    {:ok, :completed} = ExCubecl.poll(cmd)
    :ok = ExCubecl.wait(cmd)

## Pipelines

    {:ok, p} = ExCubecl.pipeline()
    :ok = ExCubecl.pipeline_add(p, "elementwise_add", [buf_a, buf_b], buf_out)
    :ok = ExCubecl.pipeline_run(p)
    :ok = ExCubecl.pipeline_free(p)

# `buffer_ref`

```elixir
@type buffer_ref() :: reference()
```

# `available?`

```elixir
@spec available?() :: boolean()
```

Checks if the NIF library is loaded and available.

Returns `true` if the NIF can be loaded, `false` otherwise.

# `buffer`

```elixir
@spec buffer(list(), [non_neg_integer()], atom()) ::
  {:ok, reference()} | {:error, term()}
```

Creates a GPU buffer from a list of values.

## Parameters

  * `data` — a flat list of numbers
  * `shape` — the tensor shape (e.g. `[3]` for a vector, `[2, 3]` for a matrix)
  * `type` — element type, one of: `:f32`, `:f64`, `:s32`, `:s64`, `:u32`, `:u8` (default `:f32`)

## Returns

  `{:ok, buffer}` on success where `buffer` is a Rustler resource reference.
  The buffer is automatically freed when the Elixir term is garbage collected.

## Examples

    {:ok, buf} = ExCubecl.buffer([1.0, 2.0, 3.0], [3], :f32)

# `buffer!`

```elixir
@spec buffer!(list(), [non_neg_integer()], atom()) :: reference()
```

Creates a GPU buffer, raising on error.

See `buffer/3` for parameters.

# `device_count`

```elixir
@spec device_count() :: {:ok, non_neg_integer()} | {:error, term()}
```

Returns the number of available GPU devices.

# `device_info`

```elixir
@spec device_info() :: {:ok, map()} | {:error, term()}
```

Returns information about the GPU compute device.

# `dtype`

```elixir
@spec dtype(reference()) :: {:ok, String.t()} | {:error, term()}
```

Returns the dtype string of a buffer (e.g. `"f32"`).

# `kernels`

```elixir
@spec kernels() :: {:ok, [String.t()]} | {:error, term()}
```

Returns the list of available kernel names.

# `pipeline`

```elixir
@spec pipeline() :: {:ok, non_neg_integer()} | {:error, term()}
```

Creates a new empty pipeline.

# `pipeline_add`

```elixir
@spec pipeline_add(non_neg_integer(), String.t(), [reference()], reference(), map()) ::
  :ok | {:error, term()}
```

Adds a kernel command to a pipeline.

## Parameters

  * `pipeline_id` — pipeline reference returned by `pipeline/0`
  * `kernel` — kernel name string (e.g. `"elementwise_add"`)
  * `inputs` — list of input buffer references
  * `output` — output buffer reference
  * `params` — optional map of kernel parameters (default `%{}`)

## Examples

    {:ok, pipeline} = ExCubecl.pipeline()
    ExCubecl.pipeline_add(pipeline, "elementwise_add", [buf_a, buf_b], buf_out)

# `pipeline_add_struct`

```elixir
@spec pipeline_add_struct(non_neg_integer(), ExCubecl.Command.t()) ::
  :ok | {:error, term()}
```

Adds a command to a pipeline using a `Command` struct.

## Examples

    cmd = ExCubecl.Command.run_kernel("elementwise_add", [buf_a, buf_b], buf_out)
    ExCubecl.pipeline_add_struct(pipeline, cmd)

# `pipeline_free`

```elixir
@spec pipeline_free(non_neg_integer()) :: :ok | {:error, term()}
```

Frees a pipeline and its resources.

# `pipeline_run`

```elixir
@spec pipeline_run(non_neg_integer()) :: {:ok, [non_neg_integer()]} | {:error, term()}
```

Runs all commands in a pipeline sequentially.

# `poll`

```elixir
@spec poll(non_neg_integer()) ::
  {:ok, :pending | :running | :completed | :failed} | {:error, term()}
```

Polls the status of an async command.

Returns `{:ok, :pending | :running | :completed | :failed}` or `{:error, reason}`.

# `read`

```elixir
@spec read(reference()) :: {:ok, binary()} | {:error, term()}
```

Reads buffer data back from the GPU as a binary.

# `read!`

```elixir
@spec read!(reference()) :: binary()
```

Reads buffer data back, raising on error.

# `run_kernel`

```elixir
@spec run_kernel(String.t(), [reference()], reference(), map()) ::
  {:ok, non_neg_integer()} | {:error, term()}
```

Runs a kernel on the GPU.

## Parameters

  * `name` — kernel name string (see `kernels/0`)
  * `inputs` — list of input buffer references
  * `output` — output buffer reference
  * `params` — optional map of kernel parameters (default `%{}`)

# `shape`

```elixir
@spec shape(reference()) :: {:ok, [non_neg_integer()]} | {:error, term()}
```

Returns the shape of a buffer.

# `size`

```elixir
@spec size(reference()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Returns the byte size of a buffer.

# `submit`

```elixir
@spec submit(String.t()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Submits a command for asynchronous execution.

Returns `{:ok, command_id}` which can be used with `poll/1` and `wait/1`.

# `supported_dtypes`

```elixir
@spec supported_dtypes() :: [atom()]
```

Returns the list of supported dtype atoms.

# `version`

```elixir
@spec version() :: String.t()
```

Returns the version of ExCubecl.

# `wait`

```elixir
@spec wait(non_neg_integer()) :: :ok | {:error, term()}
```

Blocks until an async command completes.

---

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