面向 Rust 的缓冲区级 binary codec。
概述
Qubit Binary Codec 提供基于调用方管理 byte buffer 的低层 binary codec。它不依赖 std::io;面向 stream 的 reader/writer adapter 位于 qubit-io-binary。
本库提供:
- 用于 fixed-width 标量编码/解码的
BinaryCodec。 - 用于 unsigned / signed LEB128 值的
Leb128Codec。 - 用于 ZigZag signed integer mapping 的
ZigZagCodec。 Strict和NonStrictsealed LEB128 解码策略。- 内置 LEB128 policy marker 使用的
Leb128DecodePolicy。 Leb128DecodeError和Leb128DecodeErrorKind。- binary codec 表面使用的必要
qubit-codec原语:Codec、ByteOrder、ByteOrderSpec、BigEndian和LittleEndian。
设计目标
- 缓冲区优先:直接操作调用方持有的 byte slice,不要求
Read或Write。 - 热路径效率:为已经验证过边界的调用方提供 unchecked 静态 codec 方法,并实现
Unit = u8的Codec以接入通用 codec pipeline。 - 分层清晰:只依赖
qubit-codec,stream adapter 交给qubit-io-binary。 - 规范编码:始终写出 canonical LEB128,同时允许配置 decode strictness。
- 强类型字节序:通过类型级 byte-order marker 选择 endian 行为。
- 依赖图小:让低层二进制线格式代码不必拉入通用 I/O 工具。
特性
Fixed-Width Binary Scalar
- 整数覆盖:支持明确位宽的 primitive integer 类型:
u8、i8、u16、i16、u32、i32、u64、i64、u128和i128。平台相关位宽的usize和isize不作为 fixed-width binary scalar 支持。 - 浮点覆盖:支持
f32和f64,并保留 IEEE 754 bit pattern。 - 字节序支持:支持
BigEndian与LittleEndian类型标记。 - Unchecked 热路径:调用方验证容量后,可用
decode_unchecked和encode_unchecked避免重复边界检查。
LEB128 值
- 无符号值:支持
u8、u16、u32、u64、u128和usize。 - 有符号值:支持
i8、i16、i32、i64、i128和isize。 - Strict Decode Policy:
Strict拒绝非 canonical payload。 - Non-Strict Decode Policy:
NonStrict在 decoded value 可表达时接受兼容 payload。 - Sealed Policy Trait:
Leb128DecodePolicy刻意封闭,只使用内置Strict或NonStrictmarker。
ZigZag 值
- 有符号整数映射:把 signed integer 映射到 unsigned LEB128 payload。
- 不完整输入报告:通过
Leb128DecodeError表达 partial LEB128 payload。
聚焦的公开 API
prelude模块:导入 binary codec 类型和核心字节序标记。- 核心 codec trait:
BinaryCodec、Leb128Codec和ZigZagCodec实现qubit_codec::Codec,其中Unit = u8,Value由具体 codec 决定。 - 不包含
std::ioadapter:stream helper 位于qubit-io-binary。
文档
安装
在 Cargo.toml 中添加:
[dependencies]
qubit-codec-binary = "0.1"
快速开始
use qubit_codec_binary::{
BigEndian,
BinaryCodec,
Leb128Codec,
NonStrict,
};
let mut fixed = [0_u8; BinaryCodec::<u32, BigEndian>::MAX_UNITS_PER_VALUE];
unsafe {
BinaryCodec::<u32, BigEndian>::encode_unchecked(0x0102_0304, &mut fixed, 0);
}
assert_eq!([1, 2, 3, 4], fixed);
let mut compact = [0_u8; Leb128Codec::<u64, NonStrict>::MAX_UNITS_PER_VALUE];
let written = unsafe { Leb128Codec::<u64, NonStrict>::encode_unchecked(300, &mut compact, 0) };
assert_eq!(2, written);
Unchecked API 契约
底层 codec 方法刻意设计为 unsafe。调用方必须先验证 buffer 边界:
BinaryCodec::decode_unchecked和BinaryCodec::encode_unchecked要求从index开始分别有MIN_UNITS_PER_VALUE个可读字节或MAX_UNITS_PER_VALUE个可写字节。对于 fixed-width 值,这两个边界相等。Leb128Codec和ZigZagCodec暴露MIN_UNITS_PER_VALUE和MAX_UNITS_PER_VALUE。它们的encode_unchecked要求从index开始至少有MAX_UNITS_PER_VALUE个可写字节,即使实际编码结果可能更短。Leb128Codec::decode_unchecked和ZigZagCodec::decode_unchecked要求从index开始至少有MIN_UNITS_PER_VALUE个可读字节。调用方通常应尽量提供到MAX_UNITS_PER_VALUE,除非 EOF 已经无法继续读取。不完整、畸形和非 canonical 输入都通过Leb128DecodeError表达。Leb128DecodeError::start_index()表示当前尝试解码的值从哪里开始;error_index()表示错误在哪里变得可观察。对于 incomplete input,error_index()是当前可用输入之后的边界,additional()表示至少还需要多少字节才能继续推进解码。
上层代码应先完成这些边界检查,再把 unsafe 调用封装到安全 API 中。owned-value adapter 和 buffered engine 请直接从 qubit-codec 引入;本 crate 不重导出通用 codec adapter。binary codec 示例见用户指南。
API 参考
BinaryCodec 操作
| 条目 | 描述 |
|---|---|
Codec (Unit = u8) | 通过 core trait 解码和编码一个 fixed-width scalar |
MIN_UNITS_PER_VALUE | 当前标量类型所需的最少字节数 |
MAX_UNITS_PER_VALUE | 当前标量类型所需的最多字节数 |
decode_unchecked(input, index) | 无边界检查解码一个 fixed-width scalar |
encode_unchecked(value, output, index) | 无边界检查编码一个 fixed-width scalar |
Leb128Codec 操作
| 条目 | 描述 |
|---|---|
Codec (Unit = u8) | 通过 core trait 解码和编码一个 LEB128 值 |
MIN_UNITS_PER_VALUE | 可能构成完整值的最少可读字节数 |
MAX_UNITS_PER_VALUE | 当前整数类型最多需要的字节数 |
decode_unchecked(input, index) | 解码一个完整 LEB128 值 |
encode_unchecked(value, output, index) | 编码一个 canonical LEB128 值 |
ZigZagCodec 操作
| 条目 | 描述 |
|---|---|
Codec (Unit = u8) | 通过 core trait 解码和编码一个 ZigZag LEB128 值 |
MIN_UNITS_PER_VALUE | 可能构成完整值的最少可读字节数 |
MAX_UNITS_PER_VALUE | 当前 signed integer 类型最多需要的字节数 |
decode_unchecked(input, index) | 解码 ZigZag over unsigned LEB128 |
encode_unchecked(value, output, index) | 把 signed integer 编码为 ZigZag + unsigned LEB128 |
LEB128 Decode Policy
| Policy | 含义 |
|---|---|
Strict | 拒绝非 canonical LEB128 编码 |
NonStrict | 在 decoded value 可表达时接受兼容编码 |
Leb128DecodePolicy | sealed policy trait,由内置 policy marker 实现 |
库边界
qubit-codec-binary 只包含缓冲区级 binary codec。共享 core trait 使用 qubit-codec,通用 std::io helper 使用 qubit-io,面向 stream 的 binary reader/writer 使用 qubit-io-binary。
性能考虑
BinaryCodec、Leb128Codec 和 ZigZagCodec 都是零大小 codec 类型,不产生运行时分配。它们的 unchecked 方法和 Codec 实现(Unit = u8)面向已经验证缓冲区容量的热路径,或被 buffered stream adapter 在内部使用。
测试与代码覆盖率
本项目通过 tests/ 下的集成测试覆盖二进制线格式行为。
运行测试
# 运行所有测试
cargo test
# 运行覆盖率报告
./coverage.sh
# 生成文本格式报告
./coverage.sh text
# 对齐 CI 要求
./align-ci.sh
# 运行 CI 检查(格式化、clippy、测试、覆盖率、安全审计)
RS_CI_SKIP_TOOLCHAIN_UPDATE=1 ./ci-check.sh
依赖项
运行时依赖保持很少:
qubit-codec提供共享 codec 和字节序原语。thiserror提供公共 LEB128 错误类型实现。
许可证
Copyright (c) 2026. Haixing Hu.
根据 Apache 许可证 2.0 版("许可证")授权;除非遵守许可证,否则您不得使用此文件。您可以在以下位置获取许可证副本:
http://www.apache.org/licenses/LICENSE-2.0
除非适用法律要求或书面同意,否则根据许可证分发的软件按"原样"分发,不附带任何明示或暗示的担保或条件。有关许可证下的特定语言管理权限和限制,请参阅许可证。
完整的许可证文本请参阅 LICENSE。
贡献
欢迎贡献!请随时提交 Pull Request。
开发指南
- 保持本 crate 聚焦缓冲区级 binary codec。
- 为 canonical 和 non-canonical 线格式场景补测试。
- 为公开 API 和 safety contract 编写文档。
- 提交 PR 前确保所有检查通过。
作者
胡海星
相关项目
- qubit-codec:共享核心 codec trait 与字节序标记。
- qubit-io-binary:这些 binary codec 的 stream adapter。
- qubit-io:通用
std::iohelper。 - Qubit 旗下的更多 Rust 库发布在 GitHub 组织 qubit-ltd。
---