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:
Generate code:
python -m struct_frame status.proto --build_c --build_cpp --build_ts --build_py --build_js --build_csharp
Using 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 ExampleStatus
from generated.frame_profiles import (
ProfileStandardWriter,
ProfileStandardAccumulatingReader
)
# Create and serialize a message
msg = ExampleStatus(id=42, value=3.14)
# Encode with frame profile
writer = ProfileStandardWriter(1024)
bytes_written = writer.write(msg)
frame_data = writer.data()
# Parse received frames
reader = ProfileStandardAccumulatingReader()
reader.add_data(frame_data)
# Deserialize using FrameMsgInfo
result = 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 message
const msg = new ExampleStatus();
msg.id = 42;
msg.value = 3.14;
// Encode with frame profile
const writer = new ProfileStandardWriter(1024);
writer.write(msg);
const frameData = writer.data();
// Parse received frames
const reader = new ProfileStandardAccumulatingReader();
reader.addData(frameData);
// Deserialize using FrameMsgInfo
const 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 message
ExampleStatus msg;
msg.id = 42;
msg.value = 3.14f;
// Encode with frame profile
uint8_t buffer[1024];
FrameParsers::ProfileStandardWriter writer(buffer, sizeof(buffer));
writer.write(msg);
// Parse received frames
FrameParsers::ProfileStandardAccumulatingReader reader;
reader.add_data(buffer, writer.size());
// Deserialize using FrameMsgInfo
if (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 message
var msg = new ExampleStatus {
Id = 42,
Value = 3.14f
};
// Encode with frame profile
var writer = new ProfileStandardWriter(1024);
writer.Write(msg);
var frameData = writer.Data();
// Parse received frames
var reader = new ProfileStandardAccumulatingReader();
reader.AddData(frameData);
// Deserialize using FrameMsgInfo
var 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 message
const msg = new ExampleStatus();
msg.id = 42;
msg.value = 3.14;
// Encode with frame profile
const writer = new ProfileStandardWriter(1024);
writer.write(msg);
const frameData = writer.data();
// Parse received frames
const reader = new ProfileStandardAccumulatingReader();
reader.addData(frameData);
// Deserialize using FrameMsgInfo
const 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 message
msg = ExampleStatus(id=42, value=3.14)
# Serialize to bytes
data = msg.serialize()
# Send data over serial, network, etc.
# ...
# Deserialize from bytes
received = ExampleStatus.deserialize(data)
print(f"ID: {received.id}, Value: {received.value}")
TypeScript¶
import { ExampleStatus } from './generated/example.structframe';
// Create a message
const msg = new ExampleStatus();
msg.id = 42;
msg.value = 3.14;
// Serialize to buffer
const data = msg.serialize();
// Send data over network, etc.
// ...
// Deserialize from buffer
const received = ExampleStatus.deserialize(data);
console.log(`ID: ${received.id}, Value: ${received.value}`);
JavaScript¶
const { ExampleStatus } = require('./generated/example.structframe');
// Create a message
const msg = new ExampleStatus();
msg.id = 42;
msg.value = 3.14;
// Serialize to buffer
const data = msg.serialize();
// Send data over network, etc.
// ...
// Deserialize from buffer
const 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 serial
from generated.example import ExampleStatus
from generated.frame_profiles import ProfileStandardAccumulatingReader
# Setup serial connection
ser = 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/serial
FrameParsers::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:
Creating messages with arrays works the same way across languages:
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:
Key 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