# `Crank.Machine`
[🔗](https://github.com/code-of-kai/crank/blob/v0.2.0/lib/crank/machine.ex#L1)

The struct that `Crank.crank/2` takes and returns.

`%Crank.Machine{}` carries five fields:

  * `:module` -- the callback module that defines the machine's transitions
  * `:state` -- the current state (any term: atoms, structs, tagged tuples)
  * `:data` -- data shared across all states, carried through every crank
  * `:effects` -- side effects from the last crank, stored as inert data
  * `:status` -- `:running` or `{:stopped, reason}`

The struct never executes side effects. It stores them. `Crank.Server`
interprets and executes effects when the machine runs as a process. In
pure code, inspect them directly.

Each call to `Crank.crank/2` replaces the effects list. Effects from
earlier cranks don't accumulate.

## Parameterized types

`t/0` is the generic type. For precise typing in your own modules,
use `t/2` with concrete state and data types:

    @spec get_machine() :: Crank.Machine.t(:locked | :unlocked, map())

See `Crank.Examples.Submission` for the struct-per-state pattern,
where each state is its own struct.

# `action`

```elixir
@type action() ::
  :postpone
  | :hibernate
  | reply_action()
  | event_timeout()
  | state_timeout()
  | named_timeout()
  | next_event_action()
```

Any `gen_statem` action that can appear in an effects list.

# `event_timeout`

```elixir
@type event_timeout() ::
  {:timeout, non_neg_integer() | :infinity, term()}
  | {:timeout, non_neg_integer() | :infinity, term(), keyword()}
```

Fires if no event arrives within the given period.

# `named_timeout`

```elixir
@type named_timeout() ::
  {{:timeout, term()}, non_neg_integer() | :infinity, term()}
  | {{:timeout, term()}, non_neg_integer() | :infinity, term(), keyword()}
```

A timeout identified by a caller-chosen name. Multiple named timeouts can run concurrently.

# `next_event_action`

```elixir
@type next_event_action() :: {:next_event, Crank.event_type(), term()}
```

Injects a new event into the machine's own event queue.

# `reply_action`

```elixir
@type reply_action() :: {:reply, GenServer.from(), term()}
```

Sends a reply to a caller waiting on `Crank.Server.call/3`.

# `state_timeout`

```elixir
@type state_timeout() ::
  {:state_timeout, non_neg_integer() | :infinity, term()}
  | {:state_timeout, non_neg_integer() | :infinity, term(), keyword()}
```

Fires if the machine stays in the current state for the given period.

# `status`

```elixir
@type status() :: :running | {:stopped, reason :: term()}
```

`:running` while the machine accepts events. `{:stopped, reason}` after it shuts down.

# `t`

```elixir
@type t() :: t(term(), term())
```

A machine with generic (unparameterized) state and data types.

# `t`

```elixir
@type t(state, data) :: %Crank.Machine{
  data: data,
  effects: [action()],
  module: module(),
  state: state,
  status: status()
}
```

A machine parameterized by its state and data types.

    @spec checkout_machine() :: Crank.Machine.t(:cart | :payment | :complete, Order.t())

---

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