afastdata 0.0.6

A high-performance binary serialization/deserialization library with derive macros for Rust types
Documentation

afastdata

Crates.io docs.rs License: MIT

English | 中文

高性能 Rust 二进制序列化/反序列化框架,通过 derive 宏为自定义类型自动生成序列化代码。

特性

  • 零配置派生宏#[derive(AFastSerialize, AFastDeserialize)]
  • 丰富的类型支持 — 基本类型、StringVec<T>Option<T>[T; N]Box<T>、元组、HashMapHashSetBTreeMapBTreeSet、嵌套结构体、枚举
  • 泛型支持 — 自动为泛型参数添加 trait 约束
  • 可配置长度前缀 — 默认 u32(最大 4GB),可通过 feature 切换为 u64
  • 可配置枚举标签 — 默认 u8,可通过 feature 切换为 u16u32
  • 可配置元组支持 — 默认支持最多 16 个元素,可通过 feature 切换为 8 或 32
  • 统一小端序 — 所有多字节数据使用 little-endian 编码
  • 零外部依赖 — 运行时无第三方依赖

快速开始

安装

Cargo.toml 中添加依赖:

[dependencies]
afastdata = "0.0.6"

如需 u64 长度前缀或自定义枚举标签类型:

[dependencies]
afastdata = { version = "0.0.6", features = ["len-u64", "tag-u16"] }

基本用法

use afastdata::{AFastSerialize, AFastDeserialize};

#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
struct User {
    name: String,
    age: u32,
    email: Option<String>,
}

fn main() {
    let user = User {
        name: String::from("Alice"),
        age: 30,
        email: Some(String::from("alice@example.com")),
    };

    // 序列化
    let bytes = user.to_bytes();

    // 反序列化
    let (decoded, consumed) = User::from_bytes(&bytes).unwrap();
    assert_eq!(user, decoded);
    println!("消耗 {} 字节", consumed);
}

枚举示例

use afastdata::{AFastSerialize, AFastDeserialize};

#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
enum Command {
    Ping,
    Send { to: String, message: String },
    Broadcast(Vec<String>),
}

fn main() {
    let cmd = Command::Send {
        to: String::from("Bob"),
        message: String::from("Hello!"),
    };

    let bytes = cmd.to_bytes();
    let (decoded, _) = Command::from_bytes(&bytes).unwrap();
    assert_eq!(cmd, decoded);
}

泛型结构体

use afastdata::{AFastSerialize, AFastDeserialize};

#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
struct Response<T> {
    code: u32,
    data: Option<T>,
    message: String,
}

fn main() {
    let resp = Response {
        code: 200,
        data: Some(vec![1i32, 2, 3]),
        message: String::from("ok"),
    };

    let bytes = resp.to_bytes();
    let (decoded, _) = Response::<Vec<i32>>::from_bytes(&bytes).unwrap();
    assert_eq!(resp, decoded);
}

数据校验

通过 #[afast(...)] 属性,为结构体字段和枚举变体字段添加校验规则。

结构体校验示例

use afastdata::{AFastDeserialize, AFastSerialize, ValidateError};

#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
struct A {
    #[afast(
        gt(10, 0, "${field} 必须大于 10"),
        lte(100, 0, "${field} 必须小于等于 100")
    )]
    a: i64,

    #[afast(len(
        10,
        100,
        1,
        "${field} 长度必须大于等于 10 且小于等于 100"
    ))]
    b: Option<String>,

    #[afast(func("v"))] // 调用 v 函数进行校验, 参数为 `值` 和 `字段名`
    c: i32,

    #[afast(skip("d"))] // 调用 d 函数, #[afast(skip)] 将调用 i64::default()
    e: i64,
}

fn v(value: &i32, field: &str) -> Result<(), ValidateError> {
    if *value % 2 == 0 {
        Ok(())
    } else {
        Err(ValidateError::new(
            2,
            format!("{} 必须是偶数,但实际为 {}", field, value),
        ))
    }
}

fn d() -> i64 {
    123
}

枚举变体校验示例

校验规则同样适用于枚举的命名字段变体和元组变体:

use afastdata::{AFastDeserialize, AFastSerialize, ErrorKind};

#[derive(AFastSerialize, AFastDeserialize, Debug, PartialEq)]
enum Command {
    // 命名字段变体
    Login {
        #[afast(len(1, 32, 1001, "用户名 ${field} 长度必须在 1-32 之间"))]
        username: String,
        #[afast(len(6, 128, 1002, "密码 ${field} 长度必须在 6-128 之间"))]
        password: String,
    },
    // 元组变体
    Send(#[afast(gte(0, 2001, "值必须 >= 0"))] i64),
}

fn main() {
    // 校验通过
    let cmd = Command::Login {
        username: String::from("alice"),
        password: String::from("secret123"),
    };
    let bytes = cmd.to_bytes();
    assert!(Command::from_bytes(&bytes).is_ok());

    // 校验失败:用户名为空
    let cmd = Command::Login {
        username: String::new(),
        password: String::from("secret123"),
    };
    let bytes = cmd.to_bytes();
    let err = Command::from_bytes(&bytes).unwrap_err();
    assert!(matches!(err.kind(), ErrorKind::ValidateError(1001, _)));
}

校验规则

校验规则适用于结构体字段和枚举变体字段(命名字段和元组变体):

  • skip or skip(default):跳过此字段的序列化和反序列化,并使用默认值(调用传入的 default 函数或者给字段类型实现 Default trait)
  • gt(value, code, message):字段值必须大于 value(支持整数和浮点数),否则返回 ValidateError。适用于数值类型和 Option<数值类型>None 视为通过)
  • gte(value, code, message):字段值必须大于等于 value,否则返回 ValidateError。适用于数值类型和 Option<数值类型>
  • lt(value, code, message):字段值必须小于 value,否则返回 ValidateError。适用于数值类型和 Option<数值类型>
  • lte(value, code, message):字段值必须小于等于 value,否则返回 ValidateError。适用于数值类型和 Option<数值类型>
  • len(min, max, code, message):字段长度必须在 minmax 之间(包含两端),适用于 StringVec<T>[T; N]Option<T> 包裹的上述类型(None 视为通过)。minmax-1 表示不限制该边界,例如 len(3, -1, ...) 表示最小长度 3,无最大限制
  • of([v1, v2, ...], code, message):字段值必须在 [v1, v2, ...] 列表中,否则返回 ValidateError
  • func(name):调用外部函数 name 进行校验,函数签名为 fn(value: &T, field: &str) -> Result<(), ValidateError>,返回 Ok(()) 则校验通过,否则返回 ValidateError

类型检查:校验规则在编译期检查字段类型兼容性。例如 gt/gte/lt/lte 只能用于数值类型或 Option<数值类型>len 只能用于字符串和集合类型。不兼容的组合会产生编译错误。

支持的类型

类型 序列化方式 字节数
i8, u8 little-endian 1
i16, u16 little-endian 2
i32, u32 little-endian 4
i64, u64 little-endian 8
usize u64 little-endian(跨平台兼容) 8
i128, u128 little-endian 16
f32 IEEE 754 little-endian 4
f64 IEEE 754 little-endian 8
bool 0x00=false, 0x01=true 1
String LenInt 长度前缀 + UTF-8 字节 变长
&str LenInt 长度前缀 + UTF-8 字节(仅序列化) 变长
Vec<T> LenInt 元素个数 + 逐元素编码 变长
Option<T> 1 字节标记 + 数据(仅 Some) 变长
[T; N] 逐元素编码,无长度前缀 固定
(A, B, ...) 逐元素编码,无长度前缀 固定/变长
Box<T> T 相同 T 相同
HashMap<K, V> LenInt 键值对数 + 逐对编码 变长
HashSet<T> LenInt 元素个数 + 逐元素编码 变长
BTreeMap<K, V> LenInt 键值对数 + 逐对编码 变长
BTreeSet<T> LenInt 元素个数 + 逐元素编码 变长
结构体 逐字段编码,无额外前缀 变长
枚举 Tag(u8/u16/u32) 变体索引 + 变体字段数据 变长

编码格式详解

结构体

所有字段按声明顺序依次序列化,无额外前缀:

[field1 bytes][field2 bytes][field3 bytes]...

枚举

先写入变体索引(Tag 类型,默认 u8,可通过 feature 切换为 u16u32,从 0 开始按声明顺序递增),再写入变体字段数据:

[Tag variant_index][field1 bytes][field2 bytes]...

Unit 变体只写入索引,无字段数据。

长度前缀

StringVec<T> 等变长类型使用 LenInt 作为长度前缀:

  • 默认:u32 little-endian(4 字节,最大约 4GB)
  • 启用 len-u64 feature 后:u64 little-endian(8 字节)

Feature Flags

Feature 说明 默认
len-u64 将长度前缀从 u32 切换为 u64
tag-u8 枚举变体标签使用 u8(1 字节,最多 256 个变体)
tag-u16 枚举变体标签使用 u16(2 字节,最多 65536 个变体)
tag-u32 枚举变体标签使用 u32(4 字节,最多约 42 亿个变体)
tuple-8 元组支持最多 8 个元素
tuple-16 元组支持最多 16 个元素
tuple-32 元组支持最多 32 个元素

项目结构

afastdata/
├── Cargo.toml                  # Workspace 配置
├── README.md                   # 中文文档(本文件)
├── README_EN.md                # English documentation
├── afastdata/                  # 核心库 + 统一入口 crate
│   ├── Cargo.toml              # 含 `len-u64`、`tag-*`、`tuple-*` features
│   ├── src/lib.rs              # trait 定义 + 基本类型实现 + re-export derive 宏
│   └── tests/
│       ├── derive_tests.rs     # 派生宏集成测试
│       └── primitive_tests.rs  # 基本类型序列化测试
└── afastdata-macro/            # Proc-macro 库
    ├── Cargo.toml
    └── src/lib.rs              # AFastSerialize / AFastDeserialize derive 宏

运行示例

cargo run --example basic -p afastdata

运行测试

cargo test --workspace

License

MIT