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”

文档

docs.rs/flatc-rust/0.2.0

代码库

github.com/frol/flatc-rust

所有者

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());
}

1 回复

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());
    }
}

性能优化技巧

  1. 预分配缓冲区:根据数据大小预估并预分配足够的缓冲区空间
  2. 重用构建器:在循环中重用FlatBufferBuilder实例
  3. 使用内联数据:对于小型固定大小的数据,考虑使用内联存储

注意事项

  • FlatBuffers数据一旦创建就不可变
  • Schema更改需要重新生成代码
  • 确保使用相同版本的flatc编译器和库
  • 大端序和小端序系统需要注意字节序问题

总结

flatc-rust为Rust开发者提供了高效的零拷贝序列化解决方案,特别适合高性能应用和游戏开发场景。通过编译时生成的类型安全代码,既保证了性能又提供了良好的开发体验。

回到顶部