Replies: 6 comments 6 replies
-
I agree on the points you have listed. Actually there's more places where FlatBuffers excels Protobuf:
So the thing is, we will reconsider Protobuf and perhaps switch to FlatBuffers, if the support is equally enough on both sides of Dart and Rust. We will need to do some experiments before this change. Bincode doesn't produced Dart code, so it looks like it would be hard to use here. Thank you for starting this discussion :) |
Beta Was this translation helpful? Give feedback.
-
Looks like FlatBuffers also has its own tedious part when writing code: extern crate flatbuffers;
use person_generated::MyGame::Example::Person;
use flatbuffers::{FlatBufferBuilder, WIPOffset};
fn main() {
let mut builder = FlatBufferBuilder::new();
// Create a Person object
let name = builder.create_string("John");
let age = 30;
let person = Person::create(&mut builder, &Person::new(&mut builder, &name, age));
// Finish building the buffer
builder.finish(person, None);
// Access the FlatBuffer data as bytes
let buffer = builder.finished_data();
// Deserialize the data
let parsed_person = flatbuffers::get_root::<Person>(&buffer);
// Access the fields
let parsed_name = parsed_person.name();
let parsed_age = parsed_person.age();
println!("Name: {}, Age: {}", parsed_name, parsed_age);
} |
Beta Was this translation helpful? Give feedback.
-
Non-tedious example code in Rust: // Create the monster using the `Monster::create` helper function. This
// function accepts a `MonsterArgs` struct, which supplies all of the data
// needed to build a `Monster`. To supply empty/default fields, just use the
// Rust built-in `Default::default()` function, as demonstrated below.
let orc = Monster::create(&mut builder, &MonsterArgs{
pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)),
mana: 150,
hp: 80,
name: Some(name),
inventory: Some(inventory),
color: Color::Red,
weapons: Some(weapons),
equipped_type: Equipment::Weapon,
equipped: Some(axe.as_union_value()),
//path: Some(path),
..Default::default()
}); FlatBuffers does need things like builders for fields with non-fixed size: let name = builder.create_string("Orc");
let weapons = builder.create_vector(&[sword, axe]); |
Beta Was this translation helpful? Give feedback.
-
Non-tedious example code in Dart: // Create the builder here so we can use it for both weapons and equipped
// the actual data will only be written to the buffer once.
var axe = my_game.WeaponObjectBuilder(name: 'Axe', damage: 5);
var monsterBuilder = my_game.MonsterObjectBuilder(
pos: my_game.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
mana: 150,
hp: 300,
name: 'Orc',
inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
color: my_game.Color.Red,
weapons: [my_game.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
equippedType: my_game.EquipmentTypeId.Weapon,
equipped: axe,
); |
Beta Was this translation helpful? Give feedback.
-
I've implemented FlatBuffers in a separate branch in both Dart and Rust, but the cleanest code possible was this. FlatBuffers might be more memory-efficient but the code readability is much lower. |
Beta Was this translation helpful? Give feedback.
-
I have done very similar marshalling between Rust and Flutter (and Typescript) myself and also initially went with Protobuf. However it turned out to be a bad choice for a few reasons:
Option<T>
.I ended up writing my own serialisation format. Even had a VSCode extension for it. It was pretty sweet. Unfortunately for a company I used to work for so I don't have access to it anymore.
The schema was a subset of Rust to allow struct definitions, and some very minor modifications to allow function calls with streaming input and output arguments. Serialisation used Bincode.
Maybe writing your own entire schema format and RPC system is a bit much but I would still consider finding a format that has required fields and doesn't require field ordinals.
FlatBuffers looks far more suitable and already supports Dart and Rust. I haven't used it though.
Beta Was this translation helpful? Give feedback.
All reactions