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);
}
性能优化技巧
- 重用缓冲区:对于高频序列化场景,重用缓冲区减少分配
use jam_codec::{Encoder, Decoder};
let mut encoder = Encoder::with_capacity(1024); // 预分配缓冲区
let mut decoder = Decoder::new();
- 选择合适的压缩级别:
use jam_codec::{CompressionLevel, encode_with_compression};
let data = vec![0u8; 1024];
let compressed = encode_with_compression(&data, CompressionLevel::Fastest);
- 批量处理小对象:将多个小对象打包序列化
注意事项
- 序列化格式不保证跨版本兼容
- 压缩数据需要额外的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!("所有测试通过!");
}
这个完整示例展示了:
- 基本类型的简单序列化
- 自定义结构体的压缩序列化
- 大量数据的流式处理
- 缓冲区重用等优化技巧
您可以根据实际需求调整压缩级别、缓冲区大小等参数以获得最佳性能。