afastdata 0.0.5

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

[![Crates.io](https://img.shields.io/crates/v/afastdata.svg)](https://crates.io/crates/afastdata)
[![docs.rs](https://docs.rs/afastdata/badge.svg)](https://docs.rs/afastdata)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)

**[English](README_EN.md)** | 中文

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

## 特性

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

## 快速开始

### 安装

在 `Cargo.toml` 中添加依赖:

```toml
[dependencies]
afastdata = "0.0.4"
```

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

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

### 基本用法

```rust
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);
}
```

### 枚举示例

```rust
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);
}
```

### 泛型结构体

```rust
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(...)]` 属性,为结构体字段和枚举变体字段添加校验规则。

### 结构体校验示例

```rust
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
}
```

### 枚举变体校验示例

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

```rust
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`。仅适用于数值类型
- `gte(value, code, message)`:字段值必须大于等于 `value`,否则返回 `ValidateError`。仅适用于数值类型
- `lt(value, code, message)`:字段值必须小于 `value`,否则返回 `ValidateError`。仅适用于数值类型
- `lte(value, code, message)`:字段值必须小于等于 `value`,否则返回 `ValidateError`。仅适用于数值类型
- `len(min, max, code, message)`:字段长度必须在 `min``max` 之间(包含两端),适用于 `String``Vec<T>``[T; N]``Option<T>` 包裹的上述类型,否则返回 `ValidateError`
- `of([v1, v2, ...], code, message)`:字段值必须在 `[v1, v2, ...]` 列表中,否则返回 `ValidateError`
- `func(name)`:调用外部函数 `name` 进行校验,函数签名为 `fn(value: &T, field: &str) -> Result<(), ValidateError>`,返回 `Ok(())` 则校验通过,否则返回 `ValidateError`

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

## 支持的类型

| 类型 | 序列化方式 | 字节数 |
|---|---|---|
| `i8`, `u8` | little-endian | 1 |
| `i16`, `u16` | little-endian | 2 |
| `i32`, `u32` | little-endian | 4 |
| `i64`, `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 切换为 `u16` 或 `u32`,从 0 开始按声明顺序递增),再写入变体字段数据:

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

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

### 长度前缀

`String`、`Vec<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 宏
```

## 运行示例

```bash
cargo run --example basic -p afastdata
```

## 运行测试

```bash
cargo test --workspace
```

## License

MIT