Advanced Features
This page covers advanced scenarios for special use cases.
Package IDs for Extended Addressing
Package IDs enable 16-bit message addressing for large systems.
When to use:
- Systems with more than 255 messages
- Multi-package systems requiring namespace separation
Frame compatibility: Use Extended or ExtendedMultiSystemStream payload types with package IDs.
Message ID encoding:
- Without pkgid: 8-bit (0-255)
- With pkgid: 16-bit =
(package_id << 8) | msg_id
See Message Definitions for usage details.
Minimal Frames (Bandwidth-Limited Scenarios)
Minimal frames remove length and checksum fields for lowest overhead.
Requirements:
- All messages must be fixed-size (no max_size, only size)
- Parser needs message length lookup function
The generator creates a get_msg_info function automatically:
from frame_profiles import ProfileSensorWriter, ProfileSensorAccumulatingReaderfrom struct_frame.generated.messages import get_message_info
# Encode using sensor profile (Tiny + Minimal)
writer = ProfileSensorWriter(1024)writer.write(msg)frame = writer.data()
# Parser requires get_message_info callback for minimal profiles
reader = ProfileSensorAccumulatingReader(get_message_info=get_message_info)reader.add_data(frame)result = reader.next()#include "frame_profiles.hpp"#include "messages.structframe.hpp"
// Use sensor profile with minimal frames (requires message info callback)ProfileSensorAccumulatingReader reader(get_message_info);See Framing for more on minimal frames.
Large Messages
For messages > 255 bytes, use Extended payload type:
python -m struct_frame large.proto --build_cUse BasicExtended or Network frame profile when encoding.
Variable-Length Encoding
Use option variable = true; for efficient encoding of messages with variable-length arrays or strings:
message LogEntry { option msgid = 10; option variable = true; uint64 timestamp = 1; string message = 2 [max_size=256]; repeated uint8 data = 3 [max_size=128];}Only used bytes are transmitted instead of full max_size. See Message Definitions for details.
Variable Oneofs
A oneof with a discriminator inside a variable message transmits only the active variant’s bytes by default (“trimmed” mode). Add option variable = true; to the oneof for a length-prefixed forward-compatible format.
Trimmed Mode (Default)
When the parent message is variable and the oneof has a discriminator (no option variable = true;), only the active variant’s bytes are sent. The receiver derives the size from the discriminator:
message CommandMessage { option msgid = 20; option variable = true;
oneof data { option discriminator = "field_order"; SmallPayload small = 1; // 3 bytes on the wire when active LargePayload large = 2; // 32 bytes on the wire when active }}Variable Mode (Length-Prefixed)
Add option variable = true; to include a uint16 length prefix, allowing receivers to skip unknown variants:
message CommandMessage { option msgid = 20; option variable = true;
oneof data { option discriminator = "field_order"; option variable = true; SmallPayload small = 1; // Only its own bytes transmitted LargePayload large = 2; // Only its own bytes transmitted }}Wire format: [discriminator][uint16 length][variant_bytes]
Controlling Oneof Size
option max_size = N; — valid on non-variable (trimmed) oneofs only. Reserves N bytes in the in-memory struct union for future variants without changing the wire size of current variants:
oneof data { option discriminator = "field_order"; option max_size = 64; // 64-byte in-memory buffer; not for variable oneofs SmallPayload small = 1; // Still 3 bytes on the wire}option min_size = N; — valid when the parent message is variable = true and the oneof is either variable = true or the only variable-length (trimmed) field in the message. Pads the wire payload to at least N bytes for backward compatibility:
oneof data { option discriminator = "field_order"; option variable = true; option min_size = 8; // Transmit at least 8 bytes SmallPayload small = 1; // 3 bytes → padded to 8 bytes on the wire LargePayload large = 2; // 8 bytes → transmitted as-is}
max_sizeapplies to non-variable (trimmed) oneofs — it reserves in-memory space without affecting wire size per variant.
min_sizeapplies to variable or trimmed oneofs in variable messages — it pads the wire payload and cannot exceed the oneof’s buffer size.
See Variable Oneofs in Message Definitions for the complete reference.