# `ToonEx.Btoon.Schema`
[🔗](https://github.com/ohhi-vn/toon_ex/blob/v1.6.0/lib/toon_ex/btoon/dictionary.ex#L146)

A named, typed record schema for schema-mode encoding.

In schema mode the encoder omits keys and type tags entirely, emitting
`SchemaID` followed by ordered, fixed-width values. The decoder reads the
values strictly according to the schema, which is either embedded in the
envelope (schema flag) or supplied through `Btoon.decode/2` options.

Field types are `Btoon.ElementType` atoms: fixed-width numeric types
(`:int8`..`:float64`), plus `:null`, `:bool`, `:string`, `:binary`, `:array`
and `:object`.

## Persistent Term Storage

For sharing a schema across many processes without deep-copying
on each message send, use `:persistent_term`:

    iex> schema = Btoon.Schema.new(100, "Player", [%{name: "id", type: :int32}])
    iex> Btoon.Schema.put_persistent(:player_schema, schema)
    iex> schema = Btoon.Schema.get_persistent(:player_schema)
    iex> Btoon.Schema.fields(schema)
    [%{name: "id", type: :int32}]

## Examples

    iex> schema = Btoon.Schema.new(100, "Player", [
    ...>   %{name: "id", type: :int32},
    ...>   %{name: "x", type: :float32},
    ...>   %{name: "y", type: :float32},
    ...>   %{name: "hp", type: :uint16}
    ...> ])
    iex> Btoon.Schema.fields(schema)
    [%{name: "id", type: :int32}, %{name: "x", type: :float32}, %{name: "y", type: :float32}, %{name: "hp", type: :uint16}]

# `field`

```elixir
@type field() :: %{name: String.t(), type: ToonEx.Btoon.Types.element_type()}
```

# `t`

```elixir
@type t() :: %ToonEx.Btoon.Schema{
  envelope: iodata(),
  envelope_size: non_neg_integer(),
  fields: [field()],
  id: integer(),
  name: String.t()
}
```

# `delete_persistent`

```elixir
@spec delete_persistent(term()) :: :ok
```

Deletes a schema from `:persistent_term`.

Warning: this triggers a full garbage collection sweep across all
processes on the node. Use sparingly.

# `field_count`

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

Number of fields.

# `fields`

```elixir
@spec fields(t()) :: [field()]
```

Returns the field definitions.

# `get_persistent`

```elixir
@spec get_persistent(term()) :: {:ok, t()} | :error
```

Retrieves a schema from `:persistent_term`.

Returns `{:ok, schema}` or `:error` if the key doesn't exist.

# `id`

```elixir
@spec id(t()) :: integer()
```

Returns the schema id.

# `name`

```elixir
@spec name(t()) :: String.t()
```

Returns the schema name.

# `new`

```elixir
@spec new(integer(), String.t(), [field()]) :: t()
```

Builds a schema from an id, name and field list.

# `put_persistent`

```elixir
@spec put_persistent(term(), t()) :: :ok
```

Stores a schema in `:persistent_term` under the given key.

Data in `:persistent_term` lives outside process heaps and is shared
across all processes on the node without copying on read. Updates are
expensive (global GC), so use only for write-once data like schemas
defined at application startup.

## Example

    iex> schema = Btoon.Schema.new(100, "Player", [%{name: "id", type: :int32}])
    iex> Btoon.Schema.put_persistent(:player_schema, schema)
    :ok

---

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