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);
}

功能特点

  1. COBS编码/解码:提供高效的COBS编码和解码功能
  2. 与postcard无缝集成:可以与postcard序列化库完美配合使用
  3. 无堆分配:适合嵌入式系统等资源受限环境
  4. 小体积:库体积仅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();
            }
        }
    }
}

性能提示

  1. 对于已知最大大小的数据,预分配足够大的缓冲区
  2. 在嵌入式系统中,考虑使用heapless crate的固定大小容器
  3. 批量处理数据时重用缓冲区

注意事项

  • COBS编码会增加约1字节/254字节的开销
  • 确保接收方缓冲区足够大以容纳解码后的数据
  • 错误处理很重要,特别是在不可靠的传输介质上

postcard-cobs结合了postcard的高效序列化和COBS的可靠传输特性,非常适合资源受限环境下的数据交换需求。

回到顶部