Rust序列化库matrix-pickle的使用,高效二进制数据序列化与反序列化解决方案

Rust序列化库matrix-pickle的使用,高效二进制数据序列化与反序列化解决方案

matrix-pickle是一个简单的二进制编码格式,主要用于Matrix生态系统中。它是libolm和vodozemac加密库中使用的编码格式。

如何使用

最简单的使用方式是使用derive宏:

use anyhow::Result;
use matrix_pickle::{Encode, Decode};

fn main() -> Result<()> {
    #[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
    struct MyStruct {
        public_key: [u8; 32],
        data: Vec<u8>,
    }
    
    let data = MyStruct {
        public_key: [5u8; 32],
        data: vec![1, 2, 3],
    };
    
    let encoded = data.encode_to_vec()?;
    let decoded = MyStruct::decode_from_slice(&encoded)?;
    
    assert_eq!(data, decoded);

    Ok(())
}

格式定义

matrix-pickle在大多数情况下直接编码结构体中的字节而不添加任何元数据。下表定义了常见类型的编码方式:

类型 示例值 编码值 说明
u8 255 [FF] 直接编码
bool true [01] 编码前转换为u8
[u8; N] [1u8, 2u8] [01, 02] 直接编码
u32 16 [00, 00, 00, 10] 以大端形式编码为字节数组
usize 32 [00, 00, 00, 20] 编码前转换为u32
&[T] &[3u8, 4u8] [00, 00, 00, 02, 03, 04] 先编码长度,然后编码每个元素

派生支持

只要内部类型实现了EncodeDecode,该库就支持为结构体和枚举派生EncodeDecode实现。

结构体

结构体的派生支持按定义顺序编码每个字段:

use std::io::Write;
use matrix_pickle::{Encode, EncodeError};

struct Foo {
    first: [u8; 32],
    second: Vec<u8>,
}

impl Encode for Foo {
    fn encode(&self, writer: &mut impl Write) - 
> Result<usize, EncodeError> {
        let mut ret = 0;

        // 编码第一个结构体字段
        ret += self.first.encode(writer)?;
        // 现在编码第二个结构体字段
        ret += self.second.encode(writer)?;

        Ok(ret)
    }
}

枚举

枚举首先将变体编号编码为u8,然后编码枚举值。仅支持包含单个关联数据值的枚举。

use std::io::Write;
use matrix_pickle::{Encode, EncodeError};

enum Bar {
    First(u32),
    Second(u32),
}

impl Encode for Bar {
    fn encode(&self, writer: &mut impl Write) - 
> Result<usize, EncodeError> {
        let mut ret = 0;

        match self {
            Bar::First(value) => {
                // 这是第一个变体,先编码0u8
                ret += 0u8.encode(writer)?;
                // 现在编码关联值
                ret += value.encode(writer)?;
            },
            Bar::Second(value) => {
                // 这是第二个变体,先编码1u8
                ret += 1u8.encode(writer)?;
                // 现在编码关联值
                ret += value.encode(writer)?;
            },
        }

        Ok(ret)
    }
}

编码和解码机密数据

对于解码机密数据,请确保将数组装箱。我们有一个辅助属性来提醒你应该将机密数据装箱。

只需使用#[secret]属性注释任何结构体字段。如果机密数据没有装箱,编译器会报错。例如:

use matrix_pickle::{Encode, Decode};

#[derive(Encode, Decode)]
struct Key {
    #[secret]
    private: [u8; 32],  // 不会编译
    public: [u8; 32],
}

正确的写法是:

use matrix_pickle::{Encode, Decode};

#[derive(Encode, Decode)]
struct Key {
    #[secret]
    private: Box<[u8; 32]>,  // 会编译
    public: [u8; 32],
}

完整示例

use anyhow::Result;
use matrix_pickle::{Encode, Decode};

fn main() -> Result<()> {
    // 定义包含机密数据和非机密数据的结构体
    #[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
    struct SecureMessage {
        #[secret]
        secret_key: Box<[u8; 32]>,
        public_key: [u8; 32],
        payload: Vec<u8>,
        message_type: MessageType,
    }

    // 定义枚举类型
    #[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)]
    enum MessageType {
        Text(usize),
        Binary(usize),
        Encrypted(usize),
    }

    // 创建实例
    let message = SecureMessage {
        secret_key: Box::new([0xAA; 32]),
        public_key: [0xBB; 32],
        payload: vec![1, 2, 3, 4, 5],
        message_type: MessageType::Encrypted(256),
    };

    // 序列化
    let encoded = message.encode_to_vec()?;
    println!("Encoded data: {:?}", encoded);

    // 反序列化
    let decoded = SecureMessage::decode_from_slice(&encoded)?;
    println!("Decoded data: {:?}", decoded);

    // 验证
    assert_eq!(message, decoded);

    Ok(())
}

与bincode的比较

二进制格式与bincode crate提供的以下配置类似:

let config = bincode::config::standard()
    .with_big_endian()
    .with_fixed_int_encoding()
    .skip_fixed_array_length();

两个主要区别是:

  • bincode使用u64编码切片长度
  • matrix-pickle使用u32编码切片长度

其他区别:

  • 不支持配置编码格式,如果需要调整格式,请使用bincode
  • 没有使用unsafe代码,优化了简单性而非纯粹性能

1 回复

Rust序列化库matrix-pickle使用指南

简介

matrix-pickle是一个高效的Rust二进制序列化库,专注于高性能的数据序列化与反序列化操作。它特别适合需要处理大量二进制数据的场景,如网络通信、游戏开发或高性能计算应用。

主要特性

  • 零拷贝反序列化
  • 紧凑的二进制格式
  • 高性能序列化/反序列化
  • 支持基本类型和自定义结构体
  • 内存安全的Rust实现

安装

在Cargo.toml中添加依赖:

[dependencies]
matrix-pickle = "0.1"

基本使用

序列化基本类型

use matrix_pickle::{to_bytes, from_bytes};

fn main() {
    // 序列化
    let data = 42u32;
    let serialized = to_bytes(&data).unwrap();
    
    // 反序列化
    let deserialized: u32 = from_bytes(&serialized).unwrap();
    
    assert_eq!(data, deserialized);
}

序列化自定义结构体

use matrix_pickle::{Encode, Decode};

#[derive(Encode, Decode, PartialEq, Debug)]
struct Player {
    id: u32,
    name: String,
    position: (f32, f32),
    health: u8,
}

fn main() {
    let player = Player {
        id: 1,
        name: "Alice".to_string(),
        position: (10.5, 20.3),
        health: 100,
    };
    
    let serialized = matrix_pickle::to_bytes(&player).unwrap();
    let deserialized: Player = matrix_pickle::from_bytes(&serialized).unwrap();
    
    assert_eq!(player, deserialized);
}

高级用法

处理字节缓冲区

use matrix_pickle::{Encoder, Decoder};

fn main() {
    let mut buffer = vec![0u8; 1024]; // 预分配缓冲区
    
    // 编码
    let mut encoder = Encoder::new(&mut buffer);
    encoder.encode(&42u32).unwrap();
    encoder.encode(&"hello").unwrap();
    let bytes_written = encoder.finish().unwrap();
    
    // 解码
    let mut decoder = Decoder::new(&buffer[..bytes_written]);
    let num: u32 = decoder.decode().unwrap();
    let text: String = decoder.decode().unwrap();
    
    assert_eq!(num, 42);
    assert_eq!(text, "hello");
}

处理数组和集合

use matrix_pickle::{to_bytes, from_bytes};

fn main() {
    let data = vec![1u32, 2, 3, 4, 5];
    
    let serialized = to_bytes(&data).unwrap();
    let deserialized: Vec<u32> = from_bytes(&serialized).unwrap();
    
    assert_eq!(data, deserialized);
}

性能提示

  1. 对于频繁序列化的场景,重用缓冲区而不是每次都创建新的
  2. 对于大型结构,考虑使用#[repr(C)]来优化内存布局
  3. 使用固定大小的数组而不是Vec当大小已知时

错误处理

use matrix_pickle::{from_bytes, Error};

fn try_deserialize(data: &[u8]) -> Result<u32, Error> {
    let value: u32 = from_bytes(data)?;
    Ok(value)
}

完整示例:游戏状态序列化

下面是一个完整的游戏状态序列化示例,展示了如何使用matrix-pickle处理复杂数据结构:

use matrix_pickle::{Encode, Decode, to_bytes, from_bytes};

// 定义游戏状态结构体
#[derive(Encode, Decode, PartialEq, Debug)]
struct GameState {
    version: u32,
    players: Vec<Player>,
    map: Map,
    timestamp: u64,
}

#[derive(Encode, Decode, PartialEq, Debug)]
struct Player {
    id: u32,
    name: String,
    position: (f32, f32),
    inventory: Vec<Item>,
    stats: Stats,
}

#[derive(Encode, Decode, PartialEq, Debug)]
struct Item {
    id: u16,
    quantity: u8,
    durability: f32,
}

#[derive(Encode, Decode, PartialEq, Debug)]
struct Stats {
    health: u8,
    stamina: u8,
    experience: u32,
}

#[derive(Encode, Decode, PartialEq, Debug)]
struct Map {
    tiles: Vec<u8>,
    width: u32,
    height: u32,
}

fn main() {
    // 创建游戏状态
    let game_state = GameState {
        version: 1,
        players: vec![
            Player {
                id: 1,
                name: "Alice".to_string(),
                position: (10.5, 20.3),
                inventory: vec![
                    Item { id: 101, quantity: 1, durability: 100.0 },
                    Item { id: 205, quantity: 5, durability: 75.5 },
                ],
                stats: Stats {
                    health: 100,
                    stamina: 80,
                    experience: 1500,
                },
            },
            Player {
                id: 2,
                name: "Bob".to_string(),
                position: (15.2, 8.7),
                inventory: vec![
                    Item { id: 102, quantity: 1, durability: 90.0 },
                ],
                stats: Stats {
                    health: 85,
                    stamina: 90,
                    experience: 2300,
                },
            },
        ],
        map: Map {
            tiles: vec![0, 1, 1, 0, 2, 0, 1, 3, 0],
            width: 3,
            height: 3,
        },
        timestamp: 1234567890,
    };

    // 序列化游戏状态
    let serialized = to_bytes(&game_state).unwrap();
    println!("Serialized size: {} bytes", serialized.len());

    // 反序列化游戏状态
    let deserialized: GameState = from_bytes(&serialized).unwrap();
    
    // 验证数据完整性
    assert_eq!(game_state, deserialized);
    println!("Deserialization successful!");
}

这个完整示例展示了:

  1. 如何定义复杂嵌套结构体
  2. 使用derive宏自动实现Encode和Decode trait
  3. 处理包含Vec、元组和基本类型的复杂数据结构
  4. 验证序列化和反序列化的数据一致性

通过这个示例,您可以了解如何在实际项目中使用matrix-pickle来处理复杂的游戏状态或应用数据的序列化需求。

回到顶部