Rust 序列化
Apache Fory™ Rust
Apache Fory™ 是一个极速的多语言序列化框架,由 JIT 编译和零拷贝技术驱动,在保持易用性和安全性的同时提供超高性能。
Rust 实现提供了多功能的高性能序列化,具备自动内存管理和编译时类型安全。
🚀 为什么选择 Apache Fory™ Rust?
- 🔥 极速性能:零拷贝反序列化和优化的二进制协议
- 🌍 跨语言:与 Java、Python、C++、Go、JavaScript 和 Rust 之间无缝序列化/反序列化数据
- 🎯 类型安全:通过派生宏进行编译时类型检查
- 🔄 循环引用:使用
Rc/Arc和弱指针自动追踪共享和循环引用 - 🧬 多态:使用
Box<dyn Trait>、Rc<dyn Trait>和Arc<dyn Trait>序列化 trait 对象 - 📦 Schema 演进:兼容模式支持独立的 schema 变更
- ⚡ 两种模式:对象图序列化和零拷贝的基于行的格式
📦 Crates
| Crate | 描述 | 版本 |
|---|---|---|
fory | 带派生宏的高级 API | https://crates.io/crates/fory |
fory-core | 核心序列化引擎 | https://crates.io/crates/fory-core |
fory-derive | 过程宏 | https://crates.io/crates/fory-derive |
🏃 快速开始
添加 Apache Fory™ 到你的 Cargo.toml:
[dependencies]
fory = "0.13"
基本示例
use fory::{Fory, Error, Reader};
use fory::ForyObject;
#[derive(ForyObject, Debug, PartialEq)]
struct User {
name: String,
age: i32,
email: String,
}
fn main() -> Result<(), Error> {
let mut fory = Fory::default();
fory.register::<User>(1)?;
let user = User {
name: "Alice".to_string(),
age: 30,
email: "alice@example.com".to_string(),
};
// 序列化
let bytes = fory.serialize(&user)?;
// 反序列化
let decoded: User = fory.deserialize(&bytes)?;
assert_eq!(user, decoded);
// 序列化到指定缓冲区
let mut buf: Vec<u8> = vec![];
fory.serialize_to(&user, &mut buf)?;
// 从指定缓冲区反序列化
let mut reader = Reader::new(&buf);
let decoded: User = fory.deserialize_from(&mut reader)?;
assert_eq!(user, decoded);
Ok(())
}
📚 核心特性
1. 对象图序列化
Apache Fory™ 提供了复杂对象图的自动序列化,保留对象之间的结构和关系。#[derive(ForyObject)] 宏在编译时生成高效的序列化代码,消除运行时开销。
核心能力:
- 任意深度的嵌套结构体序列化
- 集合类型(Vec、HashMap、HashSet、BTreeMap)
- 使用
Option<T>的可选字段 - 自动处理基本类型和字符串
- 使用变长整数的高效二进制编码
use fory::{Fory, Error};
use fory::ForyObject;
use std::collections::HashMap;
#[derive(ForyObject, Debug, PartialEq)]
struct Person {
name: String,
age: i32,
address: Address,
hobbies: Vec<String>,
metadata: HashMap<String, String>,
}
#[derive(ForyObject, Debug, PartialEq)]
struct Address {
street: String,
city: String,
country: String,
}
let mut fory = Fory::default();
fory.register::<Address>(100);
fory.register::<Person>(200);
let person = Person {
name: "John Doe".to_string(),
age: 30,
address: Address {
street: "123 Main St".to_string(),
city: "New York".to_string(),
country: "USA".to_string(),
},
hobbies: vec!["reading".to_string(), "coding".to_string()],
metadata: HashMap::from([
("role".to_string(), "developer".to_string()),
]),
};
let bytes = fory.serialize(&person);
let decoded: Person = fory.deserialize(&bytes)?;
assert_eq!(person, decoded);
2. 共享和循环引用
Apache Fory™ 使用 Rc<T> 和 Arc<T> 自动追踪和保留共享对象的引用标识。当同一个对象被多次引用时,Fory 只序列化一次,并为后续出现的引用使用引用 ID。这确保了:
- 空间效率:序列化输出中没有数据重复
- 引用标识保留:反序列化的对象保持相同的共享关系
- 循环引用支持:使用
RcWeak<T>和ArcWeak<T>打破循环
使用 Rc/Arc 的共享引用
use fory::Fory;
use std::rc::Rc;
let fory = Fory::default();
// 创建一个共享值
let shared = Rc::new(String::from("shared_value"));
// 多次引用它
let data = vec![shared.clone(), shared.clone(), shared.clone()];
// 共享值只被序列化一次
let bytes = fory.serialize(&data);
let decoded: Vec<Rc<String>> = fory.deserialize(&bytes)?;
// 验证引用标识被保留
assert_eq!(decoded.len(), 3);
assert_eq!(*decoded[0], "shared_value");
// 所有三个 Rc 指针指向同一个对象
assert!(Rc::ptr_eq(&decoded[0], &decoded[1]));
assert!(Rc::ptr_eq(&decoded[1], &decoded[2]));
对于线程安全的共享引用,使用 Arc<T>:
use std::sync::Arc;
let shared = Arc::new(String::from("shared_value"));
let data = vec![shared.clone(), shared.clone(), shared.clone()];
let bytes = fory.serialize(&data);
let decoded: Vec<Arc<String>> = fory.deserialize(&bytes)?;
// Arc 也保留引用标识
assert!(Arc::ptr_eq(&decoded[0], &decoded[1]));
使用弱指针的循环引用
要序列化像父子关系或双向链表结构这样的循环引用,使用 RcWeak<T> 或 ArcWeak<T> 来打破循环。这些弱指针被序列化为对其强指针对应物的引用,在不导致内存泄漏或无限递归的情况下保留图结构。
工作原理:
- 弱指针序列化为对其目标对象的引用
- 如果强指针已被丢弃,弱指针序列化为
Null - 前向引用(弱指针在目标之前出现)通过回调解析
- 弱指针的所有克隆共享相同的内部 cell 以实现自动更新
use fory::{Fory, Error};
use fory::ForyObject;
use fory::RcWeak;
use std::rc::Rc;
use std::cell::RefCell;
#[derive(ForyObject, Debug)]
struct Node {
value: i32,
parent: RcWeak<RefCell<Node>>,
children: Vec<Rc<RefCell<Node>>>,
}
let mut fory = Fory::default();
fory.register::<Node>(2000);
// Build a parent-child tree
let parent = Rc::new(RefCell::new(Node {
value: 1,
parent: RcWeak::new(),
children: vec![],
}));
let child1 = Rc::new(RefCell::new(Node {
value: 2,
parent: RcWeak::from(&parent),
children: vec![],
}));
let child2 = Rc::new(RefCell::new(Node {
value: 3,
parent: RcWeak::from(&parent),
children: vec![],
}));
parent.borrow_mut().children.push(child1.clone());
parent.borrow_mut().children.push(child2.clone());
// 序列化和反序列化循环结构
let bytes = fory.serialize(&parent);
let decoded: Rc<RefCell<Node>> = fory.deserialize(&bytes)?;
// 验证循环关系
assert_eq!(decoded.borrow().children.len(), 2);
for child in &decoded.borrow().children {
let upgraded_parent = child.borrow().parent.upgrade().unwrap();
assert!(Rc::ptr_eq(&decoded, &upgraded_parent));
}
使用 Arc 的线程安全循环图:
use fory::{Fory, Error};
use fory::ForyObject;
use fory::ArcWeak;
use std::sync::{Arc, Mutex};
#[derive(ForyObject)]
struct Node {
val: i32,
parent: ArcWeak<Mutex<Node>>,
children: Vec<Arc<Mutex<Node>>>,
}
let mut fory = Fory::default();
fory.register::<Node>(6000);
let parent = Arc::new(Mutex::new(Node {
val: 10,
parent: ArcWeak::new(),
children: vec![],
}));
let child1 = Arc::new(Mutex::new(Node {
val: 20,
parent: ArcWeak::from(&parent),
children: vec![],
}));
let child2 = Arc::new(Mutex::new(Node {
val: 30,
parent: ArcWeak::from(&parent),
children: vec![],
}));
parent.lock().unwrap().children.push(child1.clone());
parent.lock().unwrap().children.push(child2.clone());
let bytes = fory.serialize(&parent);
let decoded: Arc<Mutex<Node>> = fory.deserialize(&bytes)?;
assert_eq!(decoded.lock().unwrap().children.len(), 2);
for child in &decoded.lock().unwrap().children {
let upgraded_parent = child.lock().unwrap().parent.upgrade().unwrap();
assert!(Arc::ptr_eq(&decoded, &upgraded_parent));
}
3. Trait 对象序列化
Apache Fory™ 通过 trait 对象支持多态序列化,实现动态分发和类型灵活性。这对于插件系统、异构集合和可扩展架构至关重要。
支持的 trait 对象类型:
Box<dyn Trait>- 拥有所有权的 trait 对象Rc<dyn Trait>- 引用计数的 trait 对象Arc<dyn Trait>- 线程安全的引用计数 trait 对象Vec<Box<dyn Trait>>、HashMap<K, Box<dyn Trait>>- trait 对象集合
基本 Trait 对象序列化
use fory::{Fory, register_trait_type};
use fory::Serializer;
use fory::ForyObject;
trait Animal: Serializer {
fn speak(&self) -> String;
fn name(&self) -> &str;
}
#[derive(ForyObject)]
struct Dog { name: String, breed: String }
impl Animal for Dog {
fn speak(&self) -> String { "Woof!".to_string() }
fn name(&self) -> &str { &self.name }
}
#[derive(ForyObject)]
struct Cat { name: String, color: String }
impl Animal for Cat {
fn speak(&self) -> String { "Meow!".to_string() }
fn name(&self) -> &str { &self.name }
}
// 注册 trait 实现
register_trait_type!(Animal, Dog, Cat);
#[derive(ForyObject)]
struct Zoo {
star_animal: Box<dyn Animal>,
}
let mut fory = Fory::default().compatible(true);
fory.register::<Dog>(100);
fory.register::<Cat>(101);
fory.register::<Zoo>(102);
let zoo = Zoo {
star_animal: Box::new(Dog {
name: "Buddy".to_string(),
breed: "Labrador".to_string(),
}),
};
let bytes = fory.serialize(&zoo);
let decoded: Zoo = fory.deserialize(&bytes)?;
assert_eq!(decoded.star_animal.name(), "Buddy");
assert_eq!(decoded.star_animal.speak(), "Woof!");
序列化 dyn Any Trait 对象
Apache Fory™ 支持序列化 Rc<dyn Any> 和 Arc<dyn Any> 以实现运行时类型分发。这在你需要最大灵活性且不想定义自定义 trait 时很有用。
关键点:
- 适用于任何实现
Serializer的类型 - 反序列化后需要向下转型以访问具体类型
- 序列化期间保留类型信息
- 适用于插件系统和动态类型处理
use std::rc::Rc;
use std::any::Any;
let dog_rc: Rc<dyn Animal> = Rc::new(Dog {
name: "Rex".to_string(),
breed: "Golden".to_string()
});
// 转换为 Rc<dyn Any> 用于序列化
let dog_any: Rc<dyn Any> = dog_rc.clone();
// 序列化 Any 包装器
let bytes = fory.serialize(&dog_any);
let decoded: Rc<dyn Any> = fory.deserialize(&bytes)?;
// 向下转型回具体类型
let unwrapped = decoded.downcast_ref::<Dog>().unwrap();
assert_eq!(unwrapped.name, "Rex");
对于线程安全场景,使用 Arc<dyn Any>:
use std::sync::Arc;
use std::any::Any;
let dog_arc: Arc<dyn Animal> = Arc::new(Dog {
name: "Buddy".to_string(),
breed: "Labrador".to_string()
});
// 转换为 Arc<dyn Any>
let dog_any: Arc<dyn Any> = dog_arc.clone();
let bytes = fory.serialize(&dog_any);
let decoded: Arc<dyn Any> = fory.deserialize(&bytes)?;
// 向下转型为具体类型
let unwrapped = decoded.downcast_ref::<Dog>().unwrap();
assert_eq!(unwrapped.name, "Buddy");
结构体中基于 Rc/Arc 的 Trait 对象
对于带有 Rc<dyn Trait> 或 Arc<dyn Trait> 的字段,Fory 自动处理转换:
use std::sync::Arc;
use std::rc::Rc;
use std::collections::HashMap;
#[derive(ForyObject)]
struct AnimalShelter {
animals_rc: Vec<Rc<dyn Animal>>,
animals_arc: Vec<Arc<dyn Animal>>,
registry: HashMap<String, Arc<dyn Animal>>,
}
let mut fory = Fory::default().compatible(true);
fory.register::<Dog>(100);
fory.register::<Cat>(101);
fory.register::<AnimalShelter>(102);
let shelter = AnimalShelter {
animals_rc: vec![
Rc::new(Dog { name: "Rex".to_string(), breed: "Golden".to_string() }),
Rc::new(Cat { name: "Mittens".to_string(), color: "Gray".to_string() }),
],
animals_arc: vec![
Arc::new(Dog { name: "Buddy".to_string(), breed: "Labrador".to_string() }),
],
registry: HashMap::from([
("pet1".to_string(), Arc::new(Dog {
name: "Max".to_string(),
breed: "Shepherd".to_string()
}) as Arc<dyn Animal>),
]),
};
let bytes = fory.serialize(&shelter);
let decoded: AnimalShelter = fory.deserialize(&bytes)?;
assert_eq!(decoded.animals_rc[0].name(), "Rex");
assert_eq!(decoded.animals_arc[0].speak(), "Woof!");
独立 Trait 对象序列化
由于 Rust 的孤儿规则,Rc<dyn Trait> 和 Arc<dyn Trait> 不能直接实现 Serializer。对于独立序列化(不在结构体字段内),register_trait_type! 宏会生成包装器类型。
注意: 如果你不想使用包装器类型,可以改为序列化为 Rc<dyn Any> 或 Arc<dyn Any>(参见上面的 dyn Any 部分)。
register_trait_type! 宏生成 AnimalRc 和 AnimalArc 包装器类型:
// 对于 Rc<dyn Trait>
let dog_rc: Rc<dyn Animal> = Rc::new(Dog {
name: "Rex".to_string(),
breed: "Golden".to_string()
});
let wrapper = AnimalRc::from(dog_rc);
let bytes = fory.serialize(&wrapper);
let decoded: AnimalRc = fory.deserialize(&bytes)?;
// 解包回 Rc<dyn Animal>
let unwrapped: Rc<dyn Animal> = decoded.unwrap();
assert_eq!(unwrapped.name(), "Rex");
// 对于 Arc<dyn Trait>
let dog_arc: Arc<dyn Animal> = Arc::new(Dog {
name: "Buddy".to_string(),
breed: "Labrador".to_string()
});
let wrapper = AnimalArc::from(dog_arc);
let bytes = fory.serialize(&wrapper);
let decoded: AnimalArc = fory.deserialize(&bytes)?;
let unwrapped: Arc<dyn Animal> = decoded.unwrap();
assert_eq!(unwrapped.name(), "Buddy");
4. Schema 演进
Apache Fory™ 在兼容模式下支持 schema 演进,允许序列化和反序列化端拥有不同的类型定义。这使得分布式系统中的服务能够独立演进而不破坏兼容性。
特性:
- 添加带默认值的新字段
- 移除过时字段(反序列化期间跳过)
- 改变字段可空性(
T↔Option<T>) - 重新排序字段(按名称匹配,而非位置)
- 为缺失字段提供类型安全的默认值回退
兼容性规则:
- 字段名必须匹配(区分大小写)
- 不支持类型更改(可空/非可空除外)
- 嵌套结构体类型必须在两端都注册
use fory::Fory;
use fory::ForyObject;
use std::collections::HashMap;
#[derive(ForyObject, Debug)]
struct PersonV1 {
name: String,
age: i32,
address: String,
}
#[derive(ForyObject, Debug)]
struct PersonV2 {
name: String,
age: i32,
// address removed
// phone added
phone: Option<String>,
metadata: HashMap<String, String>,
}
let mut fory1 = Fory::default().compatible(true);
fory1.register::<PersonV1>(1);
let mut fory2 = Fory::default().compatible(true);
fory2.register::<PersonV2>(1);
let person_v1 = PersonV1 {
name: "Alice".to_string(),
age: 30,
address: "123 Main St".to_string(),
};
// 使用 V1 序列化
let bytes = fory1.serialize(&person_v1);
// 使用 V2 反序列化 - 缺失字段获得默认值
let person_v2: PersonV2 = fory2.deserialize(&bytes)?;
assert_eq!(person_v2.name, "Alice");
assert_eq!(person_v2.age, 30);
assert_eq!(person_v2.phone, None);
5. 枚举支持
Apache Fory™ 支持无数据载荷的枚举(C 风格枚举)。每个变体在序列化期间被分配一个序数值(0、1、2、...)。
特性:
- 高效的 varint 编码序数
- 兼容模式下的 schema 演进支持
- 类型安全的变体匹配
- 使用
#[default]的默认变体支持
use fory::ForyObject;
#[derive(Default, ForyObject, Debug, PartialEq)]
enum Status {
#[default]
Pending,
Active,
Inactive,
Deleted,
}
let mut fory = Fory::default();
fory.register::<Status>(1);
let status = Status::Active;
let bytes = fory.serialize(&status);
let decoded: Status = fory.deserialize(&bytes)?;
assert_eq!(status, decoded);
6. 自定义序列化器
对于不能使用 #[derive(ForyObject)] 的类型,手动实现 Serializer trait。这在以下情况下很有用:
- 来自其他 crate 的外部类型
- 具有特殊序列化要求的类型
- 旧版数据格式兼容性
- 性能关键的自定义编码
use fory::{Fory, ReadContext, WriteContext, Serializer, ForyDefault, Error};
use std::any::Any;
#[derive(Debug, PartialEq)]
struct CustomType {
value: i32,
name: String,
}
impl Serializer for CustomType {
fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) {
context.writer.write_i32(self.value);
context.writer.write_varuint32(self.name.len() as u32);
context.writer.write_utf8_string(&self.name);
}
fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
let value = context.reader.read_i32();
let len = context.reader.read_varuint32() as usize;
let name = context.reader.read_utf8_string(len);
Ok(Self { value, name })
}
fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> u32 {
Self::fory_get_type_id(type_resolver)
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl ForyDefault for CustomType {
fn fory_default() -> Self {
Self::default()
}
}
let mut fory = Fory::default();
fory.register_serializer::<CustomType>(100);
let custom = CustomType {
value: 42,
name: "test".to_string(),
};
let bytes = fory.serialize(&custom);
let decoded: CustomType = fory.deserialize(&bytes)?;
assert_eq!(custom, decoded);