# `Pbwire.Schema`

Turns `elixir-protobuf` generated modules into the schema cache the NIF
understands.

This is the Elixir half of the rule the Erlang binding documents: gpb is
the plugin there (`get_msg_defs/0` in, records out), `elixir-protobuf` is
the plugin here (`__message_props__/0` in, structs out). There is no
second wire implementation and no `.proto` parsing in this package: field
numbers, types, presence and packedness all come from the generated
`FieldProps`, and the bytes stay in the C core behind `:pbwire`.

Message and enum names in the generated defs are the Elixir module atoms
themselves, so two schemas can never collide the way unqualified gpb
record names can.

# `field`

```elixir
@type field() :: %{
  key: atom(),
  fnum: non_neg_integer(),
  rnum: pos_integer(),
  kind: field_kind(),
  occurrence: :required | :optional | :repeated | :defaulty,
  packed?: boolean(),
  default: term()
}
```

# `field_kind`

```elixir
@type field_kind() ::
  {:scalar, atom()}
  | {:enum, module()}
  | {:message, module()}
  | {:map, atom(), field_kind()}
  | {:oneof, atom(), [map()]}
```

# `spec`

```elixir
@type spec() :: %{
  mod: module(),
  name: atom(),
  syntax: :proto2 | :proto3,
  fields: [field()],
  by_key: %{required(atom()) =&gt; field()},
  enum_values: %{required(integer()) =&gt; atom()} | nil
}
```

# `build`

```elixir
@spec build([module()]) ::
  {:ok, {list(), %{required(module()) =&gt; spec()}}} | {:error, String.t()}
```

Builds the `:pbwire.load_cache/1` defs for `modules` plus every message
and enum they reference, and the per-module specs `Pbwire` translates
structs with. Pure: no NIF call, safe to unit test.

# `nif_opts`

```elixir
@spec nif_opts(keyword()) :: keyword()
```

The `:pbwire.set_opts/1` list for the given `Pbwire.load_schema/2` opts.

---

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