diff --git a/docs/source/tutorial.md b/docs/source/tutorial.md index 0f06d9a2d..cfa0b1c99 100644 --- a/docs/source/tutorial.md +++ b/docs/source/tutorial.md @@ -290,7 +290,8 @@ generally involves two things: // Convenient namespace macro to manage long namespace prefix. #undef ns - #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. + // Specified in the schema. + #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // A helper to simplify creating vectors from C-arrays. #define c_vec_len(V) (sizeof(V)/sizeof((V)[0])) @@ -337,10 +338,10 @@ generally involves two things: var flatbuffers = require('/js/flatbuffers').flatbuffers; var MyGame = require('./monster_generated').MyGame; // Generated by `flatc`. - //--------------------------------------------------------------------------// + //------------------------------------------------------------------------// - // The following code is for browser-based HTML/JavaScript. Use the above code - // for JavaScript module loaders (e.g. Node.js). + // The following code is for browser-based HTML/JavaScript. Use the above + // code for JavaScript module loaders (e.g. Node.js). // Generated by `flatc`. ``` @@ -377,8 +378,8 @@ generally involves two things: === "PHP" ```php - // It is recommended that your use PSR autoload when using FlatBuffers in PHP. - // Here is an example from `SampleBinary.php`: + // It is recommended that your use PSR autoload when using FlatBuffers in + // PHP. Here is an example from `SampleBinary.php`: function __autoload($class_name) { // The last segment of the class name matches the file name. $class = substr($class_name, strrpos($class_name, "\\") + 1); @@ -494,6 +495,10 @@ for it. The builder will automatically resize the backing buffer when necessary. === "C" ```c + flatcc_builder_t builder, *B; + B = &builder; + // Initialize the builder object. + flatcc_builder_init(B); ``` === "C#" @@ -506,61 +511,85 @@ for it. The builder will automatically resize the backing buffer when necessary. === "Dart" ```dart + // Construct a Builder with 1024 byte backing array. + var builder = new fb.Builder(initialSize: 1024); ``` === "Go" ```go + // Construct a Builder with 1024 byte backing array. + builder := flatbuffers.NewBuilder(1024) ``` === "Java" ```java + // Construct a Builder with 1024 byte backing array. + FlatBufferBuilder builder = new FlatBufferBuilder(1024); ``` === "JavaScript" ```javascript + // Construct a Builder with 1024 byte backing array. + var builder = new flatbuffers.Builder(1024); ``` === "Kotlin" ```kotlin + // Construct a Builder with 1024 byte backing array. + val builder = FlatBufferBuilder(1024) ``` === "Lobster" ```lobster + // Construct a Builder with 1024 byte backing array. + let builder = flatbuffers_builder {} ``` === "Lua" ```lua + -- Construct a Builder with 1024 byte backing array. + local builder = flatbuffers.Builder(1024) ``` === "PHP" ```php + // Construct a Builder with 1024 byte backing array. + $builder = new Google\FlatBuffers\FlatbufferBuilder(1024); ``` === "Python" ```py + # Construct a Builder with 1024 byte backing array. + builder = flatbuffers.Builder(1024) ``` === "Rust" ```rust + // Construct a Builder with 1024 byte backing array. + let mut builder = flatbuffers::FlatBufferBuilder::with_capacity(1024); ``` === "Swift" ```swift + // Construct a Builder with 1024 byte backing array. + let builder = FlatBufferBuilder(initialSize: 1024) ``` === "TypeScript" ```ts + // Construct a Builder with 1024 byte backing array. + let builder = new flatbuffers.Builder(1024); ``` Once a Builder is available, data can be serialized to it via the Builder APIs @@ -570,7 +599,8 @@ and the generated code. In this tutorial, we are building `Monsters` and `Weapons` for a computer game. A `Weapon` is represented by a flatbuffer `table` with some fields. One field is -the `name` field, which is type `string`. +the `name` field, which is type `string` and the other `damage` field is a +numerical scalar. ```c title="monster.fbs" linenums="28" table Weapon { @@ -583,7 +613,9 @@ table Weapon { Since `string` is a reference type, we first need to serialize it before assigning it to the `name` field of the `Weapon` table. This is done through the -Builder `CreateString` method: +Builder `CreateString` method. + +Let's serialize two weapon strings. === "C++" @@ -592,9 +624,16 @@ Builder `CreateString` method: flatbuffers::Offset weapon_two_name = builder.CreateString("Axe"); ``` + `flatbuffers::Offset<>` is a just a "typed" integer tied to a particular + type. It helps make the numerical offset more strongly typed. + === "C" ```c + flatbuffers_string_ref_t weapon_one_name + = flatbuffers_string_create_str(B, "Sword"); + flatbuffers_string_ref_t weapon_two_name + = flatbuffers_string_create_str(B, "Axe"); ``` === "C#" @@ -607,61 +646,85 @@ Builder `CreateString` method: === "Dart" ```dart + final int weaponOneName = builder.writeString("Sword"); + final int weaponTwoName = builder.writeString("Axe"); ``` === "Go" ```go + weaponOne := builder.CreateString("Sword") + weaponTwo := builder.CreateString("Axe") ``` === "Java" ```java + int weaponOneName = builder.createString("Sword") + int weaponTwoName = builder.createString("Axe"); ``` === "JavaScript" ```javascript + var weaponOne = builder.createString('Sword'); + var weaponTwo = builder.createString('Axe'); ``` === "Kotlin" ```kotlin + val weaponOneName = builder.createString("Sword") + val weaponTwoName = builder.createString("Axe") ``` === "Lobster" ```lobster + let weapon_one = builder.CreateString("Sword") + let weapon_two = builder.CreateString("Axe") ``` === "Lua" ```lua + local weaponOne = builder:CreateString("Sword") + local weaponTwo = builder:CreateString("Axe") ``` === "PHP" ```php + $weapon_one_name = $builder->createString("Sword") + $weapon_two_name = $builder->createString("Axe"); ``` === "Python" ```py + weapon_one = builder.CreateString('Sword') + weapon_two = builder.CreateString('Axe') ``` === "Rust" ```rust + let weapon_one_name = builder.create_string("Sword"); + let weapon_two_name = builder.create_string("Axe"); ``` === "Swift" ```swift + let weapon1Name = builder.create(string: "Sword") + let weapon2Name = builder.create(string: "Axe") ``` === "TypeScript" - ```ts + ```ts + let weaponOne = builder.createString('Sword'); + let weaponTwo = builder.createString('Axe'); ``` @@ -672,10 +735,10 @@ the buffer. #### Tables -Now that we have some names serialized, we can serialize `Weapons`. Here we will -use one of the generated helper functions that was emitted by `flatc`. The -`CreateWeapon` function takes in the Builder object, as well as the offset to -the weapon's name and a numerical value for the damage field. +Now that we have some names serialized, we can serialize the `Weapon` tables. +Here we will use one of the generated helper functions that was emitted by +`flatc`. The `CreateWeapon` function takes in the Builder object, as well as the +offset to the weapon's name and a numerical value for the damage field. === "C++" @@ -683,7 +746,8 @@ the weapon's name and a numerical value for the damage field. short weapon_one_damage = 3; short weapon_two_damage = 5; - // Use the `CreateWeapon()` shortcut to create Weapons with all the fields set. + // Use the `CreateWeapon()` shortcut to create Weapons with all the fields + // set. flatbuffers::Offset sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage); flatbuffers::Offset axe = @@ -693,6 +757,13 @@ the weapon's name and a numerical value for the damage field. === "C" ```c + uint16_t weapon_one_damage = 3; + uint16_t weapon_two_damage = 5; + + ns(Weapon_ref_t) sword + = ns(Weapon_create(B, weapon_one_name, weapon_one_damage)); + ns(Weapon_ref_t) axe + = ns(Weapon_create(B, weapon_two_name, weapon_two_damage)); ``` === "C#" @@ -701,7 +772,8 @@ the weapon's name and a numerical value for the damage field. short weaponOneDamage = 3; short weaponTwoDamage = 5; - // Use the `CreateWeapon()` helper function to create the weapons, since we set every field. + // Use the `CreateWeapon()` helper function to create the weapons, since we + // set every field. Offset sword = Weapon.CreateWeapon(builder, weaponOneName, weaponOneDamage); Offset axe = @@ -711,61 +783,193 @@ the weapon's name and a numerical value for the damage field. === "Dart" ```dart + final int weaponOneDamage = 3; + final int weaponTwoDamage = 5; + + final swordBuilder = new myGame.WeaponBuilder(builder) + ..begin() + ..addNameOffset(weaponOneName) + ..addDamage(weaponOneDamage); + final int sword = swordBuilder.finish(); + + final axeBuilder = new myGame.WeaponBuilder(builder) + ..begin() + ..addNameOffset(weaponTwoName) + ..addDamage(weaponTwoDamage); + final int axe = axeBuilder.finish(); + ``` + + Note, as an alternative, the previous steps can be combined using the + generative Builder classes. + + ```dart + final myGame.WeaponBuilder sword = new myGame.WeaponObjectBuilder( + name: "Sword", + damage: 3, + ); + + final myGame.WeaponBuilder axe = new myGame.WeaponObjectBuilder( + name: "Axe", + damage: 5, + ); ``` === "Go" ```go + // Create the first `Weapon` ("Sword"). + sample.WeaponStart(builder) + sample.WeaponAddName(builder, weaponOne) + sample.WeaponAddDamage(builder, 3) + sword := sample.WeaponEnd(builder) + + // Create the second `Weapon` ("Axe"). + sample.WeaponStart(builder) + sample.WeaponAddName(builder, weaponTwo) + sample.WeaponAddDamage(builder, 5) + axe := sample.WeaponEnd(builder) ``` === "Java" ```java + short weaponOneDamage = 3; + short weaponTwoDamage = 5; + + // Use the `createWeapon()` helper function to create the weapons, since we + // set every field. + int sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage); + int axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage); ``` === "JavaScript" ```javascript + // Create the first `Weapon` ('Sword'). + MyGame.Sample.Weapon.startWeapon(builder); + MyGame.Sample.Weapon.addName(builder, weaponOne); + MyGame.Sample.Weapon.addDamage(builder, 3); + var sword = MyGame.Sample.Weapon.endWeapon(builder); + + // Create the second `Weapon` ('Axe'). + MyGame.Sample.Weapon.startWeapon(builder); + MyGame.Sample.Weapon.addName(builder, weaponTwo); + MyGame.Sample.Weapon.addDamage(builder, 5); + var axe = MyGame.Sample.Weapon.endWeapon(builder); ``` === "Kotlin" ```kotlin + val weaponOneDamage: Short = 3; + val weaponTwoDamage: Short = 5; + + // Use the `createWeapon()` helper function to create the weapons, since we + // set every field. + val sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage) + val axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage) ``` === "Lobster" ```lobster + let sword = MyGame_Sample_WeaponBuilder { b } + .start() + .add_name(weapon_one) + .add_damage(3) + .end() + + let axe = MyGame_Sample_WeaponBuilder { b } + .start() + .add_name(weapon_two) + .add_damage(5) + .end() ``` === "Lua" ```lua + -- Create the first 'Weapon' + weapon.Start(builder) + weapon.AddName(builder, weaponOne) + weapon.AddDamage(builder, 3) + local sword = weapon.End(builder) + + -- Create the second 'Weapon' + weapon.Start(builder) + weapon.AddName(builder, weaponTwo) + weapon.AddDamage(builder, 5) + local axe = weapon.End(builder) ``` === "PHP" ```php + $sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one_name, 3); + $axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two_name, 5); ``` === "Python" ```py + # Create the first `Weapon` ('Sword'). + MyGame.Sample.Weapon.Start(builder) + MyGame.Sample.Weapon.AddName(builder, weapon_one) + MyGame.Sample.Weapon.AddDamage(builder, 3) + sword = MyGame.Sample.Weapon.End(builder) + + # Create the second `Weapon` ('Axe'). + MyGame.Sample.Weapon.Start(builder) + MyGame.Sample.Weapon.AddName(builder, weapon_two) + MyGame.Sample.Weapon.AddDamage(builder, 5) + axe = MyGame.Sample.Weapon.End(builder) ``` === "Rust" ```rust + // Use the `Weapon::create` shortcut to create Weapons with named field + // arguments. + let sword = Weapon::create(&mut builder, &WeaponArgs{ + name: Some(weapon_one_name), + damage: 3, + }); + let axe = Weapon::create(&mut builder, &WeaponArgs{ + name: Some(weapon_two_name), + damage: 5, + }); ``` === "Swift" ```swift + // start creating the weapon by calling startWeapon + let weapon1Start = Weapon.startWeapon(&builder) + Weapon.add(name: weapon1Name, &builder) + Weapon.add(damage: 3, &builder) + // end the object by passing the start point for the weapon 1 + let sword = Weapon.endWeapon(&builder, start: weapon1Start) + + let weapon2Start = Weapon.startWeapon(&builder) + Weapon.add(name: weapon2Name, &builder) + Weapon.add(damage: 5, &builder) + let axe = Weapon.endWeapon(&builder, start: weapon2Start) ``` === "TypeScript" ```ts + // Create the first `Weapon` ('Sword'). + MyGame.Sample.Weapon.startWeapon(builder); + MyGame.Sample.Weapon.addName(builder, weaponOne); + MyGame.Sample.Weapon.addDamage(builder, 3); + let sword = MyGame.Sample.Weapon.endWeapon(builder); + + // Create the second `Weapon` ('Axe'). + MyGame.Sample.Weapon.startWeapon(builder); + MyGame.Sample.Weapon.addName(builder, weaponTwo); + MyGame.Sample.Weapon.addDamage(builder, 5); + let axe = MyGame.Sample.Weapon.endWeapon(builder); ``` @@ -825,6 +1029,11 @@ The Builder provides multiple ways to create `vectors`. === "C" ```c + // We use the internal builder stack to implement a dynamic vector. + ns(Weapon_vec_start(B)); + ns(Weapon_vec_push(B, sword)); + ns(Weapon_vec_push(B, axe)); + ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B)); ``` === "C#" @@ -843,61 +1052,119 @@ The Builder provides multiple ways to create `vectors`. === "Dart" ```dart + // If using the Builder classes, serialize the `[sword,axe]` + final weapons = builder.writeList([sword, axe]); + + // If using the ObjectBuilders, just create an array from the two `Weapon`s + final List weaps = [sword, axe]; ``` === "Go" ```go + // Create a FlatBuffer vector and prepend the weapons. + // Note: Since we prepend the data, prepend them in reverse order. + sample.MonsterStartWeaponsVector(builder, 2) + builder.PrependUOffsetT(axe) + builder.PrependUOffsetT(sword) + weapons := builder.EndVector(2) ``` === "Java" ```java + // Place the two weapons into an array, and pass it to the + // `createWeaponsVector()` method to create a FlatBuffer vector. + int[] weaps = new int[2]; + weaps[0] = sword; + weaps[1] = axe; + + // Pass the `weaps` array into the `createWeaponsVector()` method to create + // a FlatBuffer vector. + int weapons = Monster.createWeaponsVector(builder, weaps); ``` === "JavaScript" ```javascript + // Create an array from the two `Weapon`s and pass it to the + // `createWeaponsVector()` method to create a FlatBuffer vector. + var weaps = [sword, axe]; + var weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps); ``` === "Kotlin" ```kotlin + // Place the two weapons into an array, and pass it to the + // `createWeaponsVector()` method to create a FlatBuffer vector. + val weaps = intArrayOf(sword, axe) + + // Pass the `weaps` array into the `createWeaponsVector()` method to create + // a FlatBuffer vector. + val weapons = Monster.createWeaponsVector(builder, weaps) ``` === "Lobster" ```lobster + let weapons = builder.MyGame_Sample_MonsterCreateWeaponsVector([sword, axe]) ``` === "Lua" ```lua + -- Create a FlatBuffer vector and prepend the weapons. + -- Note: Since we prepend the data, prepend them in reverse order. + monster.StartWeaponsVector(builder, 2) + builder:PrependUOffsetTRelative(axe) + builder:PrependUOffsetTRelative(sword) + local weapons = builder:EndVector(2) ``` === "PHP" ```php + // Create an array from the two `Weapon`s and pass it to the + // `CreateWeaponsVector()` method to create a FlatBuffer vector. + $weaps = array($sword, $axe); + $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); ``` === "Python" ```py + # Create a FlatBuffer vector and prepend the weapons. + # Note: Since we prepend the data, prepend them in reverse order. + MyGame.Sample.Monster.StartWeaponsVector(builder, 2) + builder.PrependUOffsetTRelative(axe) + builder.PrependUOffsetTRelative(sword) + weapons = builder.EndVector() ``` === "Rust" ```rust + // Create a FlatBuffer `vector` that contains offsets to the sword and axe + // we created above. + let weapons = builder.create_vector(&[sword, axe]); ``` === "Swift" ```swift + // Create a FlatBuffer `vector` that contains offsets to the sword and axe + // we created above. + let weaponsOffset = builder.createVector(ofOffsets: [sword, axe]) ``` === "TypeScript" ```ts + // Create an array from the two `Weapon`s and pass it to the + // `createWeaponsVector()` method to create a FlatBuffer vector. + let weaps = [sword, axe]; + let weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps); ``` @@ -909,39 +1176,34 @@ bit more directly. === "C++" ```c++ - // Construct an array of two `Vec3` structs. - Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) }; - - // Serialize it as a vector of structs. - flatbuffers::Offset> path = - builder.CreateVectorOfStructs(points, 2); - // Create a `vector` representing the inventory of the Orc. Each number // could correspond to an item that can be claimed after he is slain. unsigned char treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; flatbuffers::Offset> inventory = builder.CreateVector(treasure, 10); + // Construct an array of two `Vec3` structs. + Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) }; + + // Serialize it as a vector of structs. + flatbuffers::Offset> path = + builder.CreateVectorOfStructs(points, 2); ``` === "C" ```c + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + flatbuffers_uint8_vec_ref_t inventory; + // `c_vec_len` is the convenience macro we defined earlier. + inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure)); ``` === "C#" ```c# - // Start building a path vector of length 2. - Monster.StartPathVector(fbb, 2); - - // Serialize the individual Vec3 structs - Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f); - Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f); - - // End the vector to get the offset - Offset> path = fbb.EndVector(); - // Create a `vector` representing the inventory of the Orc. Each number // could correspond to an item that can be claimed after he is slain. // Note: Since we prepend the bytes, this loop iterates in reverse order. @@ -951,72 +1213,200 @@ bit more directly. builder.AddByte((byte)i); } Offset> inventory = builder.EndVector(); + + // Start building a path vector of length 2. + Monster.StartPathVector(fbb, 2); + + // Serialize the individual Vec3 structs + Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f); + Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f); + + // End the vector to get the offset + Offset> path = fbb.EndVector(); ``` === "Dart" ```dart + // Create a list representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + final List treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + final inventory = builder.writeListUint8(treasure); + + // Using the Builder classes, you can write a list of structs like so: + // Note that the intended order should be reversed if order is important. + final vec3Builder = new myGame.Vec3Builder(builder); + vec3Builder.finish(4.0, 5.0, 6.0); + vec3Builder.finish(1.0, 2.0, 3.0); + final int path = builder.endStructVector(2); // the length of the vector ``` === "Go" ```go + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + // Note: Since we prepend the bytes, this loop iterates in reverse. + sample.MonsterStartInventoryVector(builder, 10) + for i := 9; i >= 0; i-- { + builder.PrependByte(byte(i)) + } + inv := builder.EndVector(10) + + sample.MonsterStartPathVector(builder, 2) + sample.CreateVec3(builder, 1.0, 2.0, 3.0) + sample.CreateVec3(builder, 4.0, 5.0, 6.0) + path := builder.EndVector(2) ``` === "Java" ```java + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + byte[] treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + int inv = Monster.createInventoryVector(builder, treasure); + + Monster.startPathVector(fbb, 2); + Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f); + Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f); + int path = fbb.endVector(); ``` === "JavaScript" ```javascript + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + var treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + var inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure); + + MyGame.Sample.Monster.startPathVector(builder, 2); + MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0); + MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0); + var path = builder.endVector(); ``` === "Kotlin" ```kotlin + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + val inv = Monster.createInventoryVector(builder, treasure) + + Monster.startPathVector(fbb, 2) + Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f) + Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f) + val path = fbb.endVector() ``` === "Lobster" ```lobster + // Inventory. + let inv = builder.MyGame_Sample_MonsterCreateInventoryVector(map(10): _) + + builder.MyGame_Sample_MonsterStartPathVector(2) + builder.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0) + builder.MyGame_Sample_CreateVec3(4.0, 5.0, 6.0) + let path = builder.EndVector(2) ``` === "Lua" ```lua + -- Create a `vector` representing the inventory of the Orc. Each number + -- could correspond to an item that can be claimed after he is slain. + -- Note: Since we prepend the bytes, this loop iterates in reverse. + monster.StartInventoryVector(builder, 10) + for i=10,1,-1 do + builder:PrependByte(i) + end + local inv = builder:EndVector(10) + + -- Create a FlatBuffer vector and prepend the path locations. + -- Note: Since we prepend the data, prepend them in reverse order. + monster.StartPathVector(builder, 2) + vec3.CreateVec3(builder, 1.0, 2.0, 3.0) + vec3.CreateVec3(builder, 4.0, 5.0, 6.0) + local path = builder:EndVector(2) ``` === "PHP" ```php + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + $treasure = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure); + + \MyGame\Example\Monster::StartPathVector($builder, 2); + \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0); + \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0); + $path = $builder->endVector(); ``` === "Python" ```py + # Create a `vector` representing the inventory of the Orc. Each number + # could correspond to an item that can be claimed after he is slain. + # Note: Since we prepend the bytes, this loop iterates in reverse. + MyGame.Sample.Monster.StartInventoryVector(builder, 10) + for i in reversed(range(0, 10)): + builder.PrependByte(i) + inv = builder.EndVector() + + MyGame.Sample.Monster.StartPathVector(builder, 2) + MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0) + MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0) + path = builder.EndVector() ``` === "Rust" ```rust + // Inventory. + let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + // Create the path vector of Vec3 objects. + let x = Vec3::new(1.0, 2.0, 3.0); + let y = Vec3::new(4.0, 5.0, 6.0); + let path = builder.create_vector(&[x, y]); ``` === "Swift" ```swift + // create inventory + let inventory: [Byte] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + let inventoryOffset = builder.createVector(inventory) + + let path = fbb.createVector(ofStructs: [ + Vec3(x: 1, y: 2, z: 3), + Vec3(x: 4, y: 5, z: 6) + ]) ``` === "TypeScript" ```ts + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + let treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure); + + MyGame.Sample.Monster.startPathVector(builder, 2); + MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0); + MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0); + let path = builder.endVector(); ``` #### Unions -The last non-scalar data for the `Monster` table is the `equipped` `union` +The last non-scalar data field for the `Monster` table is the `equipped` `union` field. For this case, we will reuse an already serialized `Weapon` (the only type in the union), without needing to reserialize it. Union fields implicitly add a hidden `_type` field that stores the type of value stored in the union. @@ -1056,6 +1446,20 @@ the necessary values and Offsets to make a `Monster`. === "C" ```c + // Serialize a name for our monster, called "Orc". + // The _str suffix indicates the source is an ascii-z string. + flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc"); + + // Set his hit points to 300 and his mana to 150. + uint16_t hp = 300; + uint16_t mana = 150; + + // Define an equipment union. `create` calls in C has a single + // argument for unions where C++ has both a type and a data argument. + ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); + ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f }; + ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red), + weapons, equipped, path)); ``` === "C#" @@ -1084,61 +1488,260 @@ the necessary values and Offsets to make a `Monster`. === "Dart" ```dart + // Serialize a name for our monster, called "Orc". + final int name = builder.writeString('Orc'); + + // Using the Builder API: + // Set his hit points to 300 and his mana to 150. + final int hp = 300; + final int mana = 150; + + final monster = new myGame.MonsterBuilder(builder) + ..begin() + ..addNameOffset(name) + ..addInventoryOffset(inventory) + ..addWeaponsOffset(weapons) + ..addEquippedType(myGame.EquipmentTypeId.Weapon) + ..addEquippedOffset(axe) + ..addHp(hp) + ..addMana(mana) + ..addPos(vec3Builder.finish(1.0, 2.0, 3.0)) + ..addPathOffset(path) + ..addColor(myGame.Color.Red); + + final int orc = monster.finish(); ``` === "Go" ```go + // Serialize a name for our monster, called "Orc". + name := builder.CreateString("Orc") + + // Create our monster using `MonsterStart()` and `MonsterEnd()`. + sample.MonsterStart(builder) + sample.MonsterAddPos(builder, sample.CreateVec3(builder, 1.0, 2.0, 3.0)) + sample.MonsterAddHp(builder, 300) + sample.MonsterAddName(builder, name) + sample.MonsterAddInventory(builder, inv) + sample.MonsterAddColor(builder, sample.ColorRed) + sample.MonsterAddWeapons(builder, weapons) + sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) + sample.MonsterAddEquipped(builder, axe) + sample.MonsterAddPath(builder, path) + orc := sample.MonsterEnd(builder) ``` === "Java" ```java + // Serialize a name for our monster, called "Orc". + int name = builder.createString("Orc"); + + // Create our monster using `startMonster()` and `endMonster()`. + Monster.startMonster(builder); + Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)); + Monster.addName(builder, name); + Monster.addColor(builder, Color.Red); + Monster.addHp(builder, (short)300); + Monster.addInventory(builder, inv); + Monster.addWeapons(builder, weapons); + Monster.addEquippedType(builder, Equipment.Weapon); + Monster.addEquipped(builder, axe); + Monster.addPath(builder, path); + int orc = Monster.endMonster(builder); ``` === "JavaScript" ```javascript + // Serialize a name for our monster, called 'Orc'. + var name = builder.createString('Orc'); + + // Create our monster by using `startMonster()` and `endMonster()`. + MyGame.Sample.Monster.startMonster(builder); + MyGame.Sample.Monster.addPos(builder, + MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0)); + MyGame.Sample.Monster.addHp(builder, 300); + MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red) + MyGame.Sample.Monster.addName(builder, name); + MyGame.Sample.Monster.addInventory(builder, inv); + MyGame.Sample.Monster.addWeapons(builder, weapons); + MyGame.Sample.Monster.addEquippedType(builder, + MyGame.Sample.Equipment.Weapon); + MyGame.Sample.Monster.addEquipped(builder, axe); + MyGame.Sample.Monster.addPath(builder, path); + var orc = MyGame.Sample.Monster.endMonster(builder); ``` === "Kotlin" ```kotlin + // Serialize a name for our monster, called "Orc". + val name = builder.createString("Orc") + + // Create our monster using `startMonster()` and `endMonster()`. + Monster.startMonster(builder) + Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)) + Monster.addName(builder, name) + Monster.addColor(builder, Color.Red) + Monster.addHp(builder, 300.toShort()) + Monster.addInventory(builder, inv) + Monster.addWeapons(builder, weapons) + Monster.addEquippedType(builder, Equipment.Weapon) + Monster.addEquipped(builder, axe) + Monster.addPath(builder, path) + val orc = Monster.endMonster(builder) ``` === "Lobster" ```lobster + // Name of the monster. + let name = builder.CreateString("Orc") + + let orc = MyGame_Sample_MonsterBuilder { b } + .start() + .add_pos(b.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0)) + .add_hp(300) + .add_name(name) + .add_inventory(inv) + .add_color(MyGame_Sample_Color_Red) + .add_weapons(weapons) + .add_equipped_type(MyGame_Sample_Equipment_Weapon) + .add_equipped(weapon_offsets[1]) + .add_path(path) + .end() ``` === "Lua" ```lua + -- Serialize a name for our monster, called 'orc' + local name = builder:CreateString("Orc") + + -- Create our monster by using Start() andEnd() + monster.Start(builder) + monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) + monster.AddHp(builder, 300) + monster.AddName(builder, name) + monster.AddInventory(builder, inv) + monster.AddColor(builder, color.Red) + monster.AddWeapons(builder, weapons) + monster.AddEquippedType(builder, equipment.Weapon) + monster.AddEquipped(builder, axe) + monster.AddPath(builder, path) + local orc = monster.End(builder) ``` === "PHP" ```php + // Serialize a name for our monster, called "Orc". + $name = $builder->createString("Orc"); + + // Create our monster by using `StartMonster()` and `EndMonster()`. + \MyGame\Sample\Monster::StartMonster($builder); + \MyGame\Sample\Monster::AddPos($builder, + \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0)); + \MyGame\Sample\Monster::AddHp($builder, 300); + \MyGame\Sample\Monster::AddName($builder, $name); + \MyGame\Sample\Monster::AddInventory($builder, $inv); + \MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red); + \MyGame\Sample\Monster::AddWeapons($builder, $weapons); + \MyGame\Sample\Monster::AddEquippedType($builder, + \MyGame\Sample\Equipment::Weapon); + \MyGame\Sample\Monster::AddEquipped($builder, $axe); + \MyGame\Sample\Monster::AddPath($builder, $path); + $orc = \MyGame\Sample\Monster::EndMonster($builder); ``` === "Python" ```py + # Serialize a name for our monster, called "Orc". + name = builder.CreateString("Orc") + + # Create our monster by using `Monster.Start()` and `Monster.End()`. + MyGame.Sample.Monster.Start(builder) + MyGame.Sample.Monster.AddPos(builder, + MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) + MyGame.Sample.Monster.AddHp(builder, 300) + MyGame.Sample.Monster.AddName(builder, name) + MyGame.Sample.Monster.AddInventory(builder, inv) + MyGame.Sample.Monster.AddColor(builder, + MyGame.Sample.Color.Color().Red) + MyGame.Sample.Monster.AddWeapons(builder, weapons) + MyGame.Sample.Monster.AddEquippedType( + builder, MyGame.Sample.Equipment.Equipment().Weapon) + MyGame.Sample.Monster.AddEquipped(builder, axe) + MyGame.Sample.Monster.AddPath(builder, path) + orc = MyGame.Sample.Monster.End(builder) ``` === "Rust" ```rust + // Name of the Monster. + let name = builder.create_string("Orc"); + + // 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() + }); ``` === "Swift" ```swift + // Name of the Monster. + let name = builder.create(string: "Orc") + + let orc = Monster.createMonster( + &builder, + pos: MyGame_Sample_Vec3(x: 1, y: 2, z: 3), + hp: 300, + nameOffset: name, + inventoryVectorOffset: inventoryOffset, + color: .red, + weaponsVectorOffset: weaponsOffset, + equippedType: .weapon, + equippedOffset: axe) ``` === "TypeScript" ```ts + // Serialize a name for our monster, called 'Orc'. + let name = builder.createString('Orc'); + + // Create our monster by using `startMonster()` and `endMonster()`. + MyGame.Sample.Monster.startMonster(builder); + MyGame.Sample.Monster.addPos(builder, + MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0)); + MyGame.Sample.Monster.addHp(builder, 300); + MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red) + MyGame.Sample.Monster.addName(builder, name); + MyGame.Sample.Monster.addInventory(builder, inv); + MyGame.Sample.Monster.addWeapons(builder, weapons); + MyGame.Sample.Monster.addEquippedType(builder, + MyGame.Sample.Equipment.Weapon); + MyGame.Sample.Monster.addEquipped(builder, axe); + MyGame.Sample.Monster.addPath(builder, path); + let orc = MyGame.Sample.Monster.endMonster(builder); ``` @@ -1163,6 +1766,8 @@ deserializing the buffer later. === "C" ```c + // Because we used `Monster_create_as_root`, we do not need a `finish` call + // in C. ``` === "C#" @@ -1176,61 +1781,86 @@ deserializing the buffer later. === "Dart" ```dart + // Call `finish()` to instruct the builder that this monster is complete. + // See the next code section, as in Dart `finish` will also return the byte + // array. ``` === "Go" ```go + // Call `Finish()` to instruct the builder that this monster is complete. + builder.Finish(orc) ``` === "Java" ```java + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc); ``` === "JavaScript" ```javascript + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc); ``` === "Kotlin" ```kotlin + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc) ; ``` === "Lobster" ```lobster + // Call `Finish()` to instruct the builder that this monster is complete. + builder.Finish(orc) ``` === "Lua" ```lua + -- Call 'Finish()' to instruct the builder that this monster is complete. + builder:Finish(orc) ``` === "PHP" ```php + // Call `finish()` to instruct the builder that this monster is complete. + $builder->finish($orc); ``` === "Python" ```py + # Call `Finish()` to instruct the builder that this monster is complete. + builder.Finish(orc) ``` === "Rust" ```rust + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc, None); ``` === "Swift" ```swift + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(offset: orc) ``` === "TypeScript" ```ts + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc); ``` @@ -1255,6 +1885,25 @@ like so: === "C" ```c + uint8_t *buf; + size_t size; + + // Allocate and extract a readable buffer from internal builder heap. + // The returned buffer must be deallocated using `free`. + // NOTE: Finalizing the buffer does NOT change the builder, it + // just creates a snapshot of the builder content. + buf = flatcc_builder_finalize_buffer(B, &size); + // use buf + free(buf); + + // Optionally reset builder to reuse builder without deallocating + // internal stack and heap. + flatcc_builder_reset(B); + // build next buffer. + // ... + + // Cleanup. + flatcc_builder_clear(B); ``` === "C#" @@ -1274,61 +1923,101 @@ like so: === "Dart" ```dart + final Uint8List buf = builder.finish(orc); ``` === "Go" ```go + // This must be called after `Finish()`. + buf := builder.FinishedBytes() // Of type `byte[]`. ``` === "Java" ```java + // This must be called after `finish()`. + java.nio.ByteBuffer buf = builder.dataBuffer(); + // The data in this ByteBuffer does NOT start at 0, but at buf.position(). + // The number of bytes is buf.remaining(). + + // Alternatively this copies the above data out of the ByteBuffer for you: + byte[] buf = builder.sizedByteArray(); ``` === "JavaScript" ```javascript + // This must be called after `finish()`. + var buf = builder.asUint8Array(); // Of type `Uint8Array`. ``` === "Kotlin" ```kotlin + // This must be called after `finish()`. + val buf = builder.dataBuffer() + // The data in this ByteBuffer does NOT start at 0, but at buf.position(). + // The number of bytes is buf.remaining(). + + // Alternatively this copies the above data out of the ByteBuffer for you: + val buf = builder.sizedByteArray() ``` === "Lobster" ```lobster + // This must be called after `Finish()`. + let buf = builder.SizedCopy() // Of type `string`. ``` === "Lua" ```lua + local bufAsString = builder:Output() ``` === "PHP" ```php + // This must be called after `finish()`. + $buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer` + // The data in this ByteBuffer does NOT start at 0, but at + // buf->getPosition(). + // The end of the data is marked by buf->capacity(), so the size is + // buf->capacity() - buf->getPosition(). ``` === "Python" ```py + # This must be called after `Finish()`. + buf = builder.Output() // Of type `bytearray`. ``` === "Rust" ```rust + // This must be called after `finish()`. + // `finished_data` returns a byte slice. + let buf = builder.finished_data(); // Of type `&[u8]` ``` === "Swift" ```swift + // This must be called after `finish()`. + // `sizedByteArray` returns the finished buf of type [UInt8]. + let buf = builder.sizedByteArray + // or you can use to get an object of type Data + let bufData = ByteBuffer(data: builder.data) ``` === "TypeScript" ```ts + // This must be called after `finish()`. + let buf = builder.asUint8Array(); // Of type `Uint8Array`. ``` @@ -1372,6 +2061,12 @@ functions to get the root object given the buffer. === "C" ```c + // Note that we use the `table_t` suffix when reading a table object + // as opposed to the `ref_t` suffix used during the construction of + // the buffer. + ns(Monster_table_t) monster = ns(Monster_as_root(buffer)); + + // Note: root object pointers are NOT the same as the `buffer` pointer. ``` === "C#" @@ -1386,61 +2081,135 @@ functions to get the root object given the buffer. === "Dart" ```dart + List data = ... // the data, e.g. from file or network + // A generated factory constructor that will read the data. + myGame.Monster monster = new myGame.Monster(data); ``` === "Go" ```go + var buf []byte = /* the data you just read */ + + // Get an accessor to the root object inside the buffer. + monster := sample.GetRootAsMonster(buf, 0) + + // Note: We use `0` for the offset here, which is typical for most buffers + // you would read. If you wanted to read from `builder.Bytes` directly, you + // would need to pass in the offset of `builder.Head()`, as the builder + // constructs the buffer backwards, so may not start at offset 0. ``` === "Java" ```java + byte[] bytes = /* the data you just read */ + java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(bytes); + + // Get an accessor to the root object inside the buffer. + Monster monster = Monster.getRootAsMonster(buf); ``` === "JavaScript" ```javascript + // the data you just read, as a `Uint8Array` + // Note that the example here uses `readFileSync` from the built-in `fs` + // module, but other methods for accessing the file contents will also work. + var bytes = new Uint8Array(readFileSync('./monsterdata.bin')); + + var buf = new flatbuffers.ByteBuffer(bytes); + + // Get an accessor to the root object inside the buffer. + var monster = MyGame.Sample.Monster.getRootAsMonster(buf); ``` === "Kotlin" ```kotlin + val bytes = /* the data you just read */ + val buf = java.nio.ByteBuffer.wrap(bytes) + + // Get an accessor to the root object inside the buffer. + Monster monster = Monster.getRootAsMonster(buf) ``` === "Lobster" ```lobster + buf = /* the data you just read, in a string */ + + // Get an accessor to the root object inside the buffer. + let monster = MyGame_Sample_GetRootAsMonster(buf) ``` === "Lua" ```lua + local bufAsString = -- The data you just read in + + -- Convert the string representation into binary array Lua structure + local buf = flatbuffers.binaryArray.New(bufAsString) + + -- Get an accessor to the root object insert the buffer + local mon = monster.GetRootAsMonster(buf, 0) ``` === "PHP" ```php + $bytes = /* the data you just read, in a string */ + $buf = Google\FlatBuffers\ByteBuffer::wrap($bytes); + + // Get an accessor to the root object inside the buffer. + $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf); ``` === "Python" ```py + buf = /* the data you just read, in an object of type "bytearray" */ + + # Get an accessor to the root object inside the buffer. + monster = MyGame.Sample.Monster.Monster.GetRootAs(buf, 0) + + # Note: We use `0` for the offset here, which is typical for most buffers + # you would read. If you wanted to read from the `builder.Bytes` directly, + # you would need to pass in the offset of `builder.Head()`, as the builder + # constructs the buffer backwards, so may not start at offset 0. ``` === "Rust" ```rust + let buf = /* the data you just read, in a &[u8] */ + + // Get an accessor to the root object inside the buffer. + let monster = root_as_monster(buf).unwrap(); ``` === "Swift" ```swift + // create a ByteBuffer(:) from an [UInt8] or Data() + var buf = // Get your data + // Get an accessor to the root object inside the buffer. + let monster: Monster = try! getCheckedRoot(byteBuffer: &byteBuffer) + // let monster: Monster = getRoot(byteBuffer: &byteBuffer) ``` === "TypeScript" ```ts + // the data you just read, as a `Uint8Array`. + // Note that the example here uses `readFileSync` from the built-in `fs` + // module, but other methods for accessing the file contents will also work. + let bytes = new Uint8Array(readFileSync('./monsterdata.bin')); + + let buf = new flatbuffers.ByteBuffer(bytes); + + // Get an accessor to the root object inside the buffer. + let monster = MyGame.Sample.Monster.getRootAsMonster(buf); ``` @@ -1468,6 +2237,9 @@ some of the accessors of the `Monster` root table would look like: === "C" ```c + uint16_t hp = ns(Monster_hp(monster)); + uint16_t mana = ns(Monster_mana(monster)); + flatbuffers_string_t name = ns(Monster_name(monster)); ``` === "C#" @@ -1484,61 +2256,100 @@ some of the accessors of the `Monster` root table would look like: === "Dart" ```dart + // For Dart, unlike other languages support by FlatBuffers, most values + // are available as properties instead of accessor methods. + var hp = monster.hp; + var mana = monster.mana; + var name = monster.name; ``` === "Go" ```go + hp := monster.Hp() + mana := monster.Mana() + name := string(monster.Name()) // Note: `monster.Name()` returns a byte[]. ``` === "Java" ```java + short hp = monster.hp(); + short mana = monster.mana(); + String name = monster.name(); ``` === "JavaScript" ```javascript + var hp = monster.hp(); + var mana = monster.mana(); + var name = monster.name(); ``` === "Kotlin" ```kotlin + val hp = monster.hp + val mana = monster.mana + val name = monster.name ``` === "Lobster" ```lobster + let hp = monster.hp + let mana = monster.mana + let name = monster.name ``` === "Lua" ```lua + local hp = mon:Hp() + local mana = mon:Mana() + local name = mon:Name() ``` === "PHP" ```php + $hp = $monster->getHp(); + $mana = $monster->getMana(); + $name = monster->getName(); ``` === "Python" ```py + hp = monster.Hp() + mana = monster.Mana() + name = monster.Name() ``` === "Rust" ```rust + // Get and test some scalar types from the FlatBuffer. + let hp = monster.hp(); + let mana = monster.mana(); + let name = monster.name(); ``` === "Swift" ```swift + let hp = monster.hp + let mana = monster.mana + let name = monster.name // returns an optional string ``` === "TypeScript" ```ts + let hp = monster.hp(); + let mana = monster.mana(); + let name = monster.name(); ``` @@ -1567,6 +2378,10 @@ For example, accessing the `pos` `struct`, which is type `Vec3` you would do: === "C" ```c + ns(Vec3_struct_t) pos = ns(Monster_pos(monster)); + float x = ns(Vec3_x(pos)); + float y = ns(Vec3_y(pos)); + float z = ns(Vec3_z(pos)); ``` === "C#" @@ -1581,61 +2396,115 @@ For example, accessing the `pos` `struct`, which is type `Vec3` you would do: === "Dart" ```dart + myGame.Vec3 pos = monster.pos; + double x = pos.x; + double y = pos.y; + double z = pos.z; ``` === "Go" ```go + pos := monster.Pos(nil) + x := pos.X() + y := pos.Y() + z := pos.Z() + + // Note: Whenever you access a new object, like in `Pos()`, a new temporary + // accessor object gets created. If your code is very performance sensitive, + // you can pass in a pointer to an existing `Vec3` instead of `nil`. This + // allows you to reuse it across many calls to reduce the amount of object + // allocation/garbage collection. ``` === "Java" ```java + Vec3 pos = monster.pos(); + float x = pos.x(); + float y = pos.y(); + float z = pos.z(); ``` === "JavaScript" ```javascript + var pos = monster.pos(); + var x = pos.x(); + var y = pos.y(); + var z = pos.z(); ``` === "Kotlin" ```kotlin + val pos = monster.pos!! + val x = pos.x + val y = pos.y + val z = pos.z ``` === "Lobster" ```lobster + let pos = monster.pos + let x = pos.x + let y = pos.y + let z = pos.z ``` === "Lua" ```lua + local pos = mon:Pos() + local x = pos:X() + local y = pos:Y() + local z = pos:Z() ``` === "PHP" ```php + $pos = $monster->getPos(); + $x = $pos->getX(); + $y = $pos->getY(); + $z = $pos->getZ(); ``` === "Python" ```py + pos = monster.Pos() + x = pos.X() + y = pos.Y() + z = pos.Z() ``` === "Rust" ```rust + let pos = monster.pos().unwrap(); + let x = pos.x(); + let y = pos.y(); + let z = pos.z(); ``` === "Swift" ```swift + let pos = monster.pos + let x = pos.x + let y = pos.y + let z = pos.z ``` === "TypeScript" ```ts + let pos = monster.pos(); + let x = pos.x(); + let y = pos.y(); + let z = pos.z(); ``` @@ -1657,6 +2526,10 @@ You can also iterate over the length of the vector. === "C" ```c + // If `inv` hasn't been set, it will be null. It is valid get + // the length of null which will be 0, useful for iteration. + flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster)); + size_t inv_len = flatbuffers_uint8_vec_len(inv); ``` === "C#" @@ -1669,61 +2542,96 @@ You can also iterate over the length of the vector. === "Dart" ```dart + int invLength = monster.inventory.length; + var thirdItem = monster.inventory[2]; ``` === "Go" ```go + invLength := monster.InventoryLength() + thirdItem := monster.Inventory(2) ``` === "Java" ```java + int invLength = monster.inventoryLength(); + byte thirdItem = monster.inventory(2); ``` === "JavaScript" ```javascript + var invLength = monster.inventoryLength(); + var thirdItem = monster.inventory(2); ``` === "Kotlin" ```kotlin + val invLength = monster.inventoryLength + val thirdItem = monster.inventory(2)!! ``` === "Lobster" ```lobster + let inv_len = monster.inventory_length + let third_item = monster.inventory(2) ``` === "Lua" ```lua + local invLength = mon:InventoryLength() + local thirdItem = mon:Inventory(3) -- Lua is 1-based ``` === "PHP" ```php + $inv_len = $monster->getInventoryLength(); + $third_item = $monster->getInventory(2); ``` === "Python" ```py + inv_len = monster.InventoryLength() + third_item = monster.Inventory(2) ``` === "Rust" ```rust + // Get and test an element from the `inventory` FlatBuffer's `vector`. + let inv = monster.inventory().unwrap(); + + // Note that this vector is returned as a slice, because direct access for + // this type, a `u8` vector, is safe on all platforms: + let third_item = inv[2]; ``` === "Swift" ```swift + // Get a the count of objects in the vector + let count = monster.inventoryCount + + // get item at index 4 + let object = monster.inventory(at: 4) + + // or you can fetch the entire array + let inv = monster.inventory + // inv[4] should equal object ``` === "TypeScript" ```ts + let invLength = monster.inventoryLength(); + let thirdItem = monster.inventory(2); ``` @@ -1743,6 +2651,13 @@ you need to handle the result as a FlatBuffer table. Here we iterate over the === "C" ```c + ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); + size_t weapons_len = ns(Weapon_vec_len(weapons)); + // We can use `const char *` instead of `flatbuffers_string_t`. + const char *second_weapon_name = + ns(Weapon_name(ns(Weapon_vec_at(weapons, 1)))); + uint16_t second_weapon_damage = + ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1)))); ``` === "C#" @@ -1756,61 +2671,109 @@ you need to handle the result as a FlatBuffer table. Here we iterate over the === "Dart" ```dart + int weaponsLength = monster.weapons.length; + var secondWeaponName = monster.weapons[1].name; + var secondWeaponDamage = monster.Weapons[1].damage; ``` === "Go" ```go + weaponLength := monster.WeaponsLength() + // We need a `sample.Weapon` to pass into `monster.Weapons()` + // to capture the output of the function.k + weapon := new(sample.Weapon) + if monster.Weapons(weapon, 1) { + secondWeaponName := weapon.Name() + secondWeaponDamage := weapon.Damage() + } ``` === "Java" ```java + int weaponsLength = monster.weaponsLength(); + String secondWeaponName = monster.weapons(1).name(); + short secondWeaponDamage = monster.weapons(1).damage(); ``` === "JavaScript" ```javascript + var weaponsLength = monster.weaponsLength(); + var secondWeaponName = monster.weapons(1).name(); + var secondWeaponDamage = monster.weapons(1).damage(); ``` === "Kotlin" ```kotlin + val weaponsLength = monster.weaponsLength + val secondWeaponName = monster.weapons(1)!!.name + val secondWeaponDamage = monster.weapons(1)!!.damage ``` === "Lobster" ```lobster + let weapons_length = monster.weapons_length + let second_weapon_name = monster.weapons(1).name + let second_weapon_damage = monster.weapons(1).damage ``` === "Lua" ```lua + local weaponsLength = mon:WeaponsLength() + local secondWeaponName = mon:Weapon(2):Name() + local secondWeaponDamage = mon:Weapon(2):Damage() ``` === "PHP" ```php + $weapons_len = $monster->getWeaponsLength(); + $second_weapon_name = $monster->getWeapons(1)->getName(); + $second_weapon_damage = $monster->getWeapons(1)->getDamage(); ``` === "Python" ```py + weapons_length = monster.WeaponsLength() + second_weapon_name = monster.Weapons(1).Name() + second_weapon_damage = monster.Weapons(1).Damage() ``` === "Rust" ```rust + // Get and test the `weapons` FlatBuffers's `vector`. + let weps = monster.weapons().unwrap(); + let weps_len = weps.len(); + + let wep2 = weps.get(1); + let second_weapon_name = wep2.name(); + let second_weapon_damage = wep2.damage(); ``` === "Swift" ```swift + // Get the count of weapon objects + let wepsCount = monster.weaponsCount + + let weapon2 = monster.weapons(at: 1) + let weaponName = weapon2.name + let weaponDmg = weapon2.damage ``` === "TypeScript" ```ts + let weaponsLength = monster.weaponsLength(); + let secondWeaponName = monster.weapons(1).name(); + let secondWeaponDamage = monster.weapons(1).damage(); ``` @@ -1839,6 +2802,15 @@ only stores a FlatBuffer `table`). === "C" ```c + // Access union type field. + if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) { + // Cast to appropriate type: + // C allows for silent void pointer assignment, so we need no + // explicit cast. + ns(Weapon_table_t) weapon = ns(Monster_equipped(monster)); + const char *weapon_name = ns(Weapon_name(weapon)); // "Axe" + uint16_t weapon_damage = ns(Weapon_damage(weapon)); // 5 + } ``` === "C#" @@ -1857,59 +2829,173 @@ only stores a FlatBuffer `table`). === "Dart" ```dart + var unionType = monster.equippedType.value; + + if (unionType == myGame.EquipmentTypeId.Weapon.value) { + myGame.Weapon weapon = mon.equipped as myGame.Weapon; + + var weaponName = weapon.name; // "Axe" + var weaponDamage = weapon.damage; // 5 + } ``` === "Go" ```go + // We need a `flatbuffers.Table` to capture the output of the + // `monster.Equipped()` function. + unionTable := new(flatbuffers.Table) + + if monster.Equipped(unionTable) { + unionType := monster.EquippedType() + + if unionType == sample.EquipmentWeapon { + // Create a `sample.Weapon` object that can be initialized with the + // contents of the `flatbuffers.Table` (`unionTable`), which was + // populated by `monster.Equipped()`. + unionWeapon = new(sample.Weapon) + unionWeapon.Init(unionTable.Bytes, unionTable.Pos) + + weaponName = unionWeapon.Name() + weaponDamage = unionWeapon.Damage() + } + } ``` === "Java" ```java + int unionType = monster.EquippedType(); + + if (unionType == Equipment.Weapon) { + // Requires an explicit cast to `Weapon`. + Weapon weapon = (Weapon)monster.equipped(new Weapon()); + + String weaponName = weapon.name(); // "Axe" + short weaponDamage = weapon.damage(); // 5 + } ``` === "JavaScript" ```javascript + var unionType = monster.equippedType(); + + if (unionType == MyGame.Sample.Equipment.Weapon) { + // 'Axe' + var weaponName = monster.equipped(new MyGame.Sample.Weapon()).name(); + // 5 + var weaponDamage = + monster.equipped(new MyGame.Sample.Weapon()).damage(); + } ``` === "Kotlin" ```kotlin + val unionType = monster.EquippedType + + if (unionType == Equipment.Weapon) { + // Requires an explicit cast to `Weapon`. + val weapon = monster.equipped(Weapon()) as Weapon + + val weaponName = weapon.name // "Axe" + val weaponDamage = weapon.damage // 5 + } ``` === "Lobster" ```lobster + union_type = monster.equipped_type + + if union_type == MyGame_Sample_Equipment_Weapon: + // `monster.equipped_as_Weapon` returns a FlatBuffer handle much like + // normal table fields, but this is only valid to call if we already + // know it is the correct type. + let union_weapon = monster.equipped_as_Weapon + + let weapon_name = union_weapon.name // "Axe" + let weapon_damage = union_weapon.damage // 5 ``` === "Lua" ```lua + local unionType = mon:EquippedType() + + if unionType == equipment.Weapon then + local unionWeapon = weapon.New() + unionWeapon:Init(mon:Equipped().bytes, mon:Equipped().pos) + + local weaponName = unionWeapon:Name() -- 'Axe' + local weaponDamage = unionWeapon:Damage() -- 5 + end ``` === "PHP" ```php + $union_type = $monster->getEquippedType(); + + if ($union_type == \MyGame\Sample\Equipment::Weapon) { + // "Axe" + $weapon_name = + $monster->getEquipped(new \MyGame\Sample\Weapon())->getName(); + // 5 + $weapon_damage = + $monster->getEquipped(new \MyGame\Sample\Weapon())->getDamage(); + } ``` === "Python" ```py + union_type = monster.EquippedType() + + if union_type == MyGame.Sample.Equipment.Equipment().Weapon: + # `monster.Equipped()` returns a `flatbuffers.Table`, which can be used + # to initialize a `MyGame.Sample.Weapon.Weapon()`. + union_weapon = MyGame.Sample.Weapon.Weapon() + union_weapon.Init(monster.Equipped().Bytes, monster.Equipped().Pos) + + weapon_name = union_weapon.Name() // 'Axe' + weapon_damage = union_weapon.Damage() // 5 ``` === "Rust" ```rust + // Get and test the `Equipment` union (`equipped` field). + // `equipped_as_weapon` returns a FlatBuffer handle much like normal table + // fields, but this will return `None` if the union is not actually of that + // type. + if monster.equipped_type() == Equipment::Weapon { + let equipped = monster.equipped_as_weapon().unwrap(); + let weapon_name = equipped.name(); + let weapon_damage = equipped.damage(); ``` === "Swift" ```swift + // Get and check if the monster has an equipped item + if monster.equippedType == .weapon { + let _weapon = monster.equipped(type: Weapon.self) + let name = _weapon.name // should return "Axe" + let dmg = _weapon.damage // should return 5 + } ``` === "TypeScript" ```ts + let unionType = monster.equippedType(); + + if (unionType == MyGame.Sample.Equipment.Weapon) { + // 'Axe' + let weaponName = monster.equipped(new MyGame.Sample.Weapon()).name(); + // 5 + let weaponDamage = monster.equipped(new MyGame.Sample.Weapon()).damage(); + } ```