# `Ankusa.Storage.Index`
[🔗](https://github.com/jamescarr/ankusa/blob/ankusa-v0.7.0/packages/ankusa/lib/ankusa/storage/index.ex#L1)

The index object beside a segment: `%{event_id => {offset, length, seq}}`.

## Format 1

    "ANKIDX" <> <<version::8, count::32>>   (11 bytes)
    :erlang.term_to_binary(index)
    sha256(everything above)                (32 bytes)

The term is decoded with `binary_to_term(bin, [:safe])`, so an object that
names an atom this node has never seen, or carries a fun or a pid, is refused
rather than executed or interned, and the decoded shape is checked (binary ids
to three non-negative integers, as many as `count` says) before anything else
sees it.

## Format 0

The bare `term_to_binary` map the compactor wrote before the header existed.
It is read the same way (`[:safe]` and the shape check), so legacy segments
stay readable and a hostile or damaged one is `{:error, :bad_index}`.

# `t`

```elixir
@type t() :: %{
  optional(String.t()) =&gt; {non_neg_integer(), pos_integer(), pos_integer()}
}
```

# `decode`

```elixir
@spec decode(binary()) :: {:ok, t()} | {:error, atom()}
```

Decode an index object of either format: `{:ok, index}`, or
`{:error, :bad_index | :unsupported_format | :sha_mismatch}`.

# `encode`

```elixir
@spec encode(t()) :: binary()
```

Encode `index` (`%{id => {offset, length, seq}}`) as a format 1 object.

# `frames_end`

```elixir
@spec frames_end(t()) :: non_neg_integer()
```

Where an index ends: the end of the last frame, the position the trailer starts at.

# `id_range`

```elixir
@spec id_range(t()) :: {String.t(), String.t()}
```

The lowest and highest event id of an index: `{min_id, max_id}`.

---

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