1个不稳定版本
使用旧的Rust 2015
0.1.0 | 2017年9月25日 |
---|
#2241 in 编码
75KB
1.5K SLoC
zlo
一个编码/解码器对,使用位紧凑的二进制编码方案。编码对象的尺寸几乎与在运行的Rust程序中对象占用的内存大小相同或更小。它是bincode的分支,因此API相似,还包含熟悉的SizeLimit
对象。
它是为了在多玩家游戏中的网络使用而制作的,适合在网络中编码频繁发送但尺寸很小的数据差异,而bincode会产生相对较大的数据块,使用如LZO等通用算法压缩通常会与zlo编码数据相比带来非常小的改进,但代价是增加了长压缩时间。
二进制格式在不同版本之间的稳定性不得到保证。
示例
#[macro_use]
extern crate serde_derive;
extern crate zlo;
use zlo::{serialize, deserialize, Infinite};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Entity {
x: f32,
y: f32,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct World(Vec<Entity>);
fn main() {
let world = World(vec![Entity { x: 0.0, y: 4.0 }, Entity { x: 10.0, y: 20.5 }]);
let encoded: Vec<u8> = serialize(&world, Infinite).unwrap();
assert!(encoded.len() < 8 + 4 * 4);
let decoded: World = deserialize(&encoded[..]).unwrap();
assert_eq!(world, decoded);
}
性能,输出大小
zlo反序列化器不是零拷贝,且在大多数情况下不能实现。这是因为在此编码中位乱序的数据出现频率很低。
处理最快的原始数据类型是无符号整数和布尔值。性能还取决于写入的数据量。例如,编码小的64位整数仅略慢于适合该类型的值。
zlo主要用于序列化数据的差异,即包含大量Option
、小的整数和差异化的zigzag浮点数的结构体。在这些条件下,zlo可以产生非常紧凑的数据。
与Bincode相比
在编码大的64位整数时,zlo可能比bincode慢7倍。平均而言,在编码大量整数或浮点数时,zlo可以预期比bincode慢3到5倍。在编码纯字节时,zlo的性能与bincode相当,但zlo不是零拷贝,因此与bincode相比,在反序列化时可能会产生额外的分配开销。
与 bincode 相比,在编码数字时,输出大小平均可减小至 1.5 倍;在编码大量 bools 或 Option::None
时,可减小至 8 倍。
需要将数据压缩到更少的比特数吗?
- 考虑通过它们的组成部分(指数和分数)来比较浮点数。
- 或者,你的值是否保持在已知的特定范围内?那么考虑将其序列化为整数,有符号或无符号均可。
- 它是多维的?也许你可以从单个记录中推断出相关元素。
- 序列化多维单位值,如单位向量或四元数?可以更紧凑地序列化,例如,2D 单位向量可以简化为角度。
参见 示例。
有损分数编码
目前没有计划实现。此外,即使考虑有损分数,也只有在 Rust 问题 #44580 稳定后才能实现。
详情
布尔值以单个比特编码,整数以类似于 LEB128 但不等于 LEB128 的形式编码,浮点数以以下复杂的方式进行编码,元组和结构体通过逐个字段编码,枚举通过先写出表示变体的标记,然后写出内容进行编码。
由于写入的字节数量不固定,zlo 没有可配置的字节序。
需要注意的实现细节
- 单独的比特从最低位到最高位写入。
- 无符号整数使用以下原则进行编码
PC | |
---|---|
0 | 如果 整数 > 0,则 写入比特 1,否则 写入比特 0 并 返回 |
1 | 写入整数的下一个 8 位 |
2 | 如果 这是整个类型的最高有效字节,则 返回 |
3 | 如果 没有更多的比特要写入,则 写入比特 0 并 返回 |
4 | 写入比特 1 |
5 | 跳转到 1 |
- 有符号整数是 zigzag 编码的(与 protobuf 相同),然后以与无符号整数相同的方式进行编码
- 浮点数按以下方式进行编码:始终写入符号位,指数以 2 位或完整形式写入,小数部分在 f32 的情况下只写入高 16 位,在 f64 的情况下写入高 32 位,或者如果它不合适,则写入完整的小数部分。
isize
/usize
以可变 i64
/u64
的形式进行编码,以提高可移植性。- 枚举变体以变量
u32
而不是usize
进行编码。对于所有实际用途,u32
足够使用。 str
以(可变 u64, &[u8])
的形式进行编码,其中u64
是编码字符串中包含的字节数。
许可
zlo 在 MIT 许可证下授权(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
依赖项
~110–355KB