# `Rupa.Closure`
[🔗](https://github.com/zero-one-group/rupa/blob/v0.1.0/lib/rupa/closure.ex#L1)

The closure backend: `Rupa.IR` in, a tree of anonymous functions out.

One function per IR node, each closing over everything the node decided at staging time —
the compiled regex, the format's decoder, the wire key, the default. A decode is then a walk
down a tree of calls with no interpretation and no lookups, except at a recursive ref, which
is the one place a table is consulted.

Every decoder has the same shape, `(value, ctx) -> {:ok, decoded} | {:error, [Rupa.Error])`,
where `ctx` is `{mode, defs}`. Paths are built on the way back up: a leaf reports an error
with an empty path and each parent prepends its own segment, so a successful decode allocates
nothing for paths at all.

# `ctx`

```elixir
@type ctx() :: {:halt | :collect, %{required(atom()) =&gt; decoder()}}
```

# `decoder`

```elixir
@type decoder() :: (term(), ctx() -&gt; {:ok, term()} | {:error, [Rupa.Error.t()]})
```

# `build`

```elixir
@spec build(Rupa.IR.program()) :: {decoder(), %{required(atom()) =&gt; decoder()}}
```

Builds the root decoder and the table the recursive refs resolve against.

`Rupa.Codec.new/2` calls this and its two siblings; you reach what they build through
`Rupa.decode/3` rather than by holding one:

    {:ok, program} = Rupa.Stage.run(%{name: Rupa.T.string()})
    {decode, defs} = Rupa.Closure.build(program)
    decode.(%{"name" => "Ada"}, {:halt, defs})
    #=> {:ok, %{name: "Ada"}}

# `build_encoder`

```elixir
@spec build_encoder(Rupa.IR.program()) ::
  {decoder(), %{required(atom()) =&gt; decoder()}}
```

The same as `build/1`, and used the same way, in the other direction.

# `build_json`

```elixir
@spec build_json(Rupa.IR.program()) :: {decoder(), %{required(atom()) =&gt; decoder()}}
```

The other direction again, straight to JSON iodata rather than to a wire term.

Built and used exactly as `build/1` is; what it hands back emits bytes rather than a term.

---

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