3个不稳定版本
0.2.0 | 2024年3月25日 |
---|---|
0.1.1 | 2023年10月6日 |
0.1.0 | 2022年11月16日 |
#541 in 编码
6,073 个月下载量
在 11 个crate中(通过 vodozemac)使用
20KB
267 行
Matrix世界中使用的简单二进制编码格式。
matrix-pickle 二进制编码格式在 libolm 和 vodozemac 加密库中使用。
如何使用
使用 matrix-pickle
最简单的方法是使用 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] |
首先编码长度,然后编码每个元素 |
Derive 支持
只要 crate 中的类型实现了 Encode
和 Decode
,则此 crate 支持 struct 和 enum 的 derive 实现。
Structs
Structs 的 derive 支持简单地按照定义的顺序编码 struct 的每个字段,例如
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;
// Encode the first struct field.
ret += self.first.encode(writer)?;
// Now encode the second struct field.
ret += self.second.encode(writer)?;
Ok(ret)
}
}
Enums
另一方面,首先将 variant 的数量编码为 u8
,然后编码枚举的值。
仅支持具有单个关联数据值的 variant 的枚举。
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) => {
// This is our first variant, encode a 0u8 first.
ret += 0u8.encode(writer)?;
// Now encode the associated value.
ret += value.encode(writer)?;
},
Bar::Second(value) => {
// This is our second variant, encode a 1u8 first.
ret += 1u8.encode(writer)?;
// Now encode the associated value.
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],
}
与bincode的比较
二进制格式类似于bincode存储库提供的格式,配置如下
let config = bincode::config::standard()
.with_big_endian()
.with_fixed_int_encoding()
.skip_fixed_array_length();
与格式的主要两个区别是
bincode
使用u64
来编码切片长度matrix-pickle
使用u32
来编码切片长度
其他区别包括
- 不支持配置编码格式,如果您需要调整格式,请使用bincode。
- 没有不安全代码。优化以简单为主,而非纯粹的性能
依赖项
~0.3–1MB
~21K SLoC