# Executors

> USearch for Zig

One executor serves any number of indexes, and its kind must match the residency their handles were built for.
There is a constructor per C one, each taking a config of exactly what its C structure takes:

```zig
var sockets = try usearch.Executor.forRam(.{ .memory_domains = &.{ 0, 1 }, .threads = 0 });
var shared = try usearch.Executor.onPool(fork_union_pool, .{ .memory_domains = &.{0} }); // borrows a `fu_pool_t`
var gpus = try usearch.Executor.forVram(.{ .devices = &.{ 0, 1 }, .streams = null, .scratch_limit = 0 });
var drives = try usearch.Executor.forNvme(.{ .paths = &.{.of("/mnt/nvme0")}, .threads = 0 });
```

Zero threads takes 7/8 of the cores, since full occupancy starves the ordered publication path; `forVram` takes no thread count at all, driving one stream per device from the calling thread, either its own or one of the CUDA streams you lend.
`drain(mood)` waits until no call holds the executor, then lets the threads go `.parked` or stay `.spinning` once idle.

### Receivers & Deferred Calls

The receiver chooses where a verb runs and how it completes, and the verb stays the same.
The index runs it on the calling thread, `index.on(executor)` blocks on an executor, refused while another call holds it, and `index.deferred(executor, &call)` submits it there into a `usearch.Deferred` you hold:

```zig
const here = try index.search(queries, 10, &arena, .{});               // the calling thread
const there = try index.on(executor).search(queries, 10, &other, .{}); // blocking, on the executor
var call: usearch.Deferred(usearch.DenseSearch) = undefined;
try index.deferred(executor, &call).search(queries, 10, &spare, .{});  // submitted, into `call`
defer call.deinit();
```

`DenseIndex.On` and `DenseIndex.DeferredOn(Call)` offer every verb the index does, with the same arguments, the `*Arena` included, because one generic writes each verb once for both; a deferred receiver compiles only the verb its storage holds.
Constructors address no index yet, so no receiver offers them; the ones the C interface lets fan out take an `executor` in their config, and run on the calling thread without one.

A `Deferred` owns what the library reports into until its call is final, the outcome and any fixed-size result, and borrows the rest, as a blocking call does.
The handles it names, such as the index, the executor, the arena, a cursor or a stream, need nothing more: freeing one waits for every deferred call naming it.
The plain memory it reads, such as the rows, the keys, the path, the carry and the handlers' contexts, stays yours, and must outlive the call.

```zig
var call: usearch.Deferred(usearch.DenseGet) = undefined;
try index.deferred(executor, &call).get(key, .f32, &arena);
defer call.deinit();
if (call.status() == .deferred) {
    // other work
}
const vectors = try call.wait(); // the view a blocking `get` answers, valid until the next call given `arena`
```

The storage is yours to place, so submitting allocates nothing: a stack slot, a field, or an array of them for a batch of submitted calls.
The library reports into the storage, so a submitted `Deferred` stays put until `deinit`; a heap slot comes from `allocator.create` and is destroyed after `deinit`.
Zig has no async keyword left to lean on, so a deferred call is waited on and nothing else: `status` reads the outcome with acquire ordering and never blocks, and `wait` blocks in the library until the call is final and answers its result or error, the same one however often it is asked.
`deinit` waits the same way, and the slot can then hold another call.
A `Deferred` has one owner: `wait` and `deinit` never run on two threads at once, while `status` reads from any.
`message` answers the static detail of the final status, empty until the call is final and on success.
One call holds an executor at a time, so a second call finding it held finishes at once with `Error.Contended`, and nothing queues.
A deferred call on a caller-exclusive pool runs on the pool's thread 0, so polling `status` alone finishes it, and its progress handler and predicate run on the pool's threads; a single thread, WebAssembly or a VRAM executor runs it at submission.
Calls depending on each other are ordered by waiting on the first before submitting the second.
A shape only the binding can check, like a key run longer than its rows, is refused before anything is submitted, so the submitting call itself fails and the slot holds nothing to `deinit`.

`const usearch = @import("usearch");`

`const Mood = @import("usearch").Mood;`

`const Executor = @import("usearch").Executor;`

`const Deferred = @import("usearch").Deferred;`

## ExecutorForRamConfig

Optional settings of [`Executor.forRam`](#forRam), mirroring `usearch_executor_for_ram_t`.

```zig
pub const ExecutorForRamConfig = struct
```

- `memory_domains` `[]const i32`: The memory domains of the indexes it will drive; empty derives every node the process may use.
- `threads` `usize`: Threads to spawn; zero takes 7/8 of the cores those domains carry.
- `deferred_limit` `usize`: Deferred calls it tracks at once, sizing its deferred table; zero takes a default.
- `diagnostics` `?*Outcome`: Where the call's final outcome, its static message included, is copied; null copies nothing.

## ExecutorOnPoolConfig

Optional settings of [`Executor.onPool`](#onPool), mirroring `usearch_executor_on_pool_t`.

```zig
pub const ExecutorOnPoolConfig = struct
```

- `memory_domains` `[]const i32`: The memory domains of the indexes it will drive; empty derives every node the process may use.
- `deferred_limit` `usize`: Deferred calls it tracks at once, sizing its deferred table; zero takes a default.
- `diagnostics` `?*Outcome`: Where the call's final outcome, its static message included, is copied; null copies nothing.

## ExecutorForVramConfig

Optional settings of [`Executor.forVram`](#forVram), mirroring `usearch_executor_for_vram_t`.

```zig
pub const ExecutorForVramConfig = struct
```

- `devices` `[]const i32`: The devices of the indexes it will drive; empty derives one free device.
- `streams` `?[]const ?*anyopaque`: Borrowed CUDA streams, one per device in `devices` order; null creates its own.
- `scratch_limit` `usize`: The ceiling on scratch bytes per device; zero lets scratch grow as geometry asks.
- `deferred_limit` `usize`: Deferred calls it tracks at once, sizing its deferred table; zero takes a default.
- `diagnostics` `?*Outcome`: Where the call's final outcome, its static message included, is copied; null copies nothing.

## ExecutorForNvmeConfig

Optional settings of [`Executor.forNvme`](#forNvme), mirroring `usearch_executor_for_nvme_t`.

```zig
pub const ExecutorForNvmeConfig = struct
```

- `paths` `[]const BytesView`: The devices of the indexes it will drive; empty leaves every shard where its manifest points.
- `threads` `usize`: Threads to spawn, one submission ring apiece; zero derives from the devices' queue capabilities.
- `deferred_limit` `usize`: Deferred calls it tracks at once, sizing its deferred table; zero takes a default.
- `diagnostics` `?*Outcome`: Where the call's final outcome, its static message included, is copied; null copies nothing.

## Mood

What an executor does with its threads or streams once it goes idle.

```zig
pub const Mood = enum(c_int)
```

Mirrors `usearch_mood_t`.

- `parked` = `1`: Park them; the next call pays a wake-up.
- `spinning` = `2`: Keep them spinning, trading power for the next call's latency.

## name

The canonical spelling, as `.parked` spells "parked".

```zig
pub fn name(self: Mood) [:0]const u8
```

Calls `usearch_mood_name`.

## fromName

Reads a spelling back, or null when no mood spells it.

```zig
pub fn fromName(text: []const u8) ?Mood
```

Calls `usearch_mood_from_name`.

## Executor

The host threads or device streams that advance a call, and the traversal scratch each of them walks with - everything a verb needs to run but an index does not own.

```zig
pub const Executor = struct
```

One executor serves any number of index handles, and its kind is fixed by the constructor that
produced it: it must match the residency of every handle it drives, or the call reports
[`Error.Device`](https://www.unum.cloud/docs/usearch/zig/errors.md#Device). A verb called on the index itself takes no executor and runs on the calling thread.

Calls on one executor run in submission order; handles stay freely concurrent - it is the
executor that orders, never the index. An executor without threads of its own holds a deferred
call until its wait, its next [`drain`](#drain) or blocking call, or the free of a handle it names.

- `handle` `?*anyopaque`: The opaque `usearch_executor_t` the ABI hands back.
- `residency` `Residency`: The residency of the constructor that produced it, which places the arenas it makes.

## forRam

Spawns host threads for RAM-resident indexes across the domains local to `memory_domains`, which should be the very slice the indexes were placed with.

```zig
pub fn forRam(config: ExecutorForRamConfig) Error!Executor
```

Zero `threads` takes 7/8 of the cores those domains carry, because full occupancy starves
the ordered publication path. Calls `usearch_executor_for_ram`.

## onPool

Creates a RAM executor over a borrowed ForkUnion `fu_pool_t`, so several libraries in one process share one set of threads; the pool must outlive the executor, and keeps its lender's mood.

```zig
pub fn onPool(
    pool: *anyopaque,
    config: ExecutorOnPoolConfig,
) Error!Executor
```

Calls `usearch_executor_on_pool`.

## forNvme

Spawns host threads for NVMe-resident indexes, one submission ring apiece, across the domains local to the devices `paths` names.

```zig
pub fn forNvme(config: ExecutorForNvmeConfig) Error!Executor
```

Calls `usearch_executor_for_nvme`.

## forVram

Opens one submission stream on every named device, or borrows `streams`, one CUDA stream per device in `devices` order, all driven by whichever host thread submits.

```zig
pub fn forVram(config: ExecutorForVramConfig) Error!Executor
```

Calls `usearch_executor_for_vram`.

## drain

Waits for every call submitted before the drain began, then sets the mood the executor adopts whenever it next goes idle.

```zig
pub fn drain(self: Executor, mood: Mood) Error!void
```

Reports only what befell the executor itself.
Calls `usearch_executor_drain`.

## deinit

Drains every call, releases the scratch and the streams it owns, and frees the executor, which is invalid afterwards; the host arenas it made keep their memory, while its GPU arenas must be freed first.

```zig
pub fn deinit(self: *Executor) void
```

Calls `usearch_executor_free`.

## Deferred

A submitted call, held in storage the caller places - on the stack, in a struct, or from an allocator - which owns its outcome until the call is final, while the arena, the handles and the slices it was handed stay borrowed until then.

```zig
pub fn Deferred(comptime Call: type) type
```

[`status`](#status) polls without blocking, [`wait`](#wait) blocks until the call is final and answers its result or
error - the same one however often it is asked - and [`deinit`](https://www.unum.cloud/docs/usearch/zig/retrieval-and-streaming.md#deinit) waits the same way. A submitted
[`Deferred`](#Deferred) stays put until [`deinit`](https://www.unum.cloud/docs/usearch/zig/retrieval-and-streaming.md#deinit), and has one owner: [`wait`](#wait) and [`deinit`](https://www.unum.cloud/docs/usearch/zig/retrieval-and-streaming.md#deinit) never run on two
threads at once, while [`status`](#status) reads from any.

- `call` `Call`
- `answer` `?(Error!Call.Result)`

## submit

Copies `call` into `self`, which stays put until final, and submits it.

```zig
pub fn submit(
    self: *Self,
    call: Call,
    index: ?*anyopaque,
    executor: ?*anyopaque,
) void
```

Binding-only.

## status

`.deferred` until the call is final, then its final status.

```zig
pub fn status(self: *Self) Status
```

## message

The static detail of the final status; empty until the call is final, and on success.

```zig
pub fn message(self: *Self) [:0]const u8
```

## wait

Blocks until the call is final, then answers its result, the same views a blocking call answers over the arena it borrowed.

```zig
pub fn wait(self: *Self) Error!Call.Result
```

One thread waits at a time.

## deinit

Blocks until the call is final; the storage is reusable afterwards, and the result's views stay as valid as the arena keeps them.

```zig
pub fn deinit(self: *Self) void
```

Calls `usearch_outcome_wait`.

