Language Examples
This page shows how to use generated code in each language with the standardized serialize/deserialize API.
Proto Definition
Examples use this proto file:
package example;
message Status { option msgid = 1; uint32 id = 1; float value = 2;}Generate code:
python -m struct_frame status.proto --build_c --build_cpp --build_ts --build_py --build_js --build_csharpUsing Frame Profiles
Frame profiles provide complete framing and parsing functionality. This is the recommended approach for most applications.
Python with Profiles
from generated.example import ExampleStatusfrom generated.frame_profiles import ( ProfileStandardWriter, ProfileStandardAccumulatingReader)
# Create and serialize a messagemsg = ExampleStatus(id=42, value=3.14)
# Encode with frame profilewriter = ProfileStandardWriter(1024)bytes_written = writer.write(msg)frame_data = writer.data()
# Parse received framesreader = ProfileStandardAccumulatingReader()reader.add_data(frame_data)
# Deserialize using FrameMsgInforesult = reader.next()if result: decoded_msg = ExampleStatus.deserialize(result) # Pass FrameMsgInfo directly print(f"ID: {decoded_msg.id}, Value: {decoded_msg.value}")TypeScript with Profiles
import { ExampleStatus } from './generated/example.structframe';import { ProfileStandardWriter, ProfileStandardAccumulatingReader} from './generated/frame-profiles';
// Create and serialize a messageconst msg = new ExampleStatus();msg.id = 42;msg.value = 3.14;
// Encode with frame profileconst writer = new ProfileStandardWriter(1024);writer.write(msg);const frameData = writer.data();
// Parse received framesconst reader = new ProfileStandardAccumulatingReader();reader.addData(frameData);
// Deserialize using FrameMsgInfoconst result = reader.next();if (result) { const decodedMsg = ExampleStatus.deserialize(result); // Pass FrameMsgInfo directly console.log(`ID: ${decodedMsg.id}, Value: ${decodedMsg.value}`);}C++ with Profiles
#include "example.structframe.hpp"#include "FrameProfiles.hpp"
// Create and serialize a messageExampleStatus msg;msg.id = 42;msg.value = 3.14f;
// Encode with frame profileuint8_t buffer[1024];FrameParsers::ProfileStandardWriter writer(buffer, sizeof(buffer));writer.write(msg);
// Parse received framesFrameParsers::ProfileStandardAccumulatingReader reader;reader.add_data(buffer, writer.size());
// Deserialize using FrameMsgInfoif (auto result = reader.next()) { ExampleStatus decoded_msg; decoded_msg.deserialize(result); // Pass FrameMsgInfo directly std::cout << "ID: " << decoded_msg.id << ", Value: " << decoded_msg.value << std::endl;}C# with Profiles
using StructFrame;
// Create and serialize a messagevar msg = new ExampleStatus { Id = 42, Value = 3.14f};
// Encode with frame profilevar writer = new ProfileStandardWriter(1024);writer.Write(msg);var frameData = writer.Data();
// Parse received framesvar reader = new ProfileStandardAccumulatingReader();reader.AddData(frameData);
// Deserialize using FrameMsgInfovar result = reader.Next();if (result != null) { var decodedMsg = ExampleStatus.Deserialize(result); // Pass FrameMsgInfo directly Console.WriteLine($"ID: {decodedMsg.Id}, Value: {decodedMsg.Value}");}JavaScript with Profiles
const { ExampleStatus } = require('./generated/example.structframe');const { ProfileStandardWriter, ProfileStandardAccumulatingReader} = require('./generated/frame-profiles');
// Create and serialize a messageconst msg = new ExampleStatus();msg.id = 42;msg.value = 3.14;
// Encode with frame profileconst writer = new ProfileStandardWriter(1024);writer.write(msg);const frameData = writer.data();
// Parse received framesconst reader = new ProfileStandardAccumulatingReader();reader.addData(frameData);
// Deserialize using FrameMsgInfoconst result = reader.next();if (result) { const decodedMsg = ExampleStatus.deserialize(result); // Pass FrameMsgInfo directly console.log(`ID: ${decodedMsg.id}, Value: ${decodedMsg.value}`);}Direct Message Serialization
For cases where you need direct access to message bytes without framing:
Python
from generated.example import ExampleStatus
# Create a messagemsg = ExampleStatus(id=42, value=3.14)
# Serialize to bytesdata = msg.serialize()
# Send data over serial, network, etc.# ...
# Deserialize from bytesreceived = ExampleStatus.deserialize(data)print(f"ID: {received.id}, Value: {received.value}")TypeScript
import { ExampleStatus } from './generated/example.structframe';
// Create a messageconst msg = new ExampleStatus();msg.id = 42;msg.value = 3.14;
// Serialize to bufferconst data = msg.serialize();
// Send data over network, etc.// ...
// Deserialize from bufferconst received = ExampleStatus.deserialize(data);console.log(`ID: ${received.id}, Value: ${received.value}`);JavaScript
const { ExampleStatus } = require('./generated/example.structframe');
// Create a messageconst msg = new ExampleStatus();msg.id = 42;msg.value = 3.14;
// Serialize to bufferconst data = msg.serialize();
// Send data over network, etc.// ...
// Deserialize from bufferconst received = ExampleStatus.deserialize(data);console.log(`ID: ${received.id}, Value: ${received.value}`);C++
#include "example.structframe.hpp"#include <iostream>
int main() { // Create a message ExampleStatus msg; msg.id = 42; msg.value = 3.14f;
// Serialize to buffer uint8_t buffer[1024]; msg.serialize(buffer); size_t size = sizeof(ExampleStatus);
// Send data over serial, network, etc. // ...
// Deserialize from buffer ExampleStatus received; received.deserialize(buffer, size); std::cout << "ID: " << received.id << ", Value: " << received.value << std::endl;
return 0;}C#
using StructFrame;
class Program { static void Main() { // Create a message var msg = new ExampleStatus { Id = 42, Value = 3.14f };
// Serialize to bytes byte[] data = msg.Serialize();
// Send data over network, etc. // ...
// Deserialize from bytes var received = ExampleStatus.Deserialize(data); Console.WriteLine($"ID: {received.Id}, Value: {received.Value}"); }}Communication Examples
Serial Communication (Python)
import serialfrom generated.example import ExampleStatusfrom generated.frame_profiles import ProfileStandardAccumulatingReader
# Setup serial connectionser = serial.Serial('/dev/ttyUSB0', 115200)reader = ProfileStandardAccumulatingReader()
while True: if ser.in_waiting: # Read available data data = ser.read(ser.in_waiting) reader.add_data(data)
# Process all complete frames while True: result = reader.next() if result is None or not result.valid: break
# Deserialize using FrameMsgInfo msg = ExampleStatus.deserialize(result) print(f"Received: ID={msg.id}, Value={msg.value}")Streaming Parser (C++)
#include "example.structframe.hpp"#include "FrameProfiles.hpp"
// Byte-by-byte streaming parser for UART/serialFrameParsers::ProfileStandardAccumulatingReader reader;
void on_byte_received(uint8_t byte) { if (auto result = reader.push_byte(byte)) { // Complete message received - result is valid due to operator bool() ExampleStatus msg; msg.deserialize(result); std::cout << "ID: " << msg.id << std::endl; }}TCP Socket (TypeScript)
import * as net from 'net';import { ExampleStatus } from './generated/example.structframe';import { ProfileStandardAccumulatingReader } from './generated/frame-profiles';
const client = net.createConnection({ port: 8080 });const reader = new ProfileStandardAccumulatingReader();
client.on('data', (data: Buffer) => { reader.addData(data);
let result; while ((result = reader.next()) && result.valid) { const msg = ExampleStatus.deserialize(result); console.log(`ID: ${msg.id}, Value: ${msg.value}`); }});WebSocket (JavaScript)
const { ExampleStatus } = require('./generated/example.structframe');const { ProfileStandardAccumulatingReader } = require('./generated/frame-profiles');const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8080');const reader = new ProfileStandardAccumulatingReader();
ws.on('message', (data) => { reader.addData(Buffer.from(data));
let result; while ((result = reader.next()) && result.valid) { const msg = ExampleStatus.deserialize(result); console.log(`ID: ${msg.id}, Value: ${msg.value}`); }});Frame Profiles
Different profiles for different use cases:
- ProfileStandard: General purpose (Basic header + Default payload)
- ProfileSensor: Low-bandwidth sensors (Tiny header + Minimal payload)
- ProfileIPC: Trusted inter-process (No header + Minimal payload)
- ProfileBulk: Large data transfers (Basic header + Extended payload)
- ProfileNetwork: Multi-system networks (Basic header + Extended Multi-System Stream payload)
All profiles support the same API - just change the class name!
Arrays
Example with arrays:
message SensorData { option msgid = 2; repeated float readings = 1 [max_size=10];}Creating messages with arrays works the same way across languages:
ExampleSensorData data;data.readings_count = 3;data.readings[0] = 1.1f;data.readings[1] = 2.2f;data.readings[2] = 3.3f;
// Serialize/deserialize works the same as simple messages// Just use msg.serialize() / deserialize(data)ExampleSensorData data;data.readings_count = 3;data.readings[0] = 1.1f;data.readings[1] = 2.2f;data.readings[2] = 3.3f;
// Serialize/deserialize works the same as simple messages// Just use msg.serialize() / deserialize(data)data = ExampleSensorData()data.readings_count = 3data.readings[0] = 1.1data.readings[1] = 2.2data.readings[2] = 3.3
# Serialize/deserialize works the same as simple messages# Just use msg.serialize() / deserialize(data)const data = new ExampleSensorData();data.readings_count = 3;data.readings[0] = 1.1;data.readings[1] = 2.2;data.readings[2] = 3.3;
// Serialize/deserialize works the same as simple messages// Just use msg.serialize() / deserialize(data)var data = new ExampleSensorData { ReadingsCount = 3};data.Readings[0] = 1.1f;data.Readings[1] = 2.2f;data.Readings[2] = 3.3f;
// Serialize/deserialize works the same as simple messages// Just use msg.Serialize() / Deserialize(data)Nested Messages
Example with nested messages:
message Position { double lat = 1; double lon = 2;}
message Vehicle { option msgid = 3; uint32 id = 1; Position pos = 2;}Nested messages are accessed naturally in all languages:
ExampleVehicle v;v.id = 1;v.pos.lat = 37.7749;v.pos.lon = -122.4194;
// Serialize/deserialize works the same - nested messages are handled automaticallyExampleVehicle v;v.id = 1;v.pos.lat = 37.7749;v.pos.lon = -122.4194;
// Serialize/deserialize works the same - nested messages are handled automaticallyv = ExampleVehicle(id=1)v.pos.lat = 37.7749v.pos.lon = -122.4194
# Serialize/deserialize works the same - nested messages are handled automaticallyconst v = new ExampleVehicle();v.id = 1;v.pos.lat = 37.7749;v.pos.lon = -122.4194;
// Serialize/deserialize works the same - nested messages are handled automaticallyvar v = new ExampleVehicle { Id = 1, Pos = new ExamplePosition { Lat = 37.7749, Lon = -122.4194 }};
// Serialize/deserialize works the same - nested messages are handled automaticallyKey Takeaways
- Consistent API: All languages use
serialize()/deserialize()(case varies by language convention) - Frame Profiles: Use ProfileStandardWriter/Reader for complete framing and parsing
- FrameMsgInfo: Pass frame parser results directly to
deserialize()- no manual extraction needed - Variable Messages: Transparent handling - same API for fixed and variable-length messages
- Arrays & Nested Messages: Automatically handled by serialize/deserialize