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

GenServer-shaped wrapper that runs under Lockstep's controller.

Exposes `start_link/2`, `call/2`, `cast/2`, and `stop/1` — the subset of
the `GenServer` API that round-trips through Lockstep's controlled
send / selective-receive primitives. Use this when you want to test a
module that follows the `GenServer` callback contract without rewriting
it to use bare send/recv.

## Limitations (v0.5)

  * Calls do not honour `:timeout`s; everything blocks indefinitely
    under the controller. The runner's per-iteration timeout still
    applies.
  * No supervision tree; `start_link/2` returns a raw managed pid.
  * No process registration. Pass the pid around explicitly.
  * Callback module must implement `init/1`, plus any of
    `handle_call/3`, `handle_cast/2`, `handle_info/2` it needs.
  * `terminate/2` and `code_change/3` are not invoked.

## Example

    defmodule Counter do
      def init(_), do: {:ok, 0}
      def handle_call(:get, _from, n), do: {:reply, n, n}
      def handle_cast({:add, x}, n), do: {:noreply, n + x}
    end

    ctest "counter increments" do
      {:ok, srv} = Lockstep.GenServer.start_link(Counter, [])
      Lockstep.GenServer.cast(srv, {:add, 5})
      assert Lockstep.GenServer.call(srv, :get) == 5
    end

# `server`

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

# `state`

```elixir
@type state() :: any()
```

# `call`

```elixir
@spec call(server() | {:via, module(), term()}, any()) :: any()
```

Synchronous request. Blocks (in the controller) until the server
replies. Selective-receive-matched on a unique reference, so other
messages in the caller's mailbox are not disturbed.

Mirrors OTP semantics for a dead target: monitors the server before
sending; if a `:DOWN` arrives before a reply, raises an `:exit`
matching `GenServer.call/2`'s contract. This is what lets call
sites use `try/catch :exit, _` -- same as vanilla OTP -- to handle
"the server died while we were waiting" cleanly.

# `call`

```elixir
@spec call(server(), any(), timeout()) :: any()
```

Three-arg call form for OTP source compatibility. The `timeout` is
ignored -- Lockstep blocks via the controller's per-iteration
timeout instead.

# `cast`

```elixir
@spec cast(server() | {:via, module(), term()}, any()) :: :ok
```

Fire-and-forget request.

# `reply`

```elixir
@spec reply(
  {pid(), reference()},
  any()
) :: :ok
```

OTP-shape `reply` for handle_call clauses that returned `:noreply`
and need to reply asynchronously. Same contract as `GenServer.reply/2`:
given a `{caller_pid, request_ref}` tuple and a value, sends
`{ref, value}` to the caller.

# `start`

```elixir
@spec start(module(), any()) :: {:ok, pid()}
```

Unlinked variant -- same as `start_link/3` for Lockstep purposes.

# `start`

```elixir
@spec start(module(), any(), keyword()) ::
  {:ok, pid()} | {:error, {:already_started, pid()}}
```

Three-arg unlinked variant.

# `start_link`

```elixir
@spec start_link(module(), any()) :: {:ok, pid()} | {:stop, term()} | :ignore
```

Spawn a managed GenServer process. Returns `{:ok, pid}` so that
vanilla OTP-style call sites (`{:ok, srv} = GenServer.start_link(...)`)
remain pattern-compatible after `Lockstep.Rewriter` rewrites them.

Failures inside `init/1` raise on the spawned process and propagate
as a normal child crash to Lockstep's controller.

# `start_link`

```elixir
@spec start_link(module(), any(), keyword()) ::
  {:ok, pid()} | {:error, {:already_started, pid()}}
```

Three-arg form for OTP source compatibility.

The `opts` keyword may include:

  * `:name` -- only `{:via, Lockstep.Registry, {reg, key}}` form is
    modeled. Atom names are accepted but ignored (Lockstep doesn't
    have a global name table). Other `:via` modules are accepted
    and forwarded.

If a `:via` registration fails (key already taken), returns
`{:error, {:already_started, pid}}` matching OTP's contract.

# `start_link`

```elixir
@spec start_link(
  {:local, atom()} | {:via, module(), term()},
  module(),
  any(),
  keyword()
) ::
  {:ok, pid()} | {:error, {:already_started, pid()}}
```

Erlang gen_server-style 4-arg start_link. The first argument is a
registration shape:

  * `{:local, atom}` -- register locally as that atom (BEAM
    `Process.register/2`).
  * `{:via, mod, term}` -- delegate to a registry module.
  * `{:global, _}` -- not supported (no global name table modeled).

After registration, behaves like `start_link/3`. Mirrors OTP's
`gen_server:start_link/4`.

# `stop`

```elixir
@spec stop(server() | {:via, module(), term()}, any()) :: :ok
```

Send a stop signal. The server runs `terminate/2` is *not* invoked.

# `stop`

```elixir
@spec stop(server() | {:via, module(), term()}, any(), timeout()) :: :ok
```

Three-arg stop form for OTP source compatibility. Timeout ignored.

---

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