# `Tempo.IntervalSet.Backend`
[🔗](https://github.com/elixir-tempo/tempo/blob/v1.6.4/lib/tempo/interval_set/backend.ex#L1)

The behaviour a `Tempo.IntervalSet` storage backend implements.

An interval set's representation is pluggable: the set struct carries a
`:backend` module and an opaque backend `state` (in its `:intervals`
field), and every `Tempo.IntervalSet` function reaches the members
through this contract rather than assuming a concrete data structure.
`Tempo.IntervalSet.Backend.List` — a sorted plain list — is the default
and the reference implementation.

## The contract

The universal primitive is the **ordered walk**: `walk/1` returns an
enumerable that yields the member intervals in time order, sorted by
`from` endpoint, disjoint, each half-open `[from, to)`. A backend is
correct as soon as it can walk; the remaining callbacks exist so a
backend can answer common questions without a full walk, and default
to walk-derived implementations via `use Tempo.IntervalSet.Backend`.

`bounded?/1` is the honesty bit: a backend over a finite member list
returns `true`; a lazy backend over a potentially unbounded generator
returns `false`, and aggregate operations (`to_list/1`, `count/1`,
set-wide duration) refuse rather than walk forever. Callers must
consult `bounded?/1` before calling `to_list/1` or `count/1`.

## Implementing a backend

    defmodule MyBackend do
      use Tempo.IntervalSet.Backend

      @impl true
      def from_list(intervals, _options), do: build_my_state(intervals)

      @impl true
      def to_list(state), do: my_state_to_list(state)

      @impl true
      def walk(state), do: my_lazy_stream(state)

      @impl true
      def bounded?(_state), do: true
    end

`use` provides overridable `count/1`, `empty?/1`, and `first/1`
derived from `to_list/1` and `walk/1`; override them when the
representation can answer faster (a tree knows its size; any backend
can peek its first member without materialising).

Construct a set on a specific backend with
`Tempo.IntervalSet.new(intervals, backend: MyBackend)`. Set operations
preserve the backend of member-preserving results; newly constructed
extents default to the list backend.

# `state`

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

The backend's opaque representation of the member intervals. For the
list backend this is the member list itself; other backends choose
their own shape.

# `bounded?`

```elixir
@callback bounded?(state()) :: boolean()
```

Whether the member list is finite. Aggregate operations consult this
before materialising; `false` makes them refuse rather than hang.

# `count`

```elixir
@callback count(state()) :: non_neg_integer()
```

The number of members. Only valid when `bounded?/1` is `true`.

# `empty?`

```elixir
@callback empty?(state()) :: boolean()
```

Whether the set has no members. Safe on every backend — peeking one
element never requires a full walk.

# `first`

```elixir
@callback first(state()) :: Tempo.Interval.t() | nil
```

The earliest member, or `nil` when empty. Safe on every backend.

# `from_list`

```elixir
@callback from_list(
  [Tempo.Interval.t()],
  keyword()
) :: state()
```

Build backend state from a sorted, disjoint member list.

`Tempo.IntervalSet.new/2` validates, sorts, and (by default)
coalesces the members before calling this — the backend may assume
time order and disjointness.

# `overlapping`

```elixir
@callback overlapping(
  state(),
  {number(), number()}
) :: [Tempo.Interval.t()]
```

Candidate members whose extent may intersect the half-open UTC-second
range `[lo, hi)`.

A **pruning** callback, not a semantic one: the contract is to return
*at least* every member whose `[from, to)` intersects the range — a
backend may return extra members, or all of them (the default). The
caller applies the exact resolution-aware check to the candidates, so
a backend that prunes well (an interval tree) accelerates stabbing
and overlap queries without owning their semantics.

# `to_list`

```elixir
@callback to_list(state()) :: [Tempo.Interval.t()]
```

The members as a plain list in time order. Only valid when
`bounded?/1` is `true`; an unbounded backend raises.

# `walk`

```elixir
@callback walk(state()) :: Enumerable.t()
```

An enumerable yielding the members in time order. The universal
primitive: safe on every backend, lazy where the backend is lazy.

---

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