自定义序列化器
对于不支持 #[derive(ForyObject)] 的类型,可以手动实现 Serializer trait。
何时使用自定义序列化器
- 来自其他 crate 的外部类型
- 具有特殊序列化要求的类型
- 旧数据格式兼容性
- 性能关键的自定义编码
实现 Serializer Trait
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);
WriteContext 和 ReadContext
WriteContext 和 ReadContext 提供对以下内容的访问:
- writer/reader:二进制缓冲区操作
- type_resolver:类型注册信息
- ref_resolver:引用跟踪(用于共享/循环引用)
常用 Writer 方法
// 原始类型
context.writer.write_i8(value);
context.writer.write_i16(value);
context.writer.write_i32(value);
context.writer.write_i64(value);
context.writer.write_f32(value);
context.writer.write_f64(value);
context.writer.write_bool(value);
// 变长整数
context.writer.write_varint32(value);
context.writer.write_varuint32(value);
// 字符串
context.writer.write_utf8_string(&string);
常用 Reader 方法
// 原始类型
let value = context.reader.read_i8();
let value = context.reader.read_i16();
let value = context.reader.read_i32();
let value = context.reader.read_i64();
let value = context.reader.read_f32();
let value = context.reader.read_f64();
let value = context.reader.read_bool();
// 变长整数
let value = context.reader.read_varint32();
let value = context.reader.read_varuint32();
// 字符串
let string = context.reader.read_utf8_string(len);
最佳实践
- 使用变长编码:对可能较小的整数使用变长编码
- 首先写入长度:对变长数据先写入长度
- 正确处理错误:在 read 方法中正确处理错误
- 实现 ForyDefault:以支持 schema 演化