# `Lockstep.Registry`
[🔗](https://github.com/b-erdem/lockstep/blob/v0.1.0/lib/lockstep/registry.ex#L1)

Lockstep-aware process registry. Models the most common subset of
OTP `Registry` under Lockstep's controller, so libraries that depend
on key-based process lookup work under controlled scheduling.

## Supported

  * Unique keys (`keys: :unique`) and duplicate keys (`keys: :duplicate`).
  * `register/3`, `unregister/2`, `lookup/2`, `dispatch/3`,
    `count/1`, `keys/2`.
  * Automatic cleanup on registering-process death (via
    `Lockstep.monitor`).
  * `:via` tuple integration with `Lockstep.GenServer`:

        via = {:via, Lockstep.Registry, {reg, :my_name}}
        {:ok, _} = Lockstep.GenServer.start_link(MyMod, [], name: via)
        Lockstep.GenServer.call(via, :req)

## Not modeled

  * Partitioned registries (`partitions:` option). Single-partition only.
  * Listeners.
  * `match/4` patterns -- only `:_` lookup via `lookup/2`.
  * Meta key/value store (`meta/2`, `put_meta/3`).

Most production callers don't depend on the omitted bits; if you need
them, file an issue.

# `registry`

```elixir
@type registry() :: pid()
```

# `count`

```elixir
@spec count(registry()) :: non_neg_integer()
```

Number of registered entries across all keys.

# `dispatch`

```elixir
@spec dispatch(
  registry(),
  any(),
  ([{pid(), any()}] -&gt; any()) | {module(), atom(), [any()]}
) :: :ok
```

Dispatch a callback over every {pid, value} registered under `key`.
The callback may be:

  * a 1-arity function -- receives `[{pid, value}, ...]`
  * an `{module, function, args}` MFA tuple -- invoked as
    `apply(module, function, [entries | args])`, matching the
    shape OTP's `Registry.dispatch/4` accepts.

# `keys`

```elixir
@spec keys(registry(), pid()) :: [any()]
```

Keys registered by `pid` in `reg`. Same shape as `Registry.keys/2`.

# `lookup`

```elixir
@spec lookup(registry(), any()) :: [{pid(), any()}]
```

Look up entries under `key`. Returns `[{pid, value}]` (one entry for
unique keys, possibly many for duplicate keys), or `[]` if no
registration.

# `meta`

```elixir
@spec meta(registry(), any()) :: {:ok, any()} | :error
```

Read a `key`-keyed metadata value previously stored via `put_meta/3`.
Returns `{:ok, value}` if found, `:error` otherwise. Same shape as
OTP `Registry.meta/2`.

# `put_meta`

```elixir
@spec put_meta(registry(), any(), any()) :: :ok
```

Store metadata under `key`. Returns `:ok`. Same shape as
OTP `Registry.put_meta/3`.

# `register`

```elixir
@spec register(registry(), any(), any()) ::
  {:ok, pid()} | {:error, {:already_registered, pid()}}
```

Register the calling process under `key` with `value`.

For `:unique` registries returns `{:error, {:already_registered, pid}}`
when the key is taken. `:duplicate` always succeeds.

# `select`

```elixir
@spec select(registry(), :ets.match_spec()) :: [any()]
```

Run an ETS match spec against the registry's entries. Each entry
is shaped as `{key, pid, value}`, matching OTP `Registry.select/2`.
Useful for libraries that enumerate all subscribers via
`Registry.select`.

# `start_link`

```elixir
@spec start_link(keyword()) :: {:ok, pid()}
```

Start a registry. Options:

  * `:keys` -- `:unique` (default) or `:duplicate`.
  * `:name` -- accepted for shape compatibility with `Registry`,
    but Lockstep does not register the registry itself by name
    (pass the returned pid around or use `:via` only on regular
    Lockstep.GenServers).

# `unregister`

```elixir
@spec unregister(registry(), any()) :: :ok
```

Remove the calling process's registration under `key`. Always returns
`:ok` (no-op if no such registration).

---

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