Rust FlatBuffers序列化库flatc-rust的使用,高性能零拷贝数据交换格式FlatBuffers的Rust实现
Rust FlatBuffers flatc API
此crate提供了一种编程方式来调用flatc
命令(例如从build.rs
中调用),以生成Rust(或实际上任何其他语言)助手来使用FlatBuffers。
注意:您仍然需要安装版本1.10.0+的flatc
实用程序(有Windows二进制版本,适用于conda的flatbuffers
包[Windows、Linux、MacOS],Arch Linux)。
使用和示例
请参阅文档以获取使用说明和示例。
致谢
API的设计灵感来自protoc-rust、protoc和capnpc。
许可证
此项目根据以下任一许可证授权:
- Apache许可证,版本2.0
- MIT许可证
根据您的选择。
元数据
pkg:cargo/flatc-rust@0.2.0
超过4年前
2018版本
MIT OR Apache-2.0
9.19 KiB
安装
运行以下Cargo命令在您的项目目录中:
cargo add flatc-rust
或者将以下行添加到您的Cargo.toml中:
flatc-rust = “0.2.0”
文档
代码库
所有者
Vlad Frolov
分类
开发工具 API绑定 构建工具 解析器实现
报告crate
完整示例demo:
// build.rs
use flatc_rust::Flatc;
fn main() {
// 调用flatc生成Rust代码
Flatc::new()
.lang("rust")
.input("schema.fbs")
.output("src")
.run()
.expect("Failed to generate Rust code from FlatBuffers schema");
}
// Cargo.toml
[package]
name = "flatbuffers-example"
version = "0.1.0"
edition = "2018"
[dependencies]
flatbuffers = "0.6.0"
[build-dependencies]
flatc-rust = "0.2.0"
// schema.fbs
namespace Example;
table Person {
name: string;
age: int;
}
root_type Person;
// src/main.rs
// 生成的代码将在src/example_generated.rs中
mod example_generated;
use example_generated::example::{Person, PersonArgs};
use flatbuffers::{FlatBufferBuilder, WIPOffset};
fn main() {
// 创建构建器
let mut builder = FlatBufferBuilder::new();
// 创建字符串
let name = builder.create_string("John Doe");
// 创建Person对象
let person = Person::create(&mut builder, &PersonArgs {
name: Some(name),
age: 30,
});
// 完成构建
builder.finish(person, None);
// 获取字节缓冲区
let buf = builder.finished_data();
println!("Serialized data length: {}", buf.len());
// 反序列化验证
let person = flatbuffers::root::<Person>(buf).unwrap();
println!("Name: {}", person.name().unwrap());
println!("Age: {}", person.age());
}
Rust FlatBuffers序列化库flatc-rust的使用指南
概述
flatc-rust是FlatBuffers序列化库的Rust实现,提供高性能的零拷贝数据交换功能。它通过在编译时生成类型安全的代码,实现高效的内存访问和数据序列化/反序列化操作。
安装配置
安装FlatBuffers编译器
# Ubuntu/Debian
sudo apt-get install flatbuffers-compiler
# macOS
brew install flatbuffers
# 或从源码编译
git clone https://github.com/google/flatbuffers.git
cd flatbuffers && mkdir build && cd build
cmake .. && make -j4
sudo make install
添加依赖
在Cargo.toml中添加:
[dependencies]
flatbuffers = "0.8"
基本使用方法
1. 定义Schema文件
创建monster.fbs
文件:
namespace MyGame.Sample;
enum Color:byte { Red = 0, Green = 1, Blue = 2 }
union Equipment { Weapon, Armor }
table Weapon {
name: string;
damage: short;
}
table Armor {
name: string;
defense: short;
}
table Monster {
pos: Vec3;
mana: short = 150;
hp: short = 100;
name: string;
color: Color = Blue;
weapons: [Weapon];
equipped: Equipment;
}
root_type Monster;
2. 生成Rust代码
flatc --rust monster.fbs
3. 序列化示例
use flatbuffers;
use my_game::sample::{Monster, MonsterArgs, Weapon, WeaponArgs, Color};
fn create_monster() -> Vec<u8> {
let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024);
// 创建武器
let weapon_name = builder.create_string("Sword");
let weapon = Weapon::create(&mut builder, &WeaponArgs {
name: Some(weapon_name),
damage: 50,
});
// 创建怪物
let name = builder.create_string("Orc");
let weapons = builder.create_vector(&[weapon]);
let monster = Monster::create(&mut builder, &MonsterArgs {
pos: None,
mana: 150,
hp: 100,
name: Some(name),
color: Color::Green,
weapons: Some(weapons),
equipped: None,
});
builder.finish(monster, None);
builder.finished_data().to_vec()
}
4. 反序列化示例
fn read_monster(buffer: &[u8]) {
let monster = flatbuffers::root::<Monster>(buffer).unwrap();
println!("Monster name: {}", monster.name().unwrap());
println!("HP: {}", monster.hp());
println!("Mana: {}", monster.mana());
if let Some(weapons) = monster.weapons() {
for weapon in weapons {
println!("Weapon: {}, Damage: {}",
weapon.name().unwrap(),
weapon.damage());
}
}
}
高级特性
零拷贝访问
fn zero_copy_example(buffer: &[u8]) {
// 直接访问缓冲区数据,无需复制
let monster = flatbuffers::get_root::<Monster>(buffer);
println!("Direct access - HP: {}", monster.hp());
}
嵌套数据结构
fn nested_data_example() {
let mut builder = flatbuffers::FlatBufferBuilder::new();
// 创建嵌套的装备数据
let weapon1 = create_weapon(&mut builder, "Axe", 75);
let weapon2 = create_weapon(&mut builder, "Bow", 45);
let weapons = builder.create_vector(&[weapon1, weapon2]);
// ... 其余创建逻辑
}
完整示例代码
// 完整示例:创建和读取Monster数据
use flatbuffers;
use my_game::sample::{Monster, MonsterArgs, Weapon, WeaponArgs, Color};
// 创建武器的辅助函数
fn create_weapon(builder: &mut flatbuffers::FlatBufferBuilder, name: &str, damage: i16) -> flatbuffers::WIPOffset<Weapon> {
let weapon_name = builder.create_string(name);
Weapon::create(builder, &WeaponArgs {
name: Some(weapon_name),
damage: damage,
})
}
// 序列化函数
fn serialize_monster() -> Vec<u8> {
let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024);
// 创建多个武器
let sword = create_weapon(&mut builder, "Sword", 50);
let axe = create_weapon(&mut builder, "Axe", 75);
let weapons = builder.create_vector(&[sword, axe]);
// 创建怪物
let name = builder.create_string("Dragon");
let monster = Monster::create(&mut builder, &MonsterArgs {
pos: None,
mana: 300,
hp: 500,
name: Some(name),
color: Color::Red,
weapons: Some(weapons),
equipped: None,
});
builder.finish(monster, None);
builder.finished_data().to_vec()
}
// 反序列化函数
fn deserialize_monster(buffer: &[u8]) {
match flatbuffers::root::<Monster>(buffer) {
Ok(monster) => {
println!("=== 怪物信息 ===");
println!("名称: {}", monster.name().unwrap_or("未知"));
println!("生命值: {}", monster.hp());
println!("魔法值: {}", monster.mana());
println!("颜色: {:?}", monster.color());
if let Some(weapons) = monster.weapons() {
println!("\n=== 武器列表 ===");
for (i, weapon) in weapons.iter().enumerate() {
println!("武器{}: {} (伤害: {})",
i + 1,
weapon.name().unwrap_or("未知"),
weapon.damage());
}
}
}
Err(e) => println!("反序列化失败: {}", e),
}
}
// 主函数
fn main() {
// 序列化数据
let serialized_data = serialize_monster();
println!("序列化完成,数据大小: {} 字节", serialized_data.len());
// 反序列化并显示数据
deserialize_monster(&serialized_data);
// 零拷贝访问演示
println!("\n=== 零拷贝访问 ===");
if let Ok(monster) = flatbuffers::root::<Monster>(&serialized_data) {
println!("直接访问 - 生命值: {}", monster.hp());
println!("直接访问 - 魔法值: {}", monster.mana());
}
}
性能优化技巧
- 预分配缓冲区:根据数据大小预估并预分配足够的缓冲区空间
- 重用构建器:在循环中重用FlatBufferBuilder实例
- 使用内联数据:对于小型固定大小的数据,考虑使用内联存储
注意事项
- FlatBuffers数据一旦创建就不可变
- Schema更改需要重新生成代码
- 确保使用相同版本的flatc编译器和库
- 大端序和小端序系统需要注意字节序问题
总结
flatc-rust为Rust开发者提供了高效的零拷贝序列化解决方案,特别适合高性能应用和游戏开发场景。通过编译时生成的类型安全代码,既保证了性能又提供了良好的开发体验。