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

Minimal `:gen_statem`-shaped wrapper that runs under Lockstep's
controller. Supports the `handle_event_function` callback mode -- one
`handle_event/4` clause per `(event_type, event_content, state, data)`
combination -- which is the pattern most modern Elixir code uses.

Replies for `:call` events go through `{:reply, From, Reply}` actions,
same as real `:gen_statem`.

## Limitations (v0.5)

  * `callback_mode :state_functions` is NOT supported -- use
    `:handle_event_function` only.
  * No `:state_timeout`, `:generic_timeout`, or `:event_timeout`
    actions; use `Lockstep.send_after/3` from inside `handle_event/4`
    and pattern-match on the resulting `:info` event instead.
  * No `:postpone` action; the event you got is the event you handle.
  * No `terminate/3` callback.
  * `handle_event/4` may return:
    `{:next_state, new_state, new_data}` /
    `{:next_state, new_state, new_data, actions}` /
    `{:keep_state, new_data}` /
    `{:keep_state, new_data, actions}` /
    `:keep_state_and_data` /
    `{:keep_state_and_data, actions}` /
    `{:stop, reason, _data}`. Each `actions` element is `{:reply, From, Reply}`.

## Example

    defmodule Door do
      def init(_), do: {:ok, :closed, nil}

      def handle_event(:call, :open, :closed, data),
        do: {:next_state, :open, data, [{:reply, from(), :ok}]}

      def handle_event(:call, :open, :open, data),
        do: {:keep_state, data, [{:reply, from(), :already_open}]}

      def handle_event(:call, :state, state, data),
        do: {:keep_state, data, [{:reply, from(), state}]}
    end

In practice you receive `from` as the third argument of `handle_event`
(when `event_type == :call`); your implementation typically captures
it locally and uses it in `[{:reply, from, ...}]`.

Real `:gen_statem` passes `from` as part of the event content for
call events; this wrapper does the same -- `event_content` for a call
is `{from, request}`. Reply via `{:reply, from, value}` action.

# `from`

```elixir
@type from() :: {pid(), reference()}
```

# `server`

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

# `call`

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

Synchronous request -- blocks (in the controller) for the matching
`{:reply, from, _}` action emitted by `handle_event/4`.

# `cast`

```elixir
@spec cast(server(), any()) :: :ok
```

Fire-and-forget request.

# `start_link`

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

Spawn a managed gen_statem process. Returns `{:ok, pid}` to match
OTP's `:gen_statem.start_link/3` shape.

---

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