| Tutorial {#flatbuffers_guide_tutorial} |
| ======== |
| |
| ## Overview |
| |
| This tutorial provides a basic example of how to work with |
| [FlatBuffers](@ref flatbuffers_overview). We will step through a simple example |
| application, which shows you how to: |
| |
| - Write a FlatBuffer `schema` file. |
| - Use the `flatc` FlatBuffer compiler. |
| - Parse [JSON](http://json.org) files that conform to a schema into |
| FlatBuffer binary files. |
| - Use the generated files in many of the supported languages (such as C++, |
| Java, and more.) |
| |
| During this example, imagine that you are creating a game where the main |
| character, the hero of the story, needs to slay some `orc`s. We will walk |
| through each step necessary to create this monster type using FlatBuffers. |
| |
| Please select your desired language for our quest: |
| \htmlonly |
| <form> |
| <input type="radio" name="language" value="cpp" checked="checked">C++</input> |
| <input type="radio" name="language" value="java">Java</input> |
| <input type="radio" name="language" value="kotlin">Kotlin</input> |
| <input type="radio" name="language" value="csharp">C#</input> |
| <input type="radio" name="language" value="go">Go</input> |
| <input type="radio" name="language" value="python">Python</input> |
| <input type="radio" name="language" value="javascript">JavaScript</input> |
| <input type="radio" name="language" value="typescript">TypeScript</input> |
| <input type="radio" name="language" value="php">PHP</input> |
| <input type="radio" name="language" value="c">C</input> |
| <input type="radio" name="language" value="dart">Dart</input> |
| <input type="radio" name="language" value="lua">Lua</input> |
| <input type="radio" name="language" value="lobster">Lobster</input> |
| <input type="radio" name="language" value="rust">Rust</input> |
| <input type="radio" name="language" value="swift">Swift</input> |
| </form> |
| \endhtmlonly |
| |
| \htmlonly |
| <script> |
| /** |
| * Check if an HTML `class` attribute is in the language-specific format. |
| * @param {string} languageClass An HTML `class` attribute in the format |
| * 'language-{lang}', where {lang} is a programming language (e.g. 'cpp', |
| * 'java', 'go', etc.). |
| * @return {boolean} Returns `true` if `languageClass` was in the valid |
| * format, prefixed with 'language-'. Otherwise, it returns false. |
| */ |
| function isProgrammingLanguageClassName(languageClass) { |
| if (languageClass && languageClass.substring(0, 9) == 'language-' && |
| languageClass.length > 8) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Given a language-specific HTML `class` attribute, extract the language. |
| * @param {string} languageClass The string name of an HTML `class` attribute, |
| * in the format `language-{lang}`, where {lang} is a programming language |
| * (e.g. 'cpp', 'java', 'go', etc.). |
| * @return {string} Returns a string containing only the {lang} portion of |
| * the class name. If the input was invalid, then it returns `null`. |
| */ |
| function extractProgrammingLanguageFromLanguageClass(languageClass) { |
| if (isProgrammingLanguageClassName(languageClass)) { |
| return languageClass.substring(9); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Hide every code snippet, except for the language that is selected. |
| */ |
| function displayChosenLanguage() { |
| var selection = $('input:checked').val(); |
| |
| var htmlElements = document.getElementsByTagName('*'); |
| for (var i = 0; i < htmlElements.length; i++) { |
| if (isProgrammingLanguageClassName(htmlElements[i].className)) { |
| if (extractProgrammingLanguageFromLanguageClass( |
| htmlElements[i].className).toLowerCase() != selection) { |
| htmlElements[i].style.display = 'none'; |
| } else { |
| htmlElements[i].style.display = 'initial'; |
| } |
| } |
| } |
| } |
| |
| $( document ).ready(displayChosenLanguage); |
| |
| $('input[type=radio]').on("click", displayChosenLanguage); |
| </script> |
| \endhtmlonly |
| |
| ## Where to Find the Example Code |
| |
| Samples demonstating the concepts in this example are located in the source code |
| package, under the `samples` directory. You can browse the samples on GitHub |
| [here](https://github.com/google/flatbuffers/tree/master/samples). |
| |
| <div class="language-c"> |
| *Note: The above does not apply to C, instead [look here](https://github.com/dvidelabs/flatcc/tree/master/samples).* |
| </div> |
| |
| For your chosen language, please cross-reference with: |
| |
| <div class="language-cpp"> |
| [sample_binary.cpp](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.cpp) |
| </div> |
| <div class="language-java"> |
| [SampleBinary.java](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.java) |
| </div> |
| <div class="language-kotlin"> |
| [SampleBinary.kt](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.kt) |
| </div> |
| <div class="language-csharp"> |
| [SampleBinary.cs](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.cs) |
| </div> |
| <div class="language-go"> |
| [sample_binary.go](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.go) |
| </div> |
| <div class="language-python"> |
| [sample_binary.py](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.py) |
| </div> |
| <div class="language-javascript"> |
| [samplebinary.js](https://github.com/google/flatbuffers/blob/master/samples/samplebinary.js) |
| </div> |
| <div class="language-typescript"> |
| <em>none yet</em> |
| </div> |
| <div class="language-php"> |
| [SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php) |
| </div> |
| <div class="language-c"> |
| [monster.c](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c) |
| </div> |
| <div class="language-dart"> |
| [example.dart](https://github.com/google/flatbuffers/blob/master/dart/example/example.dart) |
| </div> |
| <div class="language-lua"> |
| [sample_binary.lua](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.lua) |
| </div> |
| <div class="language-lobster"> |
| [sample_binary.lobster](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.lobster) |
| </div> |
| <div class="language-rust"> |
| [sample_binary.rs](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.rs) |
| </div> |
| <div class="language-swift"> |
| [sample_binary.swift](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.swift) |
| </div> |
| |
| |
| ## Writing the Monsters' FlatBuffer Schema |
| |
| To start working with FlatBuffers, you first need to create a `schema` file, |
| which defines the format for each data structure you wish to serialize. Here is |
| the `schema` that defines the template for our monsters: |
| |
| ~~~ |
| // Example IDL file for our monster's schema. |
| |
| namespace MyGame.Sample; |
| |
| enum Color:byte { Red = 0, Green, Blue = 2 } |
| |
| union Equipment { Weapon } // Optionally add more tables. |
| |
| struct Vec3 { |
| x:float; |
| y:float; |
| z:float; |
| } |
| |
| table Monster { |
| pos:Vec3; // Struct. |
| mana:short = 150; |
| hp:short = 100; |
| name:string; |
| friendly:bool = false (deprecated); |
| inventory:[ubyte]; // Vector of scalars. |
| color:Color = Blue; // Enum. |
| weapons:[Weapon]; // Vector of tables. |
| equipped:Equipment; // Union. |
| path:[Vec3]; // Vector of structs. |
| } |
| |
| table Weapon { |
| name:string; |
| damage:short; |
| } |
| |
| root_type Monster; |
| ~~~ |
| |
| As you can see, the syntax for the `schema` |
| [Interface Definition Language (IDL)](https://en.wikipedia.org/wiki/Interface_description_language) |
| is similar to those of the C family of languages, and other IDL languages. Let's |
| examine each part of this `schema` to determine what it does. |
| |
| The `schema` starts with a `namespace` declaration. This determines the |
| corresponding package/namespace for the generated code. In our example, we have |
| the `Sample` namespace inside of the `MyGame` namespace. |
| |
| Next, we have an `enum` definition. In this example, we have an `enum` of type |
| `byte`, named `Color`. We have three values in this `enum`: `Red`, `Green`, and |
| `Blue`. We specify `Red = 0` and `Blue = 2`, but we do not specify an explicit |
| value for `Green`. Since the behavior of an `enum` is to increment if |
| unspecified, `Green` will receive the implicit value of `1`. |
| |
| Following the `enum` is a `union`. The `union` in this example is not very |
| useful, as it only contains the one `table` (named `Weapon`). If we had created |
| multiple tables that we would want the `union` to be able to reference, we |
| could add more elements to the `union Equipment`. |
| |
| After the `union` comes a `struct Vec3`, which represents a floating point |
| vector with `3` dimensions. We use a `struct` here, over a `table`, because |
| `struct`s are ideal for data structures that will not change, since they use |
| less memory and have faster lookup. |
| |
| The `Monster` table is the main object in our FlatBuffer. This will be used as |
| the template to store our `orc` monster. We specify some default values for |
| fields, such as `mana:short = 150`. All unspecified fields will default to `0` |
| or `NULL`. Another thing to note is the line |
| `friendly:bool = false (deprecated);`. Since you cannot delete fields from a |
| `table` (to support backwards compatability), you can set fields as |
| `deprecated`, which will prevent the generation of accessors for this field in |
| the generated code. Be careful when using `deprecated`, however, as it may break |
| legacy code that used this accessor. |
| |
| The `Weapon` table is a sub-table used within our FlatBuffer. It is |
| used twice: once within the `Monster` table and once within the `Equipment` |
| enum. For our `Monster`, it is used to populate a `vector of tables` via the |
| `weapons` field within our `Monster`. It is also the only table referenced by |
| the `Equipment` union. |
| |
| The last part of the `schema` is the `root_type`. The root type declares what |
| will be the root table for the serialized data. In our case, the root type is |
| our `Monster` table. |
| |
| The scalar types can also use alias type names such as `int16` instead |
| of `short` and `float32` instead of `float`. Thus we could also write |
| the `Weapon` table as: |
| |
| table Weapon { |
| name:string; |
| damage:int16; |
| } |
| |
| #### More Information About Schemas |
| |
| You can find a complete guide to writing `schema` files in the |
| [Writing a schema](@ref flatbuffers_guide_writing_schema) section of the |
| Programmer's Guide. You can also view the formal |
| [Grammar of the schema language](@ref flatbuffers_grammar). |
| |
| ## Compiling the Monsters' Schema |
| |
| After you have written the FlatBuffers schema, the next step is to compile it. |
| |
| If you have not already done so, please follow |
| [these instructions](@ref flatbuffers_guide_building) to build `flatc`, the |
| FlatBuffer compiler. |
| |
| Once `flatc` is built successfully, compile the schema for your language: |
| |
| <div class="language-c"> |
| *Note: If you're working in C, you need to use the separate project [FlatCC](https://github.com/dvidelabs/flatcc) which contains a schema compiler and runtime library in C for C.* |
| <br> |
| See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building). |
| <br> |
| Please be aware of the difference between `flatc` and `flatcc` tools. |
| <br> |
| </div> |
| |
| <div class="language-cpp"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --cpp monster.fbs |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --java monster.fbs |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --kotlin monster.fbs |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --csharp monster.fbs |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --go monster.fbs |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --python monster.fbs |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --js monster.fbs |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --ts monster.fbs |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.sh} |
| cd flatbuffers/sample |
| ./../flatc --php monster.fbs |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.sh} |
| cd flatcc |
| mkdir -p build/tmp/samples/monster |
| bin/flatcc -a -o build/tmp/samples/monster samples/monster/monster.fbs |
| # or just |
| flatcc/samples/monster/build.sh |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --dart monster.fbs |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --lua monster.fbs |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --lobster monster.fbs |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --rust monster.fbs |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.sh} |
| cd flatbuffers/samples |
| ./../flatc --swift monster.fbs |
| ~~~ |
| </div> |
| |
| For a more complete guide to using the `flatc` compiler, please read the |
| [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) |
| section of the Programmer's Guide. |
| |
| ## Reading and Writing Monster FlatBuffers |
| |
| Now that we have compiled the schema for our programming language, we can |
| start creating some monsters and serializing/deserializing them from |
| FlatBuffers. |
| |
| #### Creating and Writing Orc FlatBuffers |
| |
| The first step is to import/include the library, generated files, etc. |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| #include "monster_generated.h" // This was generated by `flatc`. |
| |
| using namespace MyGame::Sample; // Specified in the schema. |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| import MyGame.Sample.*; //The `flatc` generated files. (Monster, Vec3, etc.) |
| |
| import com.google.flatbuffers.FlatBufferBuilder; |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kotlin} |
| import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.) |
| |
| import com.google.flatbuffers.FlatBufferBuilder |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| using FlatBuffers; |
| using MyGame.Sample; // The `flatc` generated files. (Monster, Vec3, etc.) |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| import ( |
| flatbuffers "github.com/google/flatbuffers/go" |
| sample "MyGame/Sample" |
| ) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| import flatbuffers |
| |
| # Generated by `flatc`. |
| import MyGame.Sample.Color |
| import MyGame.Sample.Equipment |
| import MyGame.Sample.Monster |
| import MyGame.Sample.Vec3 |
| import MyGame.Sample.Weapon |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // The following code is for JavaScript module loaders (e.g. Node.js). See |
| // below for a browser-based HTML/JavaScript example of including the library. |
| 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). |
| <script src="../js/flatbuffers.js"></script> |
| <script src="monster_generated.js"></script> // Generated by `flatc`. |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| // note: import flatbuffers with your desired import method |
| |
| import { MyGame } from './monster_generated'; |
| </div> |
| <div class="language-php"> |
| ~~~{.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); |
| $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root. |
| |
| // Contains the `*.php` files for the FlatBuffers library and the `flatc` generated files. |
| $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")), |
| join(DIRECTORY_SEPARATOR, array($root_dir, "samples", "MyGame", "Sample"))); |
| foreach ($paths as $path) { |
| $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php")); |
| if (file_exists($file)) { |
| require($file); |
| break; |
| } |
| } |
| } |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| #include "monster_builder.h" // Generated by `flatcc`. |
| |
| // Convenient namespace macro to manage long namespace prefix. |
| #undef ns |
| #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. |
| |
| // A helper to simplify creating vectors from C-arrays. |
| #define c_vec_len(V) (sizeof(V)/sizeof((V)[0])) |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| import 'package:flat_buffers/flat_buffers.dart' as fb; |
| |
| // Generated by `flatc`. |
| import 'monster_my_game.sample_generated.dart' as myGame; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- require the flatbuffers module |
| local flatbuffers = require("flatbuffers") |
| |
| -- require the generated files from `flatc`. |
| local color = require("MyGame.Sample.Color") |
| local equipment = require("MyGame.Sample.Equipment") |
| local monster = require("MyGame.Sample.Monster") |
| local vec3 = require("MyGame.Sample.Vec3") |
| local weapon = require("MyGame.Sample.Weapon") |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| import from "../lobster/" // Where to find flatbuffers.lobster |
| import monster_generated |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // import the flatbuffers runtime library |
| extern crate flatbuffers; |
| |
| // import the generated code |
| #[allow(dead_code, unused_imports)] |
| #[path = "./monster_generated.rs"] |
| mod monster_generated; |
| pub use monster_generated::my_game::sample::{get_root_as_monster, |
| Color, Equipment, |
| Monster, MonsterArgs, |
| Vec3, |
| Weapon, WeaponArgs}; |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| /** |
| // make sure that monster_generated.swift is included in your project |
| */ |
| import Flatbuffers |
| |
| // typealiases for convenience |
| typealias Monster = MyGame1.Sample.Monster |
| typealias Weapon = MyGame1.Sample.Weapon |
| typealias Color = MyGame1.Sample.Color |
| typealias Vec3 = MyGame1.Sample.Vec3 |
| ~~~ |
| </div> |
| |
| Now we are ready to start building some buffers. In order to start, we need |
| to create an instance of the `FlatBufferBuilder`, which will contain the buffer |
| as it grows. You can pass an initial size of the buffer (here 1024 bytes), |
| which will grow automatically if needed: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| // Create a `FlatBufferBuilder`, which will be used to create our |
| // monsters' FlatBuffers. |
| flatbuffers::FlatBufferBuilder builder(1024); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| // Create a `FlatBufferBuilder`, which will be used to create our |
| // monsters' FlatBuffers. |
| FlatBufferBuilder builder = new FlatBufferBuilder(1024); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| // Create a `FlatBufferBuilder`, which will be used to create our |
| // monsters' FlatBuffers. |
| val builder = FlatBufferBuilder(1024) |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| // Create a `FlatBufferBuilder`, which will be used to create our |
| // monsters' FlatBuffers. |
| var builder = new FlatBufferBuilder(1024); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| // Create a `FlatBufferBuilder`, which will be used to create our |
| // monsters' FlatBuffers. |
| builder := flatbuffers.NewBuilder(1024) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| # Create a `FlatBufferBuilder`, which will be used to create our |
| # monsters' FlatBuffers. |
| builder = flatbuffers.Builder(1024) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // Create a `flatbuffer.Builder`, which will be used to create our |
| // monsters' FlatBuffers. |
| var builder = new flatbuffers.Builder(1024); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| // Create a `flatbuffer.Builder`, which will be used to create our |
| // monsters' FlatBuffers. |
| let builder = new flatbuffers.Builder(1024); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| // Create a `FlatBufferBuilder`, which will be used to create our |
| // monsters' FlatBuffers. |
| $builder = new Google\FlatBuffers\FlatbufferBuilder(1024); |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| flatcc_builder_t builder, *B; |
| B = &builder; |
| // Initialize the builder object. |
| flatcc_builder_init(B); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| // Create the fb.Builder object that will be used by our generated builders |
| // Note that if you are only planning to immediately get the byte array this builder would create, |
| // you can use the convenience method `toBytes()` on the generated builders. |
| // For example, you could do something like `new myGame.MonsterBuilder(...).toBytes()` |
| var builder = new fb.Builder(initialSize: 1024); |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- get access to the builder, providing an array of size 1024 |
| local builder = flatbuffers.Builder(1024) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| // get access to the builder |
| let builder = flatbuffers_builder {} |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Build up a serialized buffer algorithmically. |
| // Initialize it with a capacity of 1024 bytes. |
| let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024); |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| // create a `FlatBufferBuilder`, which will be used to serialize objects |
| let builder = FlatBufferBuilder(initialSize: 1024) |
| ~~~ |
| </div> |
| |
| After creating the `builder`, we can start serializing our data. Before we make |
| our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto weapon_one_name = builder.CreateString("Sword"); |
| short weapon_one_damage = 3; |
| |
| auto weapon_two_name = builder.CreateString("Axe"); |
| short weapon_two_damage = 5; |
| |
| // Use the `CreateWeapon` shortcut to create Weapons with all the fields set. |
| auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage); |
| auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| int weaponOneName = builder.createString("Sword") |
| short weaponOneDamage = 3; |
| |
| int weaponTwoName = builder.createString("Axe"); |
| 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); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| val weaponOneName = builder.createString("Sword") |
| val weaponOneDamage: Short = 3; |
| |
| val weaponTwoName = builder.createString("Axe") |
| 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) |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| var weaponOneName = builder.CreateString("Sword"); |
| var weaponOneDamage = 3; |
| |
| var weaponTwoName = builder.CreateString("Axe"); |
| var weaponTwoDamage = 5; |
| |
| // Use the `CreateWeapon()` helper function to create the weapons, since we set every field. |
| var sword = Weapon.CreateWeapon(builder, weaponOneName, (short)weaponOneDamage); |
| var axe = Weapon.CreateWeapon(builder, weaponTwoName, (short)weaponTwoDamage); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| weaponOne := builder.CreateString("Sword") |
| weaponTwo := builder.CreateString("Axe") |
| |
| // 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) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| weapon_one = builder.CreateString('Sword') |
| weapon_two = builder.CreateString('Axe') |
| |
| # Create the first `Weapon` ('Sword'). |
| MyGame.Sample.Weapon.WeaponStart(builder) |
| MyGame.Sample.Weapon.WeaponAddName(builder, weapon_one) |
| MyGame.Sample.Weapon.WeaponAddDamage(builder, 3) |
| sword = MyGame.Sample.Weapon.WeaponEnd(builder) |
| |
| # Create the second `Weapon` ('Axe'). |
| MyGame.Sample.Weapon.WeaponStart(builder) |
| MyGame.Sample.Weapon.WeaponAddName(builder, weapon_two) |
| MyGame.Sample.Weapon.WeaponAddDamage(builder, 5) |
| axe = MyGame.Sample.Weapon.WeaponEnd(builder) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var weaponOne = builder.createString('Sword'); |
| var weaponTwo = builder.createString('Axe'); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.js} |
| let weaponOne = builder.createString('Sword'); |
| let weaponTwo = builder.createString('Axe'); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| // Create the `Weapon`s using the `createWeapon()` helper function. |
| $weapon_one_name = $builder->createString("Sword"); |
| $sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one_name, 3); |
| |
| $weapon_two_name = $builder->createString("Axe"); |
| $axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two_name, 5); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| flatbuffers_string_ref_t weapon_one_name = flatbuffers_string_create_str(B, "Sword"); |
| uint16_t weapon_one_damage = 3; |
| |
| flatbuffers_string_ref_t weapon_two_name = flatbuffers_string_create_str(B, "Axe"); |
| 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)); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| // The generated Builder classes work much like in other languages, |
| final int weaponOneName = builder.writeString("Sword"); |
| final int weaponOneDamage = 3; |
| |
| final int weaponTwoName = builder.writeString("Axe"); |
| 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(); |
| |
| |
| |
| // The generated ObjectBuilder classes offer an easier to use alternative |
| // at the cost of requiring some additional reference allocations. If memory |
| // usage is critical, or if you'll be working with especially large messages |
| // or tables, you should prefer using the generated Builder classes. |
| // The following code would produce an identical buffer as above. |
| final String weaponOneName = "Sword"; |
| final int weaponOneDamage = 3; |
| |
| final String weaponTwoName = "Axe"; |
| final int weaponTwoDamage = 5; |
| |
| final myGame.WeaponBuilder sword = new myGame.WeaponObjectBuilder( |
| name: weaponOneName, |
| damage: weaponOneDamage, |
| ); |
| |
| final myGame.WeaponBuilder axe = new myGame.WeaponObjectBuilder( |
| name: weaponTwoName, |
| damage: weaponTwoDamage, |
| ); |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| local weaponOne = builder:CreateString("Sword") |
| local weaponTwo = builder:CreateString("Axe") |
| |
| -- 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) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| let weapon_names = [ "Sword", "Axe" ] |
| let weapon_damages = [ 3, 5 ] |
| |
| let weapon_offsets = map(weapon_names) name, i: |
| let ns = builder.CreateString(name) |
| MyGame_Sample_WeaponBuilder { b } |
| .start() |
| .add_name(ns) |
| .add_damage(weapon_damages[i]) |
| .end() |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Serialize some weapons for the Monster: A 'sword' and an 'axe'. |
| let weapon_one_name = builder.create_string("Sword"); |
| let weapon_two_name = builder.create_string("Axe"); |
| |
| // 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, |
| }); |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| let weapon1Name = builder.create(string: "Sword") |
| let weapon2Name = builder.create(string: "Axe") |
| |
| // 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) |
| ~~~ |
| </div> |
| |
| Now let's create our monster, the `orc`. For this `orc`, lets make him |
| `red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him |
| a large pool of hit points with `300`. We can give him a vector of weapons |
| to choose from (our `Sword` and `Axe` from earlier). In this case, we will |
| equip him with the `Axe`, since it is the most powerful of the two. Lastly, |
| let's fill his inventory with some potential treasures that can be taken once he |
| is defeated. |
| |
| Before we serialize a monster, we need to first serialize any objects that are |
| contained there-in, i.e. we serialize the data tree using depth-first, pre-order |
| traversal. This is generally easy to do on any tree structures. |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| // Serialize a name for our monster, called "Orc". |
| auto name = builder.CreateString("Orc"); |
| |
| // 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}; |
| auto inventory = builder.CreateVector(treasure, 10); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| // Serialize a name for our monster, called "Orc". |
| int name = builder.createString("Orc"); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| // Serialize a name for our monster, called "Orc". |
| val name = builder.createString("Orc") |
| |
| // 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) |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| // Serialize a name for our monster, called "Orc". |
| var name = builder.CreateString("Orc"); |
| |
| // 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. |
| Monster.StartInventoryVector(builder, 10); |
| for (int i = 9; i >= 0; i--) |
| { |
| builder.AddByte((byte)i); |
| } |
| var inv = builder.EndVector(); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| // Serialize a name for our monster, called "Orc". |
| name := builder.CreateString("Orc") |
| |
| // 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) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| # Serialize a name for our monster, called "Orc". |
| name = builder.CreateString("Orc") |
| |
| # 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.MonsterStartInventoryVector(builder, 10) |
| for i in reversed(range(0, 10)): |
| builder.PrependByte(i) |
| inv = builder.EndVector(10) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // Serialize a name for our monster, called 'Orc'. |
| var name = builder.createString('Orc'); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.js} |
| // Serialize a name for our monster, called 'Orc'. |
| let name = builder.createString('Orc'); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| // Serialize a name for our monster, called "Orc". |
| $name = $builder->createString("Orc"); |
| |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-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"); |
| |
| // 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)); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| // Serialize a name for our monster, called "Orc". |
| final int name = builder.writeString('Orc'); |
| |
| // 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<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| final inventory = builder.writeListUint8(treasure); |
| |
| // The following code should be used instead if you intend to use the |
| // ObjectBuilder classes: |
| // Serialize a name for our monster, called "Orc". |
| final String name = 'Orc'; |
| |
| // 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<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.py} |
| -- Serialize a name for our mosnter, called 'orc' |
| local name = builder:CreateString("Orc") |
| |
| -- 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) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| // Name of the monster. |
| let name = builder.CreateString("Orc") |
| |
| // Inventory. |
| let inv = builder.MyGame_Sample_MonsterCreateInventoryVector(map(10): _) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Name of the Monster. |
| let name = builder.create_string("Orc"); |
| |
| // Inventory. |
| let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]); |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| // Name of the Monster. |
| let name = builder.create(string: "Orc") |
| |
| // create inventory |
| let inventory: [Byte] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
| let inventoryOffset = builder.createVector(inventory) |
| ~~~ |
| </div> |
| |
| We serialized two built-in data types (`string` and `vector`) and captured |
| their return values. These values are offsets into the serialized data, |
| indicating where they are stored, such that we can refer to them below when |
| adding fields to our monster. |
| |
| *Note: To create a `vector` of nested objects (e.g. `table`s, `string`s, or |
| other `vector`s), collect their offsets into a temporary data structure, and |
| then create an additional `vector` containing their offsets.* |
| |
| If instead of creating a vector from an existing array you serialize elements |
| individually one by one, take care to note that this happens in reverse order, |
| as buffers are built back to front. |
| |
| For example, take a look at the two `Weapon`s that we created earlier (`Sword` |
| and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in |
| memory. Therefore we can create a FlatBuffer `vector` to contain these |
| offsets. |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| // Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`. |
| std::vector<flatbuffers::Offset<Weapon>> weapons_vector; |
| weapons_vector.push_back(sword); |
| weapons_vector.push_back(axe); |
| auto weapons = builder.CreateVector(weapons_vector); |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| // 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) |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| var weaps = new Offset<Weapon>[2]; |
| weaps[0] = sword; |
| weaps[1] = axe; |
| |
| // Pass the `weaps` array into the `CreateWeaponsVector()` method to create a FlatBuffer vector. |
| var weapons = Monster.CreateWeaponsVector(builder, weaps); |
| ~~~ |
| </div> |
| <div class="language-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) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| # Create a FlatBuffer vector and prepend the weapons. |
| # Note: Since we prepend the data, prepend them in reverse order. |
| MyGame.Sample.Monster.MonsterStartWeaponsVector(builder, 2) |
| builder.PrependUOffsetTRelative(axe) |
| builder.PrependUOffsetTRelative(sword) |
| weapons = builder.EndVector(2) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-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)); |
| ~~~ |
| </div> |
| <div class="language-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<myGame.WeaponBuilder> weaps = [sword, axe]; |
| ~~~ |
| </div> |
| <div class="language-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) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| let weapons = builder.MyGame_Sample_MonsterCreateWeaponsVector(weapon_offsets) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Create a FlatBuffer `vector` that contains offsets to the sword and axe |
| // we created above. |
| let weapons = builder.create_vector(&[sword, axe]); |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| // Create a FlatBuffer `vector` that contains offsets to the sword and axe |
| // we created above. |
| let weaponsOffset = builder.createVector(ofOffsets: [sword, axe]) |
| ~~~ |
| </div> |
| |
| <br> |
| Note there's additional convenience overloads of `CreateVector`, allowing you |
| to work with data that's not in a `std::vector`, or allowing you to generate |
| elements by calling a lambda. For the common case of `std::vector<std::string>` |
| there's also `CreateVectorOfStrings`. |
| </div> |
| |
| Note that vectors of structs are serialized differently from tables, since |
| structs are stored in-line in the vector. For example, to create a vector |
| for the `path` field above: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) }; |
| auto path = builder.CreateVectorOfStructs(points, 2); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| 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(); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| 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() |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| Monster.StartPathVector(fbb, 2); |
| Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f); |
| Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f); |
| var path = fbb.EndVector(); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| 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) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| MyGame.Sample.Monster.MonsterStartPathVector(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(2) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| 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(); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| 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(); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| \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(); |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| // TBD |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| // 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 |
| |
| // Otherwise, using the ObjectBuilder classes: |
| // The dart implementation provides a simple interface for writing vectors |
| // of structs, in `writeListOfStructs`. This method takes |
| // `List<ObjectBuilder>` and is used by the generated builder classes. |
| final List<myGame.Vec3ObjectBuilder> path = [ |
| new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0), |
| new myGame.Vec3ObjectBuilder(x: 4.0, y: 5.0, z: 6.0) |
| ]; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- 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) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| 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) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // 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]); |
| |
| // Note that, for convenience, it is also valid to create a vector of |
| // references to structs, like this: |
| // let path = builder.create_vector(&[&x, &y]); |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| // |
| let points = builder.createVector(structs: [MyGame.Sample.createVec3(x: 1, y: 2, z: 3), |
| MyGame.Sample.createVec3(x: 4, y: 5, z: 6)], |
| type: Vec3.self) |
| ~~~ |
| </div> |
| |
| |
| We have now serialized the non-scalar components of the orc, so we |
| can serialize the monster itself: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| // Create the position struct |
| auto position = Vec3(1.0f, 2.0f, 3.0f); |
| |
| // Set his hit points to 300 and his mana to 150. |
| int hp = 300; |
| int mana = 150; |
| |
| // Finally, create the monster using the `CreateMonster` helper function |
| // to set all fields. |
| auto orc = CreateMonster(builder, &position, mana, hp, name, inventory, |
| Color_Red, weapons, Equipment_Weapon, axe.Union(), |
| path); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| // 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) |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| // Create our monster using `StartMonster()` and `EndMonster()`. |
| Monster.StartMonster(builder); |
| Monster.AddPos(builder, Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f)); |
| Monster.AddHp(builder, (short)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.Value); // Axe |
| Monster.AddPath(builder, path); |
| var orc = Monster.EndMonster(builder); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| // 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) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| # Create our monster by using `MonsterStart()` and `MonsterEnd()`. |
| MyGame.Sample.Monster.MonsterStart(builder) |
| MyGame.Sample.Monster.MonsterAddPos(builder, |
| MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) |
| MyGame.Sample.Monster.MonsterAddHp(builder, 300) |
| MyGame.Sample.Monster.MonsterAddName(builder, name) |
| MyGame.Sample.Monster.MonsterAddInventory(builder, inv) |
| MyGame.Sample.Monster.MonsterAddColor(builder, |
| MyGame.Sample.Color.Color().Red) |
| MyGame.Sample.Monster.MonsterAddWeapons(builder, weapons) |
| MyGame.Sample.Monster.MonsterAddEquippedType( |
| builder, MyGame.Sample.Equipment.Equipment().Weapon) |
| MyGame.Sample.Monster.MonsterAddEquipped(builder, axe) |
| MyGame.Sample.Monster.MonsterAddPath(builder, path) |
| orc = MyGame.Sample.Monster.MonsterEnd(builder) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| // 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); |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| // 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)); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| // 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(); |
| |
| // -Or- using the ObjectBuilder API: |
| // Set his hit points to 300 and his mana to 150. |
| final int hp = 300; |
| final int mana = 150; |
| |
| // Note that these parameters are optional - it is not necessary to set |
| // all of them. |
| // Also note that it is not necessary to `finish` the builder helpers above |
| // - the generated code will automatically reuse offsets if the same object |
| // is used in more than one place (e.g. the axe appearing in `weapons` and |
| // `equipped`). |
| final myGame.MonsterBuilder orcBuilder = new myGame.MonsterBuilder( |
| name: name, |
| inventory: treasure, |
| weapons: weaps, |
| equippedType: myGame.EquipmentTypeId.Weapon, |
| equipped: axe, |
| path: path, |
| hp: hp, |
| mana: mana, |
| pos: new myGame.Vec3Builder(x: 1.0, y: 2.0, z: 3.0), |
| color: myGame.Color.Red, |
| path: [ |
| new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0), |
| new myGame.Vec3ObjectBuilder(x: 4.0, y: 5.0, z: 6.0) |
| ]); |
| |
| final int orc = orcBuilder.finish(builder); |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- 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) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| 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() |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // 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() |
| }); |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| let orc = Monster.createMonster(builder, |
| offsetOfPos: pos, |
| hp: 300, |
| offsetOfName: name, |
| vectorOfInventory: inventoryOffset, |
| color: .red, |
| vectorOfWeapons: weaponsOffset, |
| equippedType: .weapon, |
| offsetOfEquipped: axe) |
| ~~~ |
| </div> |
| |
| Note how we create `Vec3` struct in-line in the table. Unlike tables, structs |
| are simple combinations of scalars that are always stored inline, just like |
| scalars themselves. |
| |
| **Important**: Unlike structs, you should not nest tables or other objects, |
| which is why we created all the strings/vectors/tables that this monster refers |
| to before `start`. If you try to create any of them between `start` and `end`, |
| you will get an assert/exception/panic depending on your language. |
| |
| *Note: Since we are passing `150` as the `mana` field, which happens to be the |
| default value, the field will not actually be written to the buffer, since the |
| default value will be returned on query anyway. This is a nice space savings, |
| especially if default values are common in your data. It also means that you do |
| not need to be worried of adding a lot of fields that are only used in a small |
| number of instances, as it will not bloat the buffer if unused.* |
| |
| <div class="language-cpp"> |
| <br> |
| If you do not wish to set every field in a `table`, it may be more convenient to |
| manually set each field of your monster, instead of calling `CreateMonster()`. |
| The following snippet is functionally equivalent to the above code, but provides |
| a bit more flexibility. |
| <br> |
| ~~~{.cpp} |
| // You can use this code instead of `CreateMonster()`, to create our orc |
| // manually. |
| MonsterBuilder monster_builder(builder); |
| monster_builder.add_pos(&position); |
| monster_builder.add_hp(hp); |
| monster_builder.add_name(name); |
| monster_builder.add_inventory(inventory); |
| monster_builder.add_color(Color_Red); |
| monster_builder.add_weapons(weapons); |
| monster_builder.add_equipped_type(Equipment_Weapon); |
| monster_builder.add_equipped(axe.Union()); |
| auto orc = monster_builder.Finish(); |
| ~~~ |
| </div> |
| <div class="language-c"> |
| If you do not wish to set every field in a `table`, it may be more convenient to |
| manually set each field of your monster, instead of calling `create_monster_as_root()`. |
| The following snippet is functionally equivalent to the above code, but provides |
| a bit more flexibility. |
| <br> |
| ~~~{.c} |
| // It is important to pair `start_as_root` with `end_as_root`. |
| ns(Monster_start_as_root(B)); |
| ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f)); |
| // or alternatively |
| //ns(Monster_pos_add(&pos); |
| |
| ns(Monster_hp_add(B, hp)); |
| // Notice that `Monser_name_add` adds a string reference unlike the |
| // add_str and add_strn variants. |
| ns(Monster_name_add(B, name)); |
| ns(Monster_inventory_add(B, inventory)); |
| ns(Monster_color_add(B, ns(Color_Red))); |
| ns(Monster_weapons_add(B, weapons)); |
| ns(Monster_equipped_add(B, equipped)); |
| // Complete the monster object and make it the buffer root object. |
| ns(Monster_end_as_root(B)); |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| let start = Monster.startMonster(builder) |
| Monster.add(pos: pos, builder) |
| Monster.add(hp: 300, builder) |
| Monster.add(name: name, builder) |
| Monster.addVectorOf(inventory: inventoryOffset, builder) |
| Monster.add(color: .red, builder) |
| Monster.addVectorOf(weapons: weaponsOffset, builder) |
| Monster.add(equippedType: .weapon, builder) |
| Monster.add(equipped: axe, builder) |
| var orc = Monster.endMonster(builder, start: start) |
| ~~~ |
| </div> |
| |
| Before finishing the serialization, let's take a quick look at FlatBuffer |
| `union Equipped`. There are two parts to each FlatBuffer `union`. The first, is |
| a hidden field `_type`, that is generated to hold the type of `table` referred |
| to by the `union`. This allows you to know which type to cast to at runtime. |
| Second, is the `union`'s data. |
| |
| In our example, the last two things we added to our `Monster` were the |
| `Equipped Type` and the `Equipped` union itself. |
| |
| Here is a repetition these lines, to help highlight them more clearly: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| monster_builder.add_equipped_type(Equipment_Weapon); // Union type |
| monster_builder.add_equipped(axe); // Union data |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| Monster.addEquippedType(builder, Equipment.Weapon); // Union type |
| Monster.addEquipped(axe); // Union data |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| Monster.addEquippedType(builder, Equipment.Weapon) // Union type |
| Monster.addEquipped(axe) // Union data |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| Monster.AddEquippedType(builder, Equipment.Weapon); // Union type |
| Monster.AddEquipped(builder, axe.Value); // Union data |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) // Union type |
| sample.MonsterAddEquipped(builder, axe) // Union data |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| MyGame.Sample.Monster.MonsterAddEquippedType( # Union type |
| builder, MyGame.Sample.Equipment.Equipment().Weapon) |
| MyGame.Sample.Monster.MonsterAddEquipped(builder, axe) # Union data |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon); // Union type |
| MyGame.Sample.Monster.addEquipped(builder, axe); // Union data |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon); // Union type |
| MyGame.Sample.Monster.addEquipped(builder, axe); // Union data |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon); // Union type |
| \MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| // Add union type and data simultaneously. |
| ns(Monster_equipped_Weapon_add(B, axe)); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| // using the builder API: |
| ..addEquippedType(myGame.EquipmentTypeId.Weapon) |
| ..addEquippedOffset(axe) |
| |
| // in the ObjectBuilder API: |
| equippedTypeId: myGame.EquipmentTypeId.Weapon, // Union type |
| equipped: axe, // Union data |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| monster.AddEquippedType(builder, equipment.Weapon) -- Union type |
| monster.AddEquipped(builder, axe) -- Union data |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| .add_equipped_type(MyGame_Sample_Equipment_Weapon) |
| .add_equipped(axe) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // You need to call `as_union_value` to turn an object into a type that |
| // can be used as a union value. |
| monster_builder.add_equipped_type(Equipment::Weapon); // Union type |
| monster_builder.add_equipped(axe.as_union_value()); // Union data |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| Monster.add(equippedType: .weapon, builder) // Type of union |
| Monster.add(equipped: axe, builder) // Union data |
| ~~~ |
| </div> |
| |
| |
| After you have created your buffer, you will have the offset to the root of the |
| data in the `orc` variable, so you can finish the buffer by calling the |
| appropriate `finish` method. |
| |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| // Call `Finish()` to instruct the builder that this monster is complete. |
| // Note: Regardless of how you created the `orc`, you still need to call |
| // `Finish()` on the `FlatBufferBuilder`. |
| builder.Finish(orc); // You could also call `FinishMonsterBuffer(builder, |
| // orc);`. |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| // Call `finish()` to instruct the builder that this monster is complete. |
| builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`. |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| // Call `finish()` to instruct the builder that this monster is complete. |
| builder.finish(orc) // You could also call `Monster.finishMonsterBuffer(builder, orc);`. |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| // Call `Finish()` to instruct the builder that this monster is complete. |
| builder.Finish(orc.Value); // You could also call `Monster.FinishMonsterBuffer(builder, orc);`. |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| // Call `Finish()` to instruct the builder that this monster is complete. |
| builder.Finish(orc) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| # Call `Finish()` to instruct the builder that this monster is complete. |
| builder.Finish(orc) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // Call `finish()` to instruct the builder that this monster is complete. |
| builder.finish(orc); // You could also call `MyGame.Sample.Monster.finishMonsterBuffer(builder, |
| // orc);`. |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| // Call `finish()` to instruct the builder that this monster is complete. |
| builder.finish(orc); // You could also call `MyGame.Sample.Monster.finishMonsterBuffer(builder, |
| // orc);`. |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| // Call `finish()` to instruct the builder that this monster is complete. |
| $builder->finish($orc); // You may also call `\MyGame\Sample\Monster::FinishMonsterBuffer( |
| // $builder, $orc);`. |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| // Because we used `Monster_create_as_root`, we do not need a `finish` call in C`. |
| ~~~ |
| </div> |
| <div class="language-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. |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- Call 'Finish()' to instruct the builder that this monster is complete. |
| builder:Finish(orc) |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| // Call `Finish()` to instruct the builder that this monster is complete. |
| builder.Finish(orc) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Call `finish()` to instruct the builder that this monster is complete. |
| builder.finish(orc, None); |
| ~~~ |
| </div> |
| <div class="language-swift"> |
| ~~~{.swift} |
| // Call `finish(offset:)` to instruct the builder that this monster is complete. |
| builder.finish(offset: orc) |
| ~~~ |
| </div> |
| |
| The buffer is now ready to be stored somewhere, sent over the network, be |
| compressed, or whatever you'd like to do with it. You can access the buffer |
| like so: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| // This must be called after `Finish()`. |
| uint8_t *buf = builder.GetBufferPointer(); |
| int size = builder.GetSize(); // Returns the size of the buffer that |
| // `GetBufferPointer()` points to. |
| ~~~ |
| </div> |
| <div class="language-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(); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| // 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() |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| // This must be called after `Finish()`. |
| var buf = builder.DataBuffer; // Of type `FlatBuffers.ByteBuffer`. |
| // The data in this ByteBuffer does NOT start at 0, but at buf.Position. |
| // The end of the data is marked by buf.Length, so the size is |
| // buf.Length - buf.Position. |
| |
| // Alternatively this copies the above data out of the ByteBuffer for you: |
| byte[] buf = builder.SizedByteArray(); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| // This must be called after `Finish()`. |
| buf := builder.FinishedBytes() // Of type `byte[]`. |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| # This must be called after `Finish()`. |
| buf = builder.Output() // Of type `bytearray`. |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // This must be called after `finish()`. |
| var buf = builder.asUint8Array(); // Of type `Uint8Array`. |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| // This must be called after `finish()`. |
| let buf = builder.asUint8Array(); // Of type `Uint8Array`. |
| ~~~ |
| </div> |
| <div class="language-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(). |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| final Uint8List buf = builder.finish(orc); |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- Get the flatbuffer as a string containing the binary data |
| local bufAsString = builder:Output() |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| // This must be called after `Finish()`. |
| let buf = builder.SizedCopy() // Of type `string`. |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // This must be called after `finish()`. |
| // `finished_data` returns a byte slice. |
| let buf = builder.finished_data(); // Of type `&[u8]` |
| ~~~ |
| </div> |
| |
| <div class="language-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) |
| ~~~ |
| </div> |
| |
| Now you can write the bytes to a file, send them over the network.. |
| **Make sure your file mode (or transfer protocol) is set to BINARY, not text.** |
| If you transfer a FlatBuffer in text mode, the buffer will be corrupted, |
| which will lead to hard to find problems when you read the buffer. |
| |
| #### Reading Orc FlatBuffers |
| |
| Now that we have successfully created an `Orc` FlatBuffer, the monster data can |
| be saved, sent over a network, etc. Let's now adventure into the inverse, and |
| access a FlatBuffer. |
| |
| This section requires the same import/include, namespace, etc. requirements as |
| before: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| #include "monster_generated.h" // This was generated by `flatc`. |
| |
| using namespace MyGame::Sample; // Specified in the schema. |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| import MyGame.Sample.*; //The `flatc` generated files. (Monster, Vec3, etc.) |
| |
| import com.google.flatbuffers.FlatBufferBuilder; |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.) |
| |
| import com.google.flatbuffers.FlatBufferBuilder |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| using FlatBuffers; |
| using MyGame.Sample; // The `flatc` generated files. (Monster, Vec3, etc.) |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| import ( |
| flatbuffers "github.com/google/flatbuffers/go" |
| sample "MyGame/Sample" |
| ) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| import flatbuffers |
| |
| # Generated by `flatc`. |
| import MyGame.Sample.Any |
| import MyGame.Sample.Color |
| import MyGame.Sample.Monster |
| import MyGame.Sample.Vec3 |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| // The following code is for JavaScript module loaders (e.g. Node.js). See |
| // below for a browser-based HTML/JavaScript example of including the library. |
| 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). |
| <script src="../js/flatbuffers.js"></script> |
| <script src="monster_generated.js"></script> // Generated by `flatc`. |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.js} |
| // note: import flabuffers with your desired import method |
| |
| import { MyGame } from './monster_generated'; |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.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); |
| $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root. |
| |
| // Contains the `*.php` files for the FlatBuffers library and the `flatc` generated files. |
| $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")), |
| join(DIRECTORY_SEPARATOR, array($root_dir, "samples", "MyGame", "Sample"))); |
| foreach ($paths as $path) { |
| $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php")); |
| if (file_exists($file)) { |
| require($file); |
| break; |
| } |
| } |
| } |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| // Only needed if we don't have `#include "monster_builder.h"`. |
| #include "monster_reader.h" |
| |
| #undef ns |
| #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema. |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| import 'package:flat_buffers/flat_buffers.dart' as fb; |
| import './monster_my_game.sample_generated.dart' as myGame; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| -- require the flatbuffers module |
| local flatbuffers = require("flatbuffers") |
| |
| -- require the generated files from `flatc`. |
| local color = require("MyGame.Sample.Color") |
| local equipment = require("MyGame.Sample.Equipment") |
| local monster = require("MyGame.Sample.Monster") |
| local vec3 = require("MyGame.Sample.Vec3") |
| local weapon = require("MyGame.Sample.Weapon") |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| import from "../lobster/" // Where to find flatbuffers.lobster |
| import monster_generated |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // import the flatbuffers runtime library |
| extern crate flatbuffers; |
| |
| // import the generated code |
| #[allow(dead_code, unused_imports)] |
| #[path = "./monster_generated.rs"] |
| mod monster_generated; |
| pub use monster_generated::my_game::sample::{get_root_as_monster, |
| Color, Equipment, |
| Monster, MonsterArgs, |
| Vec3, |
| Weapon, WeaponArgs}; |
| ~~~ |
| </div> |
| |
| Then, assuming you have a buffer of bytes received from disk, |
| network, etc., you can create start accessing the buffer like so: |
| |
| **Again, make sure you read the bytes in BINARY mode, otherwise the code below |
| won't work** |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| uint8_t *buffer_pointer = /* the data you just read */; |
| |
| // Get a pointer to the root object inside the buffer. |
| auto monster = GetMonster(buffer_pointer); |
| |
| // `monster` is of type `Monster *`. |
| // Note: root object pointers are NOT the same as `buffer_pointer`. |
| // `GetMonster` is a convenience function that calls `GetRoot<Monster>`, |
| // the latter is also available for non-root types. |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| 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) |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| byte[] bytes = /* the data you just read */ |
| var buf = new ByteBuffer(bytes); |
| |
| // Get an accessor to the root object inside the buffer. |
| var monster = Monster.GetRootAsMonster(buf); |
| ~~~ |
| </div> |
| <div class="language-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. |
| ~~~ |
| </div> |
| <div class="language-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.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 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. |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var bytes = /* the data you just read, in an object of type "Uint8Array" */ |
| var buf = new flatbuffers.ByteBuffer(bytes); |
| |
| // Get an accessor to the root object inside the buffer. |
| var monster = MyGame.Sample.Monster.getRootAsMonster(buf); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| let bytes = /* the data you just read, in an object of type "Uint8Array" */ |
| let buf = new flatbuffers.ByteBuffer(bytes); |
| |
| // Get an accessor to the root object inside the buffer. |
| let monster = MyGame.Sample.Monster.getRootAsMonster(buf); |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-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. |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| List<int> 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); |
| ~~~ |
| </div> |
| <div class="language-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) |
| ~~~ |
| </div> |
| <div class="language-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) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| let buf = /* the data you just read, in a &[u8] */ |
| |
| // Get an accessor to the root object inside the buffer. |
| let monster = get_root_as_monster(buf); |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| // create a ByteBuffer(:) from an [UInt8] or Data() |
| let buf = // Get your data |
| |
| // Get an accessor to the root object inside the buffer. |
| let monster = Monster.getRootAsMonster(bb: ByteBuffer(bytes: buf)) |
| ~~~ |
| </div> |
| |
| If you look in the generated files from the schema compiler, you will see it generated |
| accessors for all non-`deprecated` fields. For example: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto hp = monster->hp(); |
| auto mana = monster->mana(); |
| auto name = monster->name()->c_str(); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| short hp = monster.hp(); |
| short mana = monster.mana(); |
| String name = monster.name(); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| val hp = monster.hp |
| val mana = monster.mana |
| val name = monster.name |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| // For C#, unlike most other languages support by FlatBuffers, most values (except for |
| // vectors and unions) are available as properties instead of accessor methods. |
| var hp = monster.Hp |
| var mana = monster.Mana |
| var name = monster.Name |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| hp := monster.Hp() |
| mana := monster.Mana() |
| name := string(monster.Name()) // Note: `monster.Name()` returns a byte[]. |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| hp = monster.Hp() |
| mana = monster.Mana() |
| name = monster.Name() |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var hp = $monster.hp(); |
| var mana = $monster.mana(); |
| var name = $monster.name(); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| let hp = $monster.hp(); |
| let mana = $monster.mana(); |
| let name = $monster.name(); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| $hp = $monster->getHp(); |
| $mana = $monster->getMana(); |
| $name = monster->getName(); |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| uint16_t hp = ns(Monster_hp(monster)); |
| uint16_t mana = ns(Monster_mana(monster)); |
| flatbuffers_string_t name = ns(Monster_name(monster)); |
| ~~~ |
| </div> |
| <div class="language-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; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| local hp = mon:Hp() |
| local mana = mon:Mana() |
| local name = mon:Name() |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| let hp = monster.hp |
| let mana = monster.mana |
| let name = monster.name |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Get and test some scalar types from the FlatBuffer. |
| let hp = monster.hp(); |
| let mana = monster.mana(); |
| let name = monster.name(); |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| let hp = monster.hp |
| let mana = monster.mana |
| let name = monster.name // returns an optional string |
| ~~~ |
| </div> |
| |
| These should hold `300`, `150`, and `"Orc"` respectively. |
| |
| *Note: The default value `150` wasn't stored in `mana`, but we are still able to retrieve it.* |
| |
| To access sub-objects, in the case of our `pos`, which is a `Vec3`: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto pos = monster->pos(); |
| auto x = pos->x(); |
| auto y = pos->y(); |
| auto z = pos->z(); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| Vec3 pos = monster.pos(); |
| float x = pos.x(); |
| float y = pos.y(); |
| float z = pos.z(); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| val pos = monster.pos!! |
| val x = pos.x |
| val y = pos.y |
| val z = pos.z |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| var pos = monster.Pos.Value; |
| var x = pos.X; |
| var y = pos.Y; |
| var z = pos.Z; |
| ~~~ |
| </div> |
| <div class="language-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. |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| pos = monster.Pos() |
| x = pos.X() |
| y = pos.Y() |
| z = pos.Z() |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var pos = monster.pos(); |
| var x = pos.x(); |
| var y = pos.y(); |
| var z = pos.z(); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| let pos = monster.pos(); |
| let x = pos.x(); |
| let y = pos.y(); |
| let z = pos.z(); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| $pos = $monster->getPos(); |
| $x = $pos->getX(); |
| $y = $pos->getY(); |
| $z = $pos->getZ(); |
| ~~~ |
| </div> |
| <div class="language-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)); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| myGame.Vec3 pos = monster.pos; |
| double x = pos.x; |
| double y = pos.y; |
| double z = pos.z; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| local pos = mon:Pos() |
| local x = pos:X() |
| local y = pos:Y() |
| local z = pos:Z() |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| let pos = monster.pos |
| let x = pos.x |
| let y = pos.y |
| let z = pos.z |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| let pos = monster.pos().unwrap(); |
| let x = pos.x(); |
| let y = pos.y(); |
| let z = pos.z(); |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| let pos = monster.pos |
| let x = pos.x |
| let y = pos.y |
| let z = pos.z |
| ~~~ |
| </div> |
| |
| `x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively. |
| |
| *Note: Had we not set `pos` during serialization, it would be a `NULL`-value.* |
| |
| Similarly, we can access elements of the inventory `vector` by indexing it. You |
| can also iterate over the length of the array/vector representing the |
| FlatBuffers `vector`. |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto inv = monster->inventory(); // A pointer to a `flatbuffers::Vector<>`. |
| auto inv_len = inv->size(); |
| auto third_item = inv->Get(2); |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| int invLength = monster.inventoryLength(); |
| byte thirdItem = monster.inventory(2); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kotlin} |
| val invLength = monster.inventoryLength |
| val thirdItem = monster.inventory(2)!! |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| int invLength = monster.InventoryLength; |
| var thirdItem = monster.Inventory(2); |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| invLength := monster.InventoryLength() |
| thirdItem := monster.Inventory(2) |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| inv_len = monster.InventoryLength() |
| third_item = monster.Inventory(2) |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var invLength = monster.inventoryLength(); |
| var thirdItem = monster.inventory(2); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| let invLength = monster.inventoryLength(); |
| let thirdItem = monster.inventory(2); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| $inv_len = $monster->getInventoryLength(); |
| $third_item = $monster->getInventory(2); |
| ~~~ |
| </div> |
| <div class="language-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); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| int invLength = monster.inventory.length; |
| var thirdItem = monster.inventory[2]; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| local invLength = mon:InventoryLength() |
| local thirdItem = mon:Inventory(3) -- Lua is 1-based |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| let inv_len = monster.inventory_length |
| let third_item = monster.inventory(2) |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // Get a 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]; |
| ~~~ |
| </div> |
| |
| <div class="language-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 |
| ~~~ |
| </div> |
| |
| For `vector`s of `table`s, you can access the elements like any other vector, |
| except your need to handle the result as a FlatBuffer `table`: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto weapons = monster->weapons(); // A pointer to a `flatbuffers::Vector<>`. |
| auto weapon_len = weapons->size(); |
| auto second_weapon_name = weapons->Get(1)->name()->str(); |
| auto second_weapon_damage = weapons->Get(1)->damage() |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| int weaponsLength = monster.weaponsLength(); |
| String secondWeaponName = monster.weapons(1).name(); |
| short secondWeaponDamage = monster.weapons(1).damage(); |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| val weaponsLength = monster.weaponsLength |
| val secondWeaponName = monster.weapons(1)!!.name |
| val secondWeaponDamage = monster.weapons(1)!!.damage |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| int weaponsLength = monster.WeaponsLength; |
| var secondWeaponName = monster.Weapons(1).Name; |
| var secondWeaponDamage = monster.Weapons(1).Damage; |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| weaponLength := monster.WeaponsLength() |
| weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()` |
| // to capture the output of the function. |
| if monster.Weapons(weapon, 1) { |
| secondWeaponName := weapon.Name() |
| secondWeaponDamage := weapon.Damage() |
| } |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| weapons_length = monster.WeaponsLength() |
| second_weapon_name = monster.Weapons(1).Name() |
| second_weapon_damage = monster.Weapons(1).Damage() |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var weaponsLength = monster.weaponsLength(); |
| var secondWeaponName = monster.weapons(1).name(); |
| var secondWeaponDamage = monster.weapons(1).damage(); |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| let weaponsLength = monster.weaponsLength(); |
| let secondWeaponName = monster.weapons(1).name(); |
| let secondWeaponDamage = monster.weapons(1).damage(); |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| $weapons_len = $monster->getWeaponsLength(); |
| $second_weapon_name = $monster->getWeapons(1)->getName(); |
| $second_weapon_damage = $monster->getWeapons(1)->getDamage(); |
| ~~~ |
| </div> |
| <div class="language-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)))); |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| int weaponsLength = monster.weapons.length; |
| var secondWeaponName = monster.weapons[1].name; |
| var secondWeaponDamage = monster.Weapons[1].damage; |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| local weaponsLength = mon:WeaponsLength() |
| local secondWeaponName = mon:Weapon(2):Name() |
| local secondWeaponDamage = mon:Weapon(2):Damage() |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| let weapons_length = monster.weapons_length |
| let second_weapon_name = monster.weapons(1).name |
| let second_weapon_damage = monster.weapons(1).damage |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // 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(); |
| ~~~ |
| </div> |
| <div class="language-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 |
| ~~~ |
| </div> |
| |
| Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created |
| the `union`, we need to get both parts of the `union`: the type and the data. |
| |
| We can access the type to dynamically cast the data as needed (since the |
| `union` only stores a FlatBuffer `table`). |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto union_type = monster.equipped_type(); |
| |
| if (union_type == Equipment_Weapon) { |
| auto weapon = static_cast<const Weapon*>(monster->equipped()); // Requires `static_cast` |
| // to type `const Weapon*`. |
| |
| auto weapon_name = weapon->name()->str(); // "Axe" |
| auto weapon_damage = weapon->damage(); // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| int unionType = monster.EquippedType(); |
| |
| if (unionType == Equipment.Weapon) { |
| Weapon weapon = (Weapon)monster.equipped(new Weapon()); // Requires explicit cast |
| // to `Weapon`. |
| |
| String weaponName = weapon.name(); // "Axe" |
| short weaponDamage = weapon.damage(); // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| val unionType = monster.EquippedType |
| |
| if (unionType == Equipment.Weapon) { |
| val weapon = monster.equipped(Weapon()) as Weapon // Requires explicit cast |
| // to `Weapon`. |
| |
| val weaponName = weapon.name // "Axe" |
| val weaponDamage = weapon.damage // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| var unionType = monster.EquippedType; |
| |
| if (unionType == Equipment.Weapon) { |
| var weapon = monster.Equipped<Weapon>().Value; |
| |
| var weaponName = weapon.Name; // "Axe" |
| var weaponDamage = weapon.Damage; // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-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() |
| } |
| } |
| ~~~ |
| </div> |
| <div class="language-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 |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| var unionType = monster.equippedType(); |
| |
| if (unionType == MyGame.Sample.Equipment.Weapon) { |
| var weapon_name = monster.equipped(new MyGame.Sample.Weapon()).name(); // 'Axe' |
| var weapon_damage = monster.equipped(new MyGame.Sample.Weapon()).damage(); // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| let unionType = monster.equippedType(); |
| |
| if (unionType == MyGame.Sample.Equipment.Weapon) { |
| let weapon_name = monster.equipped(new MyGame.Sample.Weapon()).name(); // 'Axe' |
| let weapon_damage = monster.equipped(new MyGame.Sample.Weapon()).damage(); // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| $union_type = $monster->getEquippedType(); |
| |
| if ($union_type == \MyGame\Sample\Equipment::Weapon) { |
| $weapon_name = $monster->getEquipped(new \MyGame\Sample\Weapon())->getName(); // "Axe" |
| $weapon_damage = $monster->getEquipped(new \MyGame\Sample\Weapon())->getDamage(); // 5 |
| } |
| ~~~ |
| </div> |
| <div class="language-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 |
| } |
| ~~~ |
| </div> |
| <div class="language-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 |
| } |
| ~~~ |
| </div> |
| <div class="language-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 |
| ~~~ |
| </div> |
| <div class="language-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 |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| // 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` is 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(); |
| ~~~ |
| </div> |
| |
| <div class="language-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 |
| } |
| ~~~ |
| </div> |
| |
| ## Mutating FlatBuffers |
| |
| As you saw above, typically once you have created a FlatBuffer, it is read-only |
| from that moment on. There are, however, cases where you have just received a |
| FlatBuffer, and you'd like to modify something about it before sending it on to |
| another recipient. With the above functionality, you'd have to generate an |
| entirely new FlatBuffer, while tracking what you modified in your own data |
| structures. This is inconvenient. |
| |
| For this reason FlatBuffers can also be mutated in-place. While this is great |
| for making small fixes to an existing buffer, you generally want to create |
| buffers from scratch whenever possible, since it is much more efficient and the |
| API is much more general purpose. |
| |
| To get non-const accessors, invoke `flatc` with `--gen-mutable`. |
| |
| Similar to how we read fields using the accessors above, we can now use the |
| mutators like so: |
| |
| <div class="language-cpp"> |
| ~~~{.cpp} |
| auto monster = GetMutableMonster(buffer_pointer); // non-const |
| monster->mutate_hp(10); // Set the table `hp` field. |
| monster->mutable_pos()->mutate_z(4); // Set struct field. |
| monster->mutable_inventory()->Mutate(0, 1); // Set vector element. |
| ~~~ |
| </div> |
| <div class="language-java"> |
| ~~~{.java} |
| Monster monster = Monster.getRootAsMonster(buf); |
| monster.mutateHp(10); // Set table field. |
| monster.pos().mutateZ(4); // Set struct field. |
| monster.mutateInventory(0, 1); // Set vector element. |
| ~~~ |
| </div> |
| <div class="language-kotlin"> |
| ~~~{.kt} |
| val monster = Monster.getRootAsMonster(buf) |
| monster.mutateHp(10) // Set table field. |
| monster.pos!!.mutateZ(4) // Set struct field. |
| monster.mutateInventory(0, 1) // Set vector element. |
| ~~~ |
| </div> |
| <div class="language-csharp"> |
| ~~~{.cs} |
| var monster = Monster.GetRootAsMonster(buf); |
| monster.MutateHp(10); // Set table field. |
| monster.Pos.MutateZ(4); // Set struct field. |
| monster.MutateInventory(0, 1); // Set vector element. |
| ~~~ |
| </div> |
| <div class="language-go"> |
| ~~~{.go} |
| <API for mutating FlatBuffers is not yet available in Go.> |
| ~~~ |
| </div> |
| <div class="language-python"> |
| ~~~{.py} |
| <API for mutating FlatBuffers is not yet available in Python.> |
| ~~~ |
| </div> |
| <div class="language-javascript"> |
| ~~~{.js} |
| <API for mutating FlatBuffers is not yet supported in JavaScript.> |
| ~~~ |
| </div> |
| <div class="language-typescript"> |
| ~~~{.ts} |
| <API for mutating FlatBuffers is not yet supported in TypeScript.> |
| ~~~ |
| </div> |
| <div class="language-php"> |
| ~~~{.php} |
| <API for mutating FlatBuffers is not yet supported in PHP.> |
| ~~~ |
| </div> |
| <div class="language-c"> |
| ~~~{.c} |
| <API for in-place mutating FlatBuffers will not be supported in C |
| (except in-place vector sorting is possible).> |
| ~~~ |
| </div> |
| <div class="language-dart"> |
| ~~~{.dart} |
| <API for mutating FlatBuffers not yet available in Dart.> |
| ~~~ |
| </div> |
| <div class="language-lua"> |
| ~~~{.lua} |
| <API for mutating FlatBuffers is not yet available in Lua.> |
| ~~~ |
| </div> |
| <div class="language-lobster"> |
| ~~~{.lobster} |
| <API for mutating FlatBuffers is not yet available in Lobster.> |
| ~~~ |
| </div> |
| <div class="language-rust"> |
| ~~~{.rs} |
| <API for mutating FlatBuffers is not yet available in Rust.> |
| ~~~ |
| </div> |
| |
| <div class="language-swift"> |
| ~~~{.swift} |
| let monster = Monster.getRootAsMonster(bb: ByteBuffer(bytes: buf)) |
| monster.mutate(hp: 10) // mutates a value in a table |
| monster.pos.mutate(z: 4) // mutates a value in a struct |
| monster.mutate(inventory: 6, at index: 0) // mutates a value in an Scalar array |
| ~~~ |
| </div> |
| |
| We use the somewhat verbose term `mutate` instead of `set` to indicate that this |
| is a special use case, not to be confused with the default way of constructing |
| FlatBuffer data. |
| |
| After the above mutations, you can send on the FlatBuffer to a new recipient |
| without any further work! |
| |
| Note that any `mutate` functions on a table will return a boolean, which is |
| `false` if the field we're trying to set is not present in the buffer. Fields |
| that are not present if they weren't set, or even if they happen to be equal to |
| the default value. For example, in the creation code above, the `mana` |
| field is equal to `150`, which is the default value, so it was never stored in |
| the buffer. Trying to call the corresponding `mutate` method for `mana` on such |
| data will return `false`, and the value won't actually be modified! |
| |
| One way to solve this is to call `ForceDefaults` on a FlatBufferBuilder to |
| force all fields you set to actually be written. This, of course, increases the |
| size of the buffer somewhat, but this may be acceptable for a mutable buffer. |
| |
| If this is not sufficient, other ways of mutating FlatBuffers may be supported |
| in your language through an object based API (`--gen-object-api`) or reflection. |
| See the individual language documents for support. |
| |
| ## Using `flatc` as a JSON Conversion Tool |
| |
| If you are working with C, C++, or Lobster, you can parse JSON at runtime. |
| If your language does not support JSON at the moment, `flatc` may provide an |
| alternative. Using `flatc` is often the preferred method, as it doesn't require you to |
| add any new code to your program. It is also efficient, since you can ship with |
| the binary data. The drawback is that it requires an extra step for your |
| users/developers to perform (although it may be able to be automated |
| as part of your compilation). |
| |
| #### JSON to binary representation |
| |
| Lets say you have a JSON file that describes your monster. In this example, |
| we will use the file `flatbuffers/samples/monsterdata.json`. |
| |
| Here are the contents of the file: |
| |
| ~~~{.json} |
| { |
| pos: { |
| x: 1.0, |
| y: 2.0, |
| z: 3.0 |
| }, |
| hp: 300, |
| name: "Orc", |
| weapons: [ |
| { |
| name: "axe", |
| damage: 100 |
| }, |
| { |
| name: "bow", |
| damage: 90 |
| } |
| ], |
| equipped_type: "Weapon", |
| equipped: { |
| name: "bow", |
| damage: 90 |
| } |
| } |
| ~~~ |
| |
| You can run this file through the `flatc` compiler with the `-b` flag and |
| our `monster.fbs` schema to produce a FlatBuffer binary file. |
| |
| ~~~{.sh} |
| ./../flatc -b monster.fbs monsterdata.json |
| ~~~ |
| |
| The output of this will be a file `monsterdata.bin`, which will contain the |
| FlatBuffer binary representation of the contents from our `.json` file. |
| |
| <div class="language-cpp"> |
| *Note: If you're working in C++, you can also parse JSON at runtime. See the |
| [Use in C++](@ref flatbuffers_guide_use_cpp) section of the Programmer's |
| Guide for more information.* |
| </div> |
| <div class="language-c"> |
| *Note: If you're working in C, the `flatcc --json` (not `flatc`) |
| compiler will generate schema specific high performance json parsers and |
| printers that you can compile and use at runtime. The `flatc` compiler (not |
| `flatcc`) on the other hand, is still useful for general offline json to |
| flatbuffer conversion from a given schema. There are no current plans |
| for `flatcc` to support this.* |
| </div> |
| <div class="language-lobster"> |
| *Note: If you're working in Lobster, you can also parse JSON at runtime. See the |
| [Use in Lobster](@ref flatbuffers_guide_use_lobster) section of the Programmer's |
| Guide for more information.* |
| </div> |
| |
| #### FlatBuffer binary to JSON |
| |
| Converting from a FlatBuffer binary representation to JSON is supported as well: |
| ~~~{.sh} |
| ./../flatc --json --raw-binary monster.fbs -- monsterdata.bin |
| ~~~ |
| This will convert `monsterdata.bin` back to its original JSON representation. |
| You need to pass the corresponding FlatBuffers schema so that flatc knows how to |
| interpret the binary buffer. Since `monster.fbs` does not specify an explicit |
| `file_identifier` for binary buffers, `flatc` needs to be forced into reading |
| the `.bin` file using the `--raw-binary` option. |
| |
| The FlatBuffer binary representation does not explicitly encode default values, |
| therefore they are not present in the resulting JSON unless you specify |
| `--defaults-json`. |
| |
| If you intend to process the JSON with other tools, you may consider switching |
| on `--strict-json` so that identifiers are quoted properly. |
| |
| *Note: The resulting JSON file is not necessarily identical with the original JSON. |
| If the binary representation contains floating point numbers, floats and doubles |
| are rounded to 6 and 12 digits, respectively, in order to represent them as |
| decimals in the JSON document. * |
| |
| ## Advanced Features for Each Language |
| |
| Each language has a dedicated `Use in XXX` page in the Programmer's Guide |
| to cover the nuances of FlatBuffers in that language. |
| |
| For your chosen language, see: |
| |
| <div class="language-cpp"> |
| [Use in C++](@ref flatbuffers_guide_use_cpp) |
| </div> |
| <div class="language-java"> |
| [Use in Java](@ref flatbuffers_guide_use_java) |
| </div> |
| <div class="language-kotlin"> |
| [Use in Kotlin](@ref flatbuffers_guide_use_kotlin) |
| </div> |
| <div class="language-csharp"> |
| [Use in C#](@ref flatbuffers_guide_use_c-sharp) |
| </div> |
| <div class="language-go"> |
| [Use in Go](@ref flatbuffers_guide_use_go) |
| </div> |
| <div class="language-python"> |
| [Use in Python](@ref flatbuffers_guide_use_python) |
| </div> |
| <div class="language-javascript"> |
| [Use in JavaScript](@ref flatbuffers_guide_use_javascript) |
| </div> |
| <div class="language-typescript"> |
| [Use in TypeScript](@ref flatbuffers_guide_use_typescript) |
| </div> |
| <div class="language-php"> |
| [Use in PHP](@ref flatbuffers_guide_use_php) |
| </div> |
| <div class="language-c"> |
| [Use in C](@ref flatbuffers_guide_use_c) |
| </div> |
| <div class="language-dart"> |
| [Use in Dart](@ref flatbuffers_guide_use_dart) |
| </div> |
| <div class="language-lua"> |
| [Use in Lua](@ref flatbuffers_guide_use_lua) |
| </div> |
| <div class="language-lobster"> |
| [Use in Lobster](@ref flatbuffers_guide_use_lobster) |
| </div> |
| <div class="language-rust"> |
| [Use in Rust](@ref flatbuffers_guide_use_rust) |
| </div> |
| <div class="language-swift"> |
| [Use in Swift](@ref flatbuffers_guide_use_swift) |
| </div> |
| <br> |