Message Definitions¶
Messages are defined in Protocol Buffer (.proto) files. Struct Frame uses these definitions to generate serialization code for each target language.
Why Proto Files¶
Proto files provide: - Language-neutral message definitions - Type safety across language boundaries - Familiar syntax for developers who know Protocol Buffers - Tooling support (syntax highlighting, linting)
Struct Frame uses proto syntax but generates different code than Google's Protocol Buffers. Messages are fixed-size packed structs, not variable-length encoded.
Packages¶
Packages group related messages and prevent name collisions:
Generated code uses the package name as a prefix or namespace depending on language.
Messages¶
Messages define the structure of data to be serialized:
message DeviceStatus {
option msgid = 1;
uint32 device_id = 1;
float battery = 2;
bool online = 3;
}
Message Options¶
msgid (required for top-level messages)
Message IDs must be unique within a package (range 0-255).
variable (optional, enables variable-length encoding)
message SensorData {
option msgid = 1;
option variable = true; // Encode only used bytes
repeated uint8 readings = 1 [max_size=100];
}
With variable encoding, arrays and strings only transmit actual used bytes instead of the full max_size. This reduces bandwidth when fields are partially filled.
pkgid (optional package-level option)
Enables extended message addressing with 16-bit message IDs (256 packages × 256 messages = 65,536 total).
Data Types¶
| Type | Size | Description |
|---|---|---|
| int8 | 1 byte | Signed -128 to 127 |
| uint8 | 1 byte | Unsigned 0 to 255 |
| int16 | 2 bytes | Signed -32768 to 32767 |
| uint16 | 2 bytes | Unsigned 0 to 65535 |
| int32 | 4 bytes | Signed integer |
| uint32 | 4 bytes | Unsigned integer |
| int64 | 8 bytes | Signed large integer |
| uint64 | 8 bytes | Unsigned large integer |
| float | 4 bytes | IEEE 754 single precision |
| double | 8 bytes | IEEE 754 double precision |
| bool | 1 byte | true or false |
All types use little-endian byte order.
Strings¶
Strings require a size specification.
Fixed-size string
Always uses 16 bytes, padded with nulls if shorter.
Variable-size string
Stores up to 256 characters plus a 1-byte length prefix.
Arrays¶
All repeated fields must specify a size. Arrays can contain primitive types, enums, strings, or nested messages.
Fixed arrays
Bounded arrays (variable count)
Includes a 1-byte count prefix.
String arrays
Array of up to 10 strings, each up to 32 characters.
Arrays of nested messages
message Waypoint {
double lat = 1;
double lon = 2;
}
message Route {
option msgid = 5;
string name = 1 [size=32];
repeated Waypoint waypoints = 2 [max_size=20];
}
Array of up to 20 waypoint messages. Each Waypoint is embedded inline.
Enums¶
enum SensorType {
TEMPERATURE = 0;
HUMIDITY = 1;
PRESSURE = 2;
}
message SensorReading {
option msgid = 1;
SensorType type = 1;
float value = 2;
}
Enums are stored as uint8 (1 byte).
Nested Messages¶
message Position {
double lat = 1;
double lon = 2;
}
message Vehicle {
option msgid = 1;
uint32 id = 1;
Position pos = 2;
}
Nested messages are embedded inline.
Import Statements¶
Import proto definitions from other files:
// vehicle.proto
import "types.proto";
package fleet;
message Vehicle {
option msgid = 1;
uint32 id = 1;
common.Position pos = 2;
}
Flatten Option¶
Flatten nested message fields into the parent (Python/GraphQL only):
Access: status.lat instead of status.pos.lat
Validation Rules¶
The generator enforces:
- Message IDs unique within package (0-255)
- Package IDs unique across packages (0-255)
- Field numbers unique within message
- All arrays must have size or max_size
- All strings must have size or max_size
- String arrays need both max_size and element_size
- Array max_size limited to 255 (count fits in 1 byte)
Complete Example¶
package robot_control;
enum RobotState {
IDLE = 0;
MOVING = 1;
ERROR = 2;
}
message Position {
double lat = 1;
double lon = 2;
float altitude = 3;
}
message RobotStatus {
option msgid = 1;
uint32 robot_id = 1;
string name = 2 [size=16];
RobotState state = 3;
Position current_pos = 4;
float battery_percent = 5;
repeated float joint_angles = 6 [size=6];
string error_msg = 7 [max_size=128];
}