ToonEx.Btoon.Dictionary (toon_ex v1.3.1)

Copy Markdown View Source

A session string dictionary.

A session dictionary is negotiated once per connection (see the BTOON handshake in the specification) and shared between encoder and decoder. Strings present in the dictionary are encoded as StringRef (tag 0x0B) referencing their zero-based index, avoiding repeated UTF-8 transmission.

The per-message string table carried in the envelope is layered on top of the session dictionary: entry i of the table gets ref id length(dictionary) + i.

Persistent Term Storage

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

iex> dict = Btoon.Dictionary.new(["player", "position", "velocity"])
iex> Btoon.Dictionary.put_persistent(:session_dict, dict)
iex> dict = Btoon.Dictionary.get_persistent(:session_dict)
iex> Btoon.Dictionary.ref(dict, "velocity")
2

Examples

iex> dict = ToonEx.Btoon.Dictionary.new(["player", "position", "velocity"])
iex> ToonEx.Btoon.Dictionary.entries(dict)
["player", "position", "velocity"]
iex> ToonEx.Btoon.Dictionary.ref(dict, "velocity")
2

Summary

Functions

Deletes a dictionary from :persistent_term.

Returns the dictionary entries in ref-id order.

Returns the dictionary entries as a tuple for fast indexed access.

Retrieves a dictionary from :persistent_term.

Returns the precomputed string → ref-id lookup map for the encoder's hot path.

Returns true when the dictionary contains the string.

Builds a dictionary from a list of strings.

Stores a dictionary in :persistent_term under the given key.

Returns the ref id for a string, or nil when absent.

Number of entries in the dictionary.

Types

t()

@type t() :: %ToonEx.Btoon.Dictionary{
  entries: [String.t()],
  entries_tuple: tuple(),
  index: map(),
  size: non_neg_integer()
}

Functions

delete_persistent(key)

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

Deletes a dictionary from :persistent_term.

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

entries(dictionary)

@spec entries(t()) :: [String.t()]

Returns the dictionary entries in ref-id order.

entries_tuple(dictionary)

@spec entries_tuple(t()) :: tuple()

Returns the dictionary entries as a tuple for fast indexed access.

get_persistent(key)

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

Retrieves a dictionary from :persistent_term.

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

lookup(dictionary)

@spec lookup(t()) :: %{optional(String.t()) => non_neg_integer()}

Returns the precomputed string → ref-id lookup map for the encoder's hot path.

member?(dictionary, string)

@spec member?(t(), String.t()) :: boolean()

Returns true when the dictionary contains the string.

new(entries)

@spec new([String.t()]) :: t()

Builds a dictionary from a list of strings.

put_persistent(key, dict)

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

Stores a dictionary 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 session dictionaries negotiated at connection time.

Example

iex> dict = Btoon.Dictionary.new(["player", "position"])
iex> Btoon.Dictionary.put_persistent(:my_session_dict, dict)
:ok

ref(dictionary, string)

@spec ref(t(), String.t()) :: non_neg_integer() | nil

Returns the ref id for a string, or nil when absent.

size(dictionary)

@spec size(t()) :: non_neg_integer()

Number of entries in the dictionary.