Generates binary protocol specifications from plugin schemas.
This module auto-generates field mappings and encoders for plugin-defined properties, preventing protocol chaos through systematic field numbering.
Field Numbering
Each property in a component gets a unique field number:
prop "volume", :f32
# → FIELD_VOLUME = 0x07
# → [f32]Field numbers are assigned sequentially starting from 0x01 for each component, ensuring no collisions within a plugin.
Binary Format
The protocol uses a compact binary format:
+--------+--------+--------+--------+
| opcode | id | field | value |
+--------+--------+--------+--------+
1 byte 8 bytes 1 byte N bytesWhere:
- opcode: CREATE_NODE, UPDATE_PROP, etc.
- id: 64-bit node identifier
- field: field number (0x01-0xFF)
- value: type-encoded value
Type Encoding
| Type | Tag | Size | Format |
|---|---|---|---|
| string | 0x01 | var | UTF-8 + len |
| bool | 0x02 | 1 | 0x00/0x01 |
| int | 0x03 | 8 | signed 64-bit |
| float | 0x04 | 8 | 64-bit IEEE |
| f32 | 0x05 | 4 | 32-bit IEEE |
| f64 | 0x06 | 8 | 64-bit IEEE |
| color | 0x07 | 4 | ARGB |
| binary | 0x08 | var | len + data |
Capability Negotiation & Lifecycle Events
The protocol also encodes capability negotiation and lifecycle events:
# Capability negotiation
encode_capability_negotiation([:gestures, :animation], [:gestures, :accessibility, :animation])
# → binary with requested + provided capabilities
# Lifecycle events
encode_lifecycle_event(:init, %{opts: []})
encode_lifecycle_event(:activate, %{})
encode_lifecycle_event(:cleanup, %{})Example
defmodule MyApp.VideoPlugin do
use Dala.Plugin
component "video" do
prop "source", :string
prop "volume", :f32
prop "autoplay", :bool
end
endGenerates:
FIELD_SOURCE = 0x01
FIELD_VOLUME = 0x02
FIELD_AUTOPLAY = 0x03
# Encoding {"video.mp4", 0.8, true}:
# 01 00 00 00 00 00 00 00 00 # id (8 bytes)
# 01 0B 76 69 64 65 6F 2E 6D # field 01, string "video.mp4"
# 70 02 00 00 00 00 02 03 10 # field 02, f32 0.8
# 03 01 # field 03, bool true
Summary
Functions
Builds a global field map for quick lookup.
Encodes a capability negotiation message.
Encodes a lifecycle event message.
Encodes a property update for a node.
Encodes a value according to its type tag.
Generates example encoded data for documentation.
Generates protocol specification for a plugin.
Generates field mappings for a single component.
Converts a prop type to its binary type tag.
Types
Functions
Builds a global field map for quick lookup.
Encodes a capability negotiation message.
The binary format is:
- 1 byte: capability opcode (0xF1)
- 2 bytes: count of requested capabilities
- For each capability: 2 bytes length + UTF-8 name
- 2 bytes: count of provided capabilities
- For each capability: 2 bytes length + UTF-8 name
Encodes a lifecycle event message.
The binary format is:
- 1 byte: lifecycle opcode (0xF0)
- 2 bytes: event name length
- N bytes: event name (UTF-8)
- 4 bytes: payload length
- M bytes: payload (JSON-encoded)
@spec encode_prop_update(String.t(), field_number(), type_tag(), term()) :: binary()
Encodes a property update for a node.
Encodes a value according to its type tag.
@spec example_encoding(Dala.Plugin.Component.t()) :: String.t()
Generates example encoded data for documentation.
@spec generate(Dala.Plugin.t()) :: map()
Generates protocol specification for a plugin.
Returns a map containing field mappings and encoding helpers.
@spec generate_component(Dala.Plugin.Component.t()) :: map()
Generates field mappings for a single component.
@spec type_to_tag(Dala.Plugin.Component.prop_type()) :: type_tag()
Converts a prop type to its binary type tag.