Rust序列化库postcard-cobs的使用:高效CBOR编码与postcard格式的无缝转换
Rust序列化库postcard-cobs的使用:高效CBOR编码与postcard格式的无缝转换
postcard-cobs是一个Rust序列化库,提供了高效的CBOR编码与postcard格式的无缝转换功能。它基于COBS(Consistent Overhead Byte Stuffing)编码方案,特别适合嵌入式系统和通信协议中使用。
安装
在项目中添加依赖:
postcard-cobs = "0.2.0"
或者运行Cargo命令:
cargo add postcard-cobs
使用示例
下面是一个完整的示例,展示如何使用postcard-cobs进行序列化和反序列化:
use postcard::{from_bytes, to_vec};
use postcard_cobs::{decode, encode};
fn main() {
// 1. 准备要序列化的数据
let data = vec![1, 2, 3, 4, 5];
// 2. 使用postcard进行序列化
let serialized = to_vec(&data).unwrap();
// 3. 使用COBS编码
let mut buf = [0u8; 32];
let encoded = encode(&serialized, &mut buf).unwrap();
println!("Encoded: {:?}", encoded);
// 4. 解码过程
let mut decode_buf = [0u8; 32];
let decoded = decode(encoded, &mut decode_buf).unwrap();
// 5. 使用postcard反序列化
let deserialized: Vec<u8> = from_bytes(decoded).unwrap();
println!("Original: {:?}", data);
println!("Deserialized: {:?}", deserialized);
assert_eq!(data, deserialized);
}
完整示例demo
下面是一个更完整的示例,展示如何处理自定义数据结构:
use serde::{Serialize, Deserialize};
use postcard::{from_bytes, to_vec};
use postcard_cobs::{decode, encode};
// 自定义数据结构
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SensorData {
id: u32,
temperature: f32,
humidity: f32,
timestamp: u64,
}
fn main() {
// 1. 准备要序列化的数据
let data = SensorData {
id: 1234,
temperature: 25.5,
humidity: 60.0,
timestamp: 1625097600,
};
// 2. 使用postcard进行序列化
let serialized = to_vec(&data).unwrap();
// 3. 使用COBS编码
let mut buf = [0u8; 128]; // 更大的缓冲区
let encoded = encode(&serialized, &mut buf).unwrap();
println!("Encoded length: {}", encoded.len());
// 4. 解码过程
let mut decode_buf = [0u8; 128];
let decoded = decode(encoded, &mut decode_buf).unwrap();
// 5. 使用postcard反序列化
let deserialized: SensorData = from_bytes(decoded).unwrap();
println!("Original: {:?}", data);
println!("Deserialized: {:?}", deserialized);
assert_eq!(data, deserialized);
}
功能特点
- COBS编码/解码:提供高效的COBS编码和解码功能
- 与postcard无缝集成:可以与postcard序列化库完美配合使用
- 无堆分配:适合嵌入式系统等资源受限环境
- 小体积:库体积仅11.8 KiB
许可证
postcard-cobs采用MIT或Apache-2.0双许可证。
1 回复
Rust序列化库postcard-cobs的使用:高效CBOR编码与postcard格式的无缝转换
介绍
postcard-cobs是一个Rust序列化库,它结合了postcard的紧凑二进制格式和COBS(Consistent Overhead Byte Stuffing)编码的优点。这个库特别适合嵌入式系统和网络通信场景,其中需要高效、可靠的数据序列化和反序列化。
主要特点:
- 基于postcard格式的高效二进制序列化
- 使用COBS编码实现帧同步和可靠传输
- 零拷贝反序列化支持
- 无堆分配(no_std兼容)
- 体积小巧,适合嵌入式环境
安装
在Cargo.toml中添加依赖:
[dependencies]
postcard-cobs = "0.2"
基本使用方法
序列化数据
use postcard_cobs::CobsAccumulator;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct SensorData {
id: u32,
temperature: f32,
humidity: f32,
active: bool,
}
fn main() {
let data = SensorData {
id: 42,
temperature: 23.5,
humidity: 65.2,
active: true,
};
// 序列化为postcard格式
let mut buf = [0u8; 32];
let serialized = postcard::to_slice(&data, &mut buf).unwrap();
// 使用COBS编码
let mut cobs_buf = [0u8; 64];
let used = postcard_cobs::encode(serialized, &mut cobs_buf).unwrap();
println!("Encoded data: {:?}", &cobs_buf[..used]);
}
反序列化数据
use postcard_cobs::{CobsAccumulator, FeedResult};
fn main() {
// 假设这是接收到的COBS编码数据
let received_data = &[0x03, 0x2A, 0x00, 0x00, 0x00, 0x41, 0xBC, 0x00, 0x00, 0x42, 0x82, 0x66, 0x66, 0x01, 0x00];
let mut acc = CobsAccumulator::new();
let mut deserialized = None;
for byte in received_data {
match acc.feed(&[*byte]) {
FeedResult::Consumed => continue,
FeedResult::DeserError(e) => eprintln!("Deserialization error: {:?}", e),
FeedResult::Success { data, .. } => {
deserialized = Some(postcard::from_bytes::<SensorData>(data).unwrap());
break;
}
}
}
if let Some(data) = deserialized {
println!("Deserialized data: {:?}", data);
}
}
流式处理示例
对于流式数据(如串口通信),可以这样处理:
use postcard_cobs::{CobsAccumulator, FeedResult};
fn process_stream_data(stream: &mut impl Iterator<Item=u8>) {
let mut acc = CobsAccumulator::new();
for byte in stream {
match acc.feed(&[byte]) {
FeedResult::Consumed => continue,
FeedResult::DeserError(e) => {
eprintln!("Error: {:?}", e);
acc.reset();
},
FeedResult::Success { data, .. } => {
if let Ok(decoded) = postcard::from_bytes::<SensorData>(data) {
println!("Received: {:?}", decoded);
}
acc.reset();
}
}
}
}
高级用法
自定义缓冲区大小
// 使用更大的缓冲区处理大数据
let mut acc = CobsAccumulator::new_with_buffer([0u8; 1024]);
零拷贝反序列化
#[derive(Serialize, Deserialize)]
struct Packet<'a> {
header: u8,
payload: &'a [u8],
checksum: u16,
}
let raw_data = &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let packet = Packet {
header: 0xAA,
payload: raw_data,
checksum: 0x1234,
};
let mut buf = [0u8; 64];
let serialized = postcard::to_slice(&packet, &mut buf).unwrap();
let mut cobs_buf = [0u8; 128];
let used = postcard_cobs::encode(serialized, &mut cobs_buf).unwrap();
// 反序列化时,payload仍然引用原始数据
let mut acc = CobsAccumulator::new();
if let FeedResult::Success { data, .. } = acc.feed(&cobs_buf[..used]) {
let decoded: Packet = postcard::from_bytes(data).unwrap();
println!("Payload: {:?}", decoded.payload);
}
完整示例
下面是一个完整的示例,展示了如何使用postcard-cobs进行序列化和反序列化:
use postcard_cobs::{encode, CobsAccumulator, FeedResult};
use serde::{Serialize, Deserialize};
// 定义数据结构
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct DeviceStatus {
device_id: u32,
firmware_version: [u8; 3],
sensors: [f32; 4],
uptime: u64,
is_operational: bool,
}
fn main() {
// 1. 序列化示例
let status = DeviceStatus {
device_id: 0xDEADBEEF,
firmware_version: [1, 0, 2],
sensors: [25.5, 60.2, 1023.7, 0.0],
uptime: 86400,
is_operational: true,
};
// 准备缓冲区
let mut ser_buf = [0u8; 128];
let mut cobs_buf = [0u8; 256];
// 序列化为postcard格式
let serialized = postcard::to_slice(&status, &mut ser_buf).unwrap();
// COBS编码
let used = encode(serialized, &mut cobs_buf).unwrap();
println!("Encoded COBS data ({} bytes): {:02X?}", used, &cobs_buf[..used]);
// 2. 反序列化示例
let mut acc = CobsAccumulator::new();
let mut decoded_status = None;
// 模拟逐字节接收数据
for &byte in &cobs_buf[..used] {
match acc.feed(&[byte]) {
FeedResult::Consumed => continue,
FeedResult::DeserError(e) => {
eprintln!("Error during deserialization: {:?}", e);
break;
},
FeedResult::Success { data, .. } => {
decoded_status = Some(postcard::from_bytes::<DeviceStatus>(data).unwrap());
break;
}
}
}
if let Some(status) = decoded_status {
println!("Decoded status: {:?}", status);
assert_eq!(status, status); // 验证数据一致性
}
// 3. 流式处理模拟
println!("\nSimulating stream processing:");
let mut stream = cobs_buf[..used].iter().copied();
let mut stream_acc = CobsAccumulator::new();
while let Some(byte) = stream.next() {
match stream_acc.feed(&[byte]) {
FeedResult::Consumed => {
println!("Consumed byte: 0x{:02X}", byte);
},
FeedResult::DeserError(e) => {
println!("Stream error: {:?}", e);
stream_acc.reset();
},
FeedResult::Success { data, .. } => {
if let Ok(decoded) = postcard::from_bytes::<DeviceStatus>(data) {
println!("Successfully decoded from stream: {:?}", decoded);
}
stream_acc.reset();
}
}
}
}
性能提示
- 对于已知最大大小的数据,预分配足够大的缓冲区
- 在嵌入式系统中,考虑使用
heapless
crate的固定大小容器 - 批量处理数据时重用缓冲区
注意事项
- COBS编码会增加约1字节/254字节的开销
- 确保接收方缓冲区足够大以容纳解码后的数据
- 错误处理很重要,特别是在不可靠的传输介质上
postcard-cobs结合了postcard的高效序列化和COBS的可靠传输特性,非常适合资源受限环境下的数据交换需求。