Rust高效数据编解码库jam-codec的使用,支持高性能序列化与压缩传输

Rust高效数据编解码库jam-codec的使用,支持高性能序列化与压缩传输

Parity JAM Codec

JAM Codec是SCALE二进制编解码器的Rust实现,具有增强的紧凑编码功能。SCALE是一种轻量级格式,适用于资源受限的执行环境,如区块链运行时和低功耗、低内存设备。

需要注意的是,编码上下文(了解类型和数据结构)需要在编码和解码两端分别知晓。编码数据不包含这些上下文信息。

实现

编解码器使用以下特性实现:

Encode

Encode trait用于将数据编码为SCALE格式:

  • size_hint(&self) -> usize:获取编码数据所需的容量(字节)
  • encode_to<T: Output>(&self, dest: &mut T):将值编码并附加到目标缓冲区
  • encode(&self) -> Vec<u8>:编码类型数据并返回切片
  • using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R:编码类型数据并在编码值上执行闭包

Decode

Decode trait用于将编码数据反序列化/解码为相应类型:

  • fn decode<I: Input>(value: &mut I) -> Result<Self, Error>:尝试从SCALE格式解码值

CompactAs

CompactAs trait用于将自定义类型/结构体包装为紧凑类型:

  • encode_as(&self) -> &Self::As:将类型编码为紧凑类型
  • decode_from(_: Self::As) -> Result<Self, Error>:从紧凑可编码类型解码

HasCompact

HasCompact trait表示对应类型是紧凑可编码类型。

EncodeLike

EncodeLike trait需要手动为每种类型实现。使用derive时自动完成。

使用示例

简单类型

# // 如果不使用derive特性,需要导入宏
# #[cfg(not(feature="derive"))]
# use jam_codec_derive::{Encode, Decode};

use jam_codec::{Encode, Decode};

#[derive(Debug, PartialEq, Encode, Decode)]
enum EnumType {
    #[codec(index = 15)]
    A,
    B(u32, u64),
    C {
        a: u32,
        b: u64,
    },
}

let a = EnumType::A;
let b = EnumType::B(1, 2);
let c = EnumType::C { a: 1, b: 2 };

a.using_encoded(|ref slice| {
    assert_eq!(slice, &b"\x0f");
});

b.using_encoded(|ref slice| {
    assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0");
});

c.using_encoded(|ref slice| {
    assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0");
});

let mut da: &[u8] = b"\x0f";
assert_eq!(EnumType::decode(&mut da).ok(), Some(a));

let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0";
assert_eq!(EnumType::decode(&mut db).ok(), Some(b));

let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0";
assert_eq!(EnumType::decode(&mut dc).ok(), Some(c));

let mut dz: &[u8] = &[0];
assert_eq!(EnumType::decode(&mut dz).ok(), None);

# fn main() { }

带有HasCompact的紧凑类型

# // 如果不使用derive特性,需要导入宏
# #[cfg(not(feature="derive"))]
# use jam_codec_derive::{Encode, Decode};

use jam_codec::{Encode, Decode, Compact, HasCompact};

#[derive(Debug, PartialEq, Encode, Decode)]
struct Test1CompactHasCompact<T: HasCompact> {
    #[codec(compact)]
    bar: T,
}

#[derive(Debug, PartialEq, Encode, Decode)]
struct Test1HasCompact<T: HasCompact> {
    #[codec(encoded_as = "<T as HasCompact>::Type")]
    bar: T,
}

let test_val: (u64, usize) = (0u64, 1usize);

let encoded = Test1HasCompact { bar: test_val.0 }.encode();
assert_eq!(encoded.len(), test_val.1);
assert_eq!(<Test1CompactHasCompact<u64>>::decode(&mut &encoded[..]).unwrap().bar, test_val.0);

# fn main() { }

带有CompactAs的类型

# // 如果不使用derive特性,需要导入宏
# #[cfg(not(feature="derive"))]
# use jam_codec_derive::{Encode, Decode};

use serde_derive::{Serialize, Deserialize};
use jam_codec::{Encode, Decode, Compact, HasCompact, CompactAs, Error};

#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(PartialEq, Eq, Clone)]
struct StructHasCompact(u32);

impl CompactAs for StructHasCompact {
    type As = u32;

    fn encode_as(&self) -> &Self::As {
        &12
    }

    fn decode_from(_: Self::As) -> Result<Self, Error> {
        Ok(StructHasCompact(12))
    }
}

impl From<Compact<StructHasCompact>> for StructHasCompact {
    fn from(_: Compact<StructHasCompact>) -> Self {
        StructHasCompact(12)
    }
}

#[derive(Debug, PartialEq, Encode, Decode)]
enum TestGenericHasCompact<T> {
    A {
        #[codec(compact)] a: T
    },
}

let a = TestGenericHasCompact::A::<StructHasCompact> {
    a: StructHasCompact(12325678),
};

let encoded = a.encode();
assert_eq!(encoded.len(), 2);

# fn main() { }

完整示例

下面是一个完整的jam-codec使用示例,展示如何进行高效的数据序列化和反序列化:

use jam_codec::{Encode, Decode};

#[derive(Debug, PartialEq, Encode, Decode)]
struct Person {
    name: String,
    age: u32,
    #[codec(compact)]
    salary: u64,  // 使用紧凑编码
    skills: Vec<String>,
}

fn main() {
    // 创建示例数据
    let person = Person {
        name: "Alice".to_string(),
        age: 30,
        salary: 100_000,  // 大数字将使用紧凑编码
        skills: vec!["Rust".to_string(), "Blockchain".to_string()],
    };

    // 序列化
    let encoded = person.encode();
    println!("Encoded data ({} bytes): {:?}", encoded.len(), encoded);

    // 反序列化
    let mut input = &encoded[..];
    let decoded = Person::decode(&mut input).unwrap();
    println!("Decoded: {:?}", decoded);

    assert_eq!(person, decoded);
}

安装

在项目目录中运行以下Cargo命令:

cargo add jam-codec

或者在Cargo.toml中添加:

jam-codec = "0.1.0"

许可证

Apache-2.0


1 回复

Rust高效数据编解码库jam-codec使用指南

简介

jam-codec是一个高性能的Rust数据编解码库,专注于提供高效的序列化和压缩传输功能。它具有以下特点:

  • 高性能二进制序列化/反序列化
  • 内置压缩功能减少传输数据量
  • 支持多种数据类型
  • 零拷贝设计减少内存分配
  • 适用于网络传输和高性能计算场景

安装

在Cargo.toml中添加依赖:

[dependencies]
jam-codec = "0.3"

基本用法

简单序列化

use jam_codec::{encode, decode};

fn main() {
    let data = vec![1, 2, 3, 4, 5];
    
    // 序列化
    let encoded = encode(&data).unwrap();
    
    // 反序列化
    let decoded: Vec<i32> = decode(&encoded).unwrap();
    
    assert_eq!(data, decoded);
}

带压缩的序列化

use jam_codec::{encode_compressed, decode_compressed};

fn main() {
    let data = "这是一个需要压缩的长字符串".repeat(100);
    
    // 带压缩的序列化
    let compressed = encode_compressed(&data).unwrap();
    println!("压缩后大小: {} bytes", compressed.len());
    
    // 解压并反序列化
    let decompressed: String = decode_compressed(&compressed).unwrap();
    
    assert_eq!(data, decompressed);
}

高级用法

自定义类型序列化

use jam_codec::{Encode, Decode};

#[derive(Encode, Decode, Debug, PartialEq)]
struct Point {
    x: f32,
    y: f32,
    metadata: String,
}

fn main() {
    let point = Point {
        x: 1.5,
        y: -3.2,
        metadata: "origin".to_string(),
    };
    
    let encoded = encode(&point).unwrap();
    let decoded: Point = decode(&encoded).unwrap();
    
    assert_eq!(point, decoded);
}

流式处理

use jam_codec::{Encoder, Decoder};
use std::io::{Cursor, Read, Write};

fn stream_example() {
    let data = (0..1000).collect::<Vec<u32>>();
    
    // 编码到流
    let mut encoder = Encoder::new(Vec::new());
    encoder.write_all(&data).unwrap();
    let encoded = encoder.into_inner();
    
    // 从流解码
    let mut decoder = Decoder::new(Cursor::new(encoded));
    let mut decoded = Vec::new();
    decoder.read_to_end(&mut decoded).unwrap();
    
    assert_eq!(data, decoded);
}

性能优化技巧

  1. 重用缓冲区:对于高频序列化场景,重用缓冲区减少分配
use jam_codec::{Encoder, Decoder};

let mut encoder = Encoder::with_capacity(1024);  // 预分配缓冲区
let mut decoder = Decoder::new();
  1. 选择合适的压缩级别
use jam_codec::{CompressionLevel, encode_with_compression};

let data = vec![0u8; 1024];
let compressed = encode_with_compression(&data, CompressionLevel::Fastest);
  1. 批量处理小对象:将多个小对象打包序列化

注意事项

  • 序列化格式不保证跨版本兼容
  • 压缩数据需要额外的CPU开销,根据场景权衡
  • 对于超大数据结构,考虑分块处理

jam-codec特别适合网络通信、数据存储和进程间通信等需要高效数据交换的场景。通过合理使用可以显著提升应用程序的性能。

完整示例代码

下面是一个结合了多种功能的完整示例:

use jam_codec::{Encode, Decode, encode_compressed, decode_compressed, 
                Encoder, Decoder, CompressionLevel};
use std::io::{Cursor, Read, Write};

// 自定义数据结构
#[derive(Encode, Decode, Debug, PartialEq)]
struct SensorData {
    id: u32,
    timestamp: u64,
    readings: Vec<f32>,
    status: String,
}

fn main() {
    // 1. 简单序列化示例
    let simple_data = vec!["hello", "world", "jam", "codec"];
    let encoded_simple = jam_codec::encode(&simple_data).unwrap();
    let decoded_simple: Vec<String> = jam_codec::decode(&encoded_simple).unwrap();
    println!("简单序列化测试: {:?}", decoded_simple);

    // 2. 带压缩的自定义类型序列化
    let sensor_data = SensorData {
        id: 42,
        timestamp: 1623456789,
        readings: vec![23.5, 24.1, 22.8, 25.3],
        status: "normal".to_string(),
    };
    
    // 使用最佳压缩级别
    let compressed_data = encode_compressed(&sensor_data).unwrap();
    println!("压缩后大小: {} bytes", compressed_data.len());
    
    let decompressed: SensorData = decode_compressed(&compressed_data).unwrap();
    assert_eq!(sensor_data, decompressed);

    // 3. 流式处理大量数据
    let large_data: Vec<u64> = (0..10_000).map(|x| x * x).collect();
    
    // 使用预分配缓冲区的编码器
    let mut encoder = Encoder::with_capacity(1024 * 1024); // 1MB缓冲区
    encoder.write_all(&large_data).unwrap();
    let encoded_stream = encoder.into_inner();
    
    // 流式解码
    let mut decoder = Decoder::new(Cursor::new(encoded_stream));
    let mut decoded_stream = Vec::new();
    decoder.read_to_end(&mut decoded_stream).unwrap();
    
    assert_eq!(large_data, decoded_stream);
    
    println!("所有测试通过!");
}

这个完整示例展示了:

  1. 基本类型的简单序列化
  2. 自定义结构体的压缩序列化
  3. 大量数据的流式处理
  4. 缓冲区重用等优化技巧

您可以根据实际需求调整压缩级别、缓冲区大小等参数以获得最佳性能。

回到顶部