1# Tutorial 2 3This tutorial provides an example of how to work with FlatBuffers in a variety 4of languages. The following topics will cover all the steps of using FlatBuffers 5in your application. 6 71. Writing a FlatBuffers schema file (`.fbs`). 82. Using the `flatc` compiler to transform the schema into language-specific 9 code. 103. Importing the generated code and libraries into your application. 114. Serializing data into a flatbuffer. 125. Deserializing a flatbuffer. 13 14The tutorial is structured to be language agnostic, with language specifics in 15code blocks providing more context. Additionally, this tries to cover the major 16parts and type system of flatbuffers to give a general overview. It's not 17expected to be an exhaustive list of all features, or provide the best way to do 18things. 19 20## FlatBuffers Schema (`.fbs`) 21 22To start working with FlatBuffers, you first need to create a 23[schema](schema.md) file which defines the format of the data structures you 24wish to serialize. The schema is processed by the `flatc` compiler to generate 25language-specific code that you use in your projects. 26 27The following 28[`monster.fbs`](https://github.com/google/flatbuffers/blob/master/samples/monster.fbs) 29schema will be used for this tutorial. This is part of the FlatBuffers 30[sample code](https://github.com/google/flatbuffers/tree/master/samples) to give 31complete sample binaries demonstrations. 32 33FlatBuffers schema is a Interface Definition Language (IDL) that has a couple 34data structures, see the [schema](schema.md) documentation for a detail 35description. Use the inline code annotations to get a brief synopsis of each 36part of the schema. 37 38```proto title="monster.fbs" linenums="1" 39// Example IDL file for our monster's schema. 40 41namespace MyGame.Sample; //(1)! 42 43enum Color:byte { Red = 0, Green, Blue = 2 } //(2)! 44 45// Optionally add more tables. 46union Equipment { Weapon } //(3)! 47 48struct Vec3 { //(4)! 49 x:float; //(5)! 50 y:float; 51 z:float; 52} 53 54table Monster { //(6)! 55 pos:Vec3; //(7)! 56 mana:short = 150; //(8)! 57 hp:short = 100; 58 name:string; //(9)! 59 friendly:bool = false (deprecated); //(10)! 60 inventory:[ubyte]; //(11)! 61 color:Color = Blue; 62 weapons:[Weapon]; //(12)! 63 equipped:Equipment; //(13)! 64 path:[Vec3]; 65} 66 67table Weapon { 68 name:string; 69 damage:short; 70} 71 72root_type Monster; //(14)! 73``` 74 751. FlatBuffers has support for namespaces to place the generated code into. 76 There is mixed level of support for namespaces (some languages don't have 77 namespaces), but for the C family of languages, it is fully supported. 78 792. Enums definitions can be defined with the backing numerical type. Implicit 80 numbering is supported, so that `Green` would have a value of 1. 81 823. A union represents a single value from a set of possible values. Its 83 effectively an enum (to represent the type actually store) and a value, 84 combined into one. In this example, the union is not very useful, since it 85 only has a single type. 86 874. A struct is a collection of scalar fields with names. It is itself a scalar 88 type, which uses less memory and has faster lookup. However, once a struct is 89 defined, it cannot be changed. Use tables for data structures that can evolve 90 over time. 91 925. FlatBuffers has the standard set of scalar numerical types (`int8`, `int16`, 93 `int32`, `int64`, `uint8`, `uint16`, `uint32`, `uint64`, `float`, `double`), 94 as well as `bool`. Note, scalars are fixed width, `varints` are not 95 supported. 96 976. Tables are the main data structure for grouping data together. It can evolve 98 by adding and deprecating fields over time, while preserving forward and 99 backwards compatibility. 100 1017. A field that happens to be a `struct`. This means the data of the `Vec3` 102 struct will be serialized inline in the table without any need for offset. 103 1048. Fields can be provided a default value. Default values can be configured to 105 not be serialized at all while still providing the default value while 106 deserializing. However, once set, a default value cannot be changed. 107 1089. A `string` field which points to a serialized string external to the table. 109 11010. A deprecated field that is no longer being used. This is used instead of 111 removing the field outright. 112 11311. A `vector` field that points to a vector of bytes. Like `strings`, the 114 vector data is serialized elsewhere and this field just stores an offset to 115 the vector. 116 11712. Vector of `tables` and `structs` are also possible. 118 11913. A field to a `union` type. 120 12114. The root of the flatbuffer is always a `table`. This indicates the type of 122 `table` the "entry" point of the flatbuffer will point to. 123 124## Compiling Schema to Code (`flatc`) 125 126After a schema file is written, you compile it to code in the languages you wish 127to work with. This compilation is done by the [FlatBuffers Compiler](flatc.md) 128(`flatc`) which is one of the binaries built in the repo. 129 130### Building `flatc` 131 132FlatBuffers uses [`cmake`](https://cmake.org/) to build projects files for your 133environment. 134 135=== "Unix" 136 137 ```sh 138 cmake -G "Unix Makefiles" 139 make flatc 140 ``` 141 142=== "Windows" 143 144 ```sh 145 cmake -G "Visual Studio 17 2022" 146 msbuild.exe FlatBuffers.sln 147 ``` 148 149See the documentation on [building](building.md) for more details and other 150environments. Some languages also include a prebuilt `flatc` via their package 151manager. 152 153### Compiling Schema 154 155To compile the schema, invoke `flatc` with the schema file and the language 156flags you wish to generate code for. This compilation will generate files that 157you include in your application code. These files provide convenient APIs for 158serializing and deserializing the flatbuffer binary data. 159 160=== "C++" 161 162 ```sh 163 flatc --cpp monster.fbs 164 ``` 165 166=== "C" 167 168 !!! Note 169 170 If you're working in C, you need to use the separate project 171 [FlatCC](https://github.com/dvidelabs/flatcc) which contains a schema 172 compiler and runtime library in C for C. See 173 [flatcc build instructions](https://github.com/dvidelabs/flatcc#building). 174 175 Please be aware of the difference between `flatc` and `flatcc` tools. 176 177 ```sh 178 cd flatcc 179 mkdir -p build/tmp/samples/monster 180 bin/flatcc -a -o build/tmp/samples/monster samples/monster/monster.fbs 181 # or just 182 flatcc/samples/monster/build.sh 183 ``` 184 185=== "C#" 186 187 ```sh 188 flatc --csharp monster.fbs 189 ``` 190 191=== "Dart" 192 193 ```sh 194 flatc --dart monster.fbs 195 ``` 196 197=== "Go" 198 199 ```sh 200 flatc --go monster.fbs 201 ``` 202 203=== "Java" 204 205 ```sh 206 flatc --java monster.fbs 207 ``` 208 209=== "JavaScript" 210 211 ```sh 212 flatc --js monster.fbs 213 ``` 214 215=== "Kotlin" 216 217 ```sh 218 flatc --kotlin monster.fbs 219 ``` 220 221=== "Lobster" 222 223 ```sh 224 flatc --lobster monster.fbs 225 ``` 226 227=== "Lua" 228 229 ```sh 230 flatc --lua monster.fbs 231 ``` 232 233=== "PHP" 234 235 ```sh 236 flatc --php monster.fbs 237 ``` 238 239=== "Python" 240 241 ```sh 242 flatc --python monster.fbs 243 ``` 244 245=== "Rust" 246 247 ```sh 248 flatc --rust monster.fbs 249 ``` 250 251=== "Swift" 252 253 ```sh 254 flatc --swift monster.fbs 255 ``` 256 257=== "TypeScript" 258 259 ```sh 260 flatc --ts monster.fbs 261 ``` 262 263You can deserialize flatbuffers in languages that differ from the language that 264serialized it. For purpose of this tutorial, we assume one language is used for 265both serializing and deserializing. 266 267## Application Integration 268 269The generated files are then included in your project to be built into your 270application. This is heavily dependent on your build system and language, but 271generally involves two things: 272 2731. Importing the generated code. 2742. Importing the "runtime" libraries. 275 276=== "C++" 277 278 ```c++ 279 #include "monster_generated.h" // This was generated by `flatc` 280 #include "flatbuffers.h" // The runtime library for C++ 281 282 // Simplifies naming in the following examples. 283 using namespace MyGame::Sample; // Specified in the schema. 284 ``` 285 286=== "C" 287 288 ```c 289 #include "monster_builder.h" // Generated by `flatcc`. 290 291 // Convenient namespace macro to manage long namespace prefix. 292 #undef ns 293 // Specified in the schema. 294 #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) 295 296 // A helper to simplify creating vectors from C-arrays. 297 #define c_vec_len(V) (sizeof(V)/sizeof((V)[0])) 298 ``` 299 300=== "C#" 301 302 ```c# 303 using Google.FlatBuffers; // The runtime library for C# 304 using MyGame.Sample; // The generated files from `flatc` 305 ``` 306 307=== "Dart" 308 309 ```dart 310 import 'package:flat_buffers/flat_buffers.dart' as fb; 311 312 // Generated by `flatc`. 313 import 'monster_my_game.sample_generated.dart' as myGame; 314 ``` 315 316=== "Go" 317 318 ```go 319 import ( 320 flatbuffers "github.com/google/flatbuffers/go" 321 sample "MyGame/Sample" 322 ) 323 ``` 324 325=== "Java" 326 327 ```java 328 import MyGame.Sample.*; //The `flatc` generated files. (Monster, Vec3, etc.) 329 330 import com.google.flatbuffers.FlatBufferBuilder; 331 ``` 332 333=== "JavaScript" 334 335 ```javascript 336 // The following code is an example - use your desired module flavor by 337 // transpiling from TS. 338 var flatbuffers = require('/js/flatbuffers').flatbuffers; 339 var MyGame = require('./monster_generated').MyGame; // Generated by `flatc`. 340 341 //------------------------------------------------------------------------// 342 343 // The following code is for browser-based HTML/JavaScript. Use the above 344 // code for JavaScript module loaders (e.g. Node.js). 345 <script src="../js/flatbuffers.js"></script> 346 <script src="monster_generated.js"></script> // Generated by `flatc`. 347 ``` 348 349=== "Kotlin" 350 351 ```kotlin 352 import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.) 353 354 import com.google.flatbuffers.FlatBufferBuilder 355 ``` 356 357=== "Lobster" 358 359 ```lobster 360 import from "../lobster/" // Where to find flatbuffers.lobster 361 import monster_generated 362 ``` 363 364=== "Lua" 365 366 ```lua 367 -- require the flatbuffers module 368 local flatbuffers = require("flatbuffers") 369 370 -- require the generated files from `flatc`. 371 local color = require("MyGame.Sample.Color") 372 local equipment = require("MyGame.Sample.Equipment") 373 local monster = require("MyGame.Sample.Monster") 374 local vec3 = require("MyGame.Sample.Vec3") 375 local weapon = require("MyGame.Sample.Weapon") 376 ``` 377 378=== "PHP" 379 380 ```php 381 // It is recommended that your use PSR autoload when using FlatBuffers in 382 // PHP. Here is an example from `SampleBinary.php`: 383 function __autoload($class_name) { 384 // The last segment of the class name matches the file name. 385 $class = substr($class_name, strrpos($class_name, "\\") + 1); 386 // `flatbuffers` root. 387 $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); 388 389 // Contains the `*.php` files for the FlatBuffers library and the `flatc` 390 // generated files. 391 $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")), 392 join(DIRECTORY_SEPARATOR, 393 array($root_dir, "samples", "MyGame", "Sample"))); 394 foreach ($paths as $path) { 395 $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php")); 396 if (file_exists($file)) { 397 require($file); 398 break; 399 } 400 } 401 } 402 ``` 403 404=== "Python" 405 406 ```py 407 import flatbuffers 408 409 # Generated by `flatc`. 410 import MyGame.Sample.Color 411 import MyGame.Sample.Equipment 412 import MyGame.Sample.Monster 413 import MyGame.Sample.Vec3 414 import MyGame.Sample.Weapon 415 ``` 416 417=== "Rust" 418 419 ```rust 420 // import the flatbuffers runtime library 421 extern crate flatbuffers; 422 423 // import the generated code 424 #[allow(dead_code, unused_imports)] 425 #[path = "./monster_generated.rs"] 426 mod monster_generated; 427 pub use monster_generated::my_game::sample::{root_as_monster, 428 Color, Equipment, 429 Monster, MonsterArgs, 430 Vec3, 431 Weapon, WeaponArgs}; 432 ``` 433 434=== "Swift" 435 436 ```swift 437 /** 438 // make sure that monster_generated.swift is included in your project 439 */ 440 import Flatbuffers 441 442 // typealiases for convenience 443 typealias Monster = MyGame1_Sample_Monster 444 typealias Weapon = MyGame1_Sample_Weapon 445 typealias Color = MyGame1_Sample_Color 446 typealias Vec3 = MyGame1_Sample_Vec3 447 ``` 448 449=== "TypeScript" 450 451 ```ts 452 // note: import flatbuffers with your desired import method 453 454 import { MyGame } from './monster_generated'; 455 ``` 456 457For some languages the runtime libraries are just code files you compile into 458your application. While other languages provide packaged libraries via their 459package managers. 460 461The generated files include APIs for both serializing and deserializing 462FlatBuffers. So these steps are identical for both the consumer and producer. 463 464## Serialization 465 466Once all the files are included into your application, it's time to start 467serializing some data! 468 469With FlatBuffers, serialization can be a bit verbose, since each piece of data 470must be serialized separately and in a particular order (depth-first, pre-order 471traversal). The verbosity allows efficient serialization without heap 472allocations, at the cost of more complex serialization APIs. 473 474For example, any reference type (e.g. `table`, `vector`, `string`) must be 475serialized before it can be referred to by other structures. So its typical to 476serialize the data from leaf to root node, as will be shown below. 477 478### FlatBufferBuilder 479 480Most languages use a Builder object for managing the binary array that the data 481is serialized into. It provides an API for serializing data, as well as keeps 482track of some internal state. The generated code wraps methods on the Builder 483object to provide an API tailored to the schema. 484 485First instantiate a Builder (or reuse an existing one) and specify some memory 486for it. The builder will automatically resize the backing buffer when necessary. 487 488=== "C++" 489 490 ```c++ 491 // Construct a Builder with 1024 byte backing array. 492 flatbuffers::FlatBufferBuilder builder(1024); 493 ``` 494 495=== "C" 496 497 ```c 498 flatcc_builder_t builder, *B; 499 B = &builder; 500 // Initialize the builder object. 501 flatcc_builder_init(B); 502 ``` 503 504=== "C#" 505 506 ```c# 507 // Construct a Builder with 1024 byte backing array. 508 FlatBufferBuilder builder = new FlatBufferBuilder(1024); 509 ``` 510 511=== "Dart" 512 513 ```dart 514 // Construct a Builder with 1024 byte backing array. 515 var builder = new fb.Builder(initialSize: 1024); 516 ``` 517 518=== "Go" 519 520 ```go 521 // Construct a Builder with 1024 byte backing array. 522 builder := flatbuffers.NewBuilder(1024) 523 ``` 524 525=== "Java" 526 527 ```java 528 // Construct a Builder with 1024 byte backing array. 529 FlatBufferBuilder builder = new FlatBufferBuilder(1024); 530 ``` 531 532=== "JavaScript" 533 534 ```javascript 535 // Construct a Builder with 1024 byte backing array. 536 var builder = new flatbuffers.Builder(1024); 537 ``` 538 539=== "Kotlin" 540 541 ```kotlin 542 // Construct a Builder with 1024 byte backing array. 543 val builder = FlatBufferBuilder(1024) 544 ``` 545 546=== "Lobster" 547 548 ```lobster 549 // Construct a Builder with 1024 byte backing array. 550 let builder = flatbuffers_builder {} 551 ``` 552 553=== "Lua" 554 555 ```lua 556 -- Construct a Builder with 1024 byte backing array. 557 local builder = flatbuffers.Builder(1024) 558 ``` 559 560=== "PHP" 561 562 ```php 563 // Construct a Builder with 1024 byte backing array. 564 $builder = new Google\FlatBuffers\FlatbufferBuilder(1024); 565 ``` 566 567=== "Python" 568 569 ```py 570 # Construct a Builder with 1024 byte backing array. 571 builder = flatbuffers.Builder(1024) 572 ``` 573 574=== "Rust" 575 576 ```rust 577 // Construct a Builder with 1024 byte backing array. 578 let mut builder = flatbuffers::FlatBufferBuilder::with_capacity(1024); 579 ``` 580 581=== "Swift" 582 583 ```swift 584 // Construct a Builder with 1024 byte backing array. 585 let builder = FlatBufferBuilder(initialSize: 1024) 586 ``` 587 588=== "TypeScript" 589 590 ```ts 591 // Construct a Builder with 1024 byte backing array. 592 let builder = new flatbuffers.Builder(1024); 593 ``` 594 595Once a Builder is available, data can be serialized to it via the Builder APIs 596and the generated code. 597 598### Serializing Data 599 600In this tutorial, we are building `Monsters` and `Weapons` for a computer game. 601A `Weapon` is represented by a flatbuffer `table` with some fields. One field is 602the `name` field, which is type `string` and the other `damage` field is a 603numerical scalar. 604 605```c title="monster.fbs" linenums="28" 606table Weapon { 607 name:string; 608 damage:short; 609} 610``` 611 612#### Strings 613 614Since `string` is a reference type, we first need to serialize it before 615assigning it to the `name` field of the `Weapon` table. This is done through the 616Builder `CreateString` method. 617 618Let's serialize two weapon strings. 619 620=== "C++" 621 622 ```c++ 623 flatbuffers::Offset<String> weapon_one_name = builder.CreateString("Sword"); 624 flatbuffers::Offset<String> weapon_two_name = builder.CreateString("Axe"); 625 ``` 626 627 `flatbuffers::Offset<>` is a just a "typed" integer tied to a particular 628 type. It helps make the numerical offset more strongly typed. 629 630=== "C" 631 632 ```c 633 flatbuffers_string_ref_t weapon_one_name 634 = flatbuffers_string_create_str(B, "Sword"); 635 flatbuffers_string_ref_t weapon_two_name 636 = flatbuffers_string_create_str(B, "Axe"); 637 ``` 638 639=== "C#" 640 641 ```c# 642 Offset<String> weaponOneName = builder.CreateString("Sword"); 643 Offset<String> weaponTwoName = builder.CreateString("Axe"); 644 ``` 645 646=== "Dart" 647 648 ```dart 649 final int weaponOneName = builder.writeString("Sword"); 650 final int weaponTwoName = builder.writeString("Axe"); 651 ``` 652 653=== "Go" 654 655 ```go 656 weaponOne := builder.CreateString("Sword") 657 weaponTwo := builder.CreateString("Axe") 658 ``` 659 660=== "Java" 661 662 ```java 663 int weaponOneName = builder.createString("Sword") 664 int weaponTwoName = builder.createString("Axe"); 665 ``` 666 667=== "JavaScript" 668 669 ```javascript 670 var weaponOne = builder.createString('Sword'); 671 var weaponTwo = builder.createString('Axe'); 672 ``` 673 674=== "Kotlin" 675 676 ```kotlin 677 val weaponOneName = builder.createString("Sword") 678 val weaponTwoName = builder.createString("Axe") 679 ``` 680 681=== "Lobster" 682 683 ```lobster 684 let weapon_one = builder.CreateString("Sword") 685 let weapon_two = builder.CreateString("Axe") 686 ``` 687 688=== "Lua" 689 690 ```lua 691 local weaponOne = builder:CreateString("Sword") 692 local weaponTwo = builder:CreateString("Axe") 693 ``` 694 695=== "PHP" 696 697 ```php 698 $weapon_one_name = $builder->createString("Sword") 699 $weapon_two_name = $builder->createString("Axe"); 700 ``` 701 702=== "Python" 703 704 ```py 705 weapon_one = builder.CreateString('Sword') 706 weapon_two = builder.CreateString('Axe') 707 ``` 708 709=== "Rust" 710 711 ```rust 712 let weapon_one_name = builder.create_string("Sword"); 713 let weapon_two_name = builder.create_string("Axe"); 714 ``` 715 716=== "Swift" 717 718 ```swift 719 let weapon1Name = builder.create(string: "Sword") 720 let weapon2Name = builder.create(string: "Axe") 721 ``` 722 723=== "TypeScript" 724 725 ```ts 726 let weaponOne = builder.createString('Sword'); 727 let weaponTwo = builder.createString('Axe'); 728 ``` 729 730 731This performs the actual serialization (the string data is copied into the 732backing array) and returns an offset. Think of the offset as a handle to that 733reference. It's just a "typed" numerical offset to where that data resides in 734the buffer. 735 736#### Tables 737 738Now that we have some names serialized, we can serialize the `Weapon` tables. 739Here we will use one of the generated helper functions that was emitted by 740`flatc`. The `CreateWeapon` function takes in the Builder object, as well as the 741offset to the weapon's name and a numerical value for the damage field. 742 743=== "C++" 744 745 ```c++ 746 short weapon_one_damage = 3; 747 short weapon_two_damage = 5; 748 749 // Use the `CreateWeapon()` shortcut to create Weapons with all the fields 750 // set. 751 flatbuffers::Offset<Weapon> sword = 752 CreateWeapon(builder, weapon_one_name, weapon_one_damage); 753 flatbuffers::Offset<Weapon> axe = 754 CreateWeapon(builder, weapon_two_name, weapon_two_damage); 755 ``` 756 757=== "C" 758 759 ```c 760 uint16_t weapon_one_damage = 3; 761 uint16_t weapon_two_damage = 5; 762 763 ns(Weapon_ref_t) sword 764 = ns(Weapon_create(B, weapon_one_name, weapon_one_damage)); 765 ns(Weapon_ref_t) axe 766 = ns(Weapon_create(B, weapon_two_name, weapon_two_damage)); 767 ``` 768 769=== "C#" 770 771 ```c# 772 short weaponOneDamage = 3; 773 short weaponTwoDamage = 5; 774 775 // Use the `CreateWeapon()` helper function to create the weapons, since we 776 // set every field. 777 Offset<Weapon> sword = 778 Weapon.CreateWeapon(builder, weaponOneName, weaponOneDamage); 779 Offset<Weapon> axe = 780 Weapon.CreateWeapon(builder, weaponTwoName, weaponTwoDamage); 781 ``` 782 783=== "Dart" 784 785 ```dart 786 final int weaponOneDamage = 3; 787 final int weaponTwoDamage = 5; 788 789 final swordBuilder = new myGame.WeaponBuilder(builder) 790 ..begin() 791 ..addNameOffset(weaponOneName) 792 ..addDamage(weaponOneDamage); 793 final int sword = swordBuilder.finish(); 794 795 final axeBuilder = new myGame.WeaponBuilder(builder) 796 ..begin() 797 ..addNameOffset(weaponTwoName) 798 ..addDamage(weaponTwoDamage); 799 final int axe = axeBuilder.finish(); 800 ``` 801 802 Note, as an alternative, the previous steps can be combined using the 803 generative Builder classes. 804 805 ```dart 806 final myGame.WeaponBuilder sword = new myGame.WeaponObjectBuilder( 807 name: "Sword", 808 damage: 3, 809 ); 810 811 final myGame.WeaponBuilder axe = new myGame.WeaponObjectBuilder( 812 name: "Axe", 813 damage: 5, 814 ); 815 ``` 816 817=== "Go" 818 819 ```go 820 // Create the first `Weapon` ("Sword"). 821 sample.WeaponStart(builder) 822 sample.WeaponAddName(builder, weaponOne) 823 sample.WeaponAddDamage(builder, 3) 824 sword := sample.WeaponEnd(builder) 825 826 // Create the second `Weapon` ("Axe"). 827 sample.WeaponStart(builder) 828 sample.WeaponAddName(builder, weaponTwo) 829 sample.WeaponAddDamage(builder, 5) 830 axe := sample.WeaponEnd(builder) 831 ``` 832 833=== "Java" 834 835 ```java 836 short weaponOneDamage = 3; 837 short weaponTwoDamage = 5; 838 839 // Use the `createWeapon()` helper function to create the weapons, since we 840 // set every field. 841 int sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage); 842 int axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage); 843 ``` 844 845=== "JavaScript" 846 847 ```javascript 848 // Create the first `Weapon` ('Sword'). 849 MyGame.Sample.Weapon.startWeapon(builder); 850 MyGame.Sample.Weapon.addName(builder, weaponOne); 851 MyGame.Sample.Weapon.addDamage(builder, 3); 852 var sword = MyGame.Sample.Weapon.endWeapon(builder); 853 854 // Create the second `Weapon` ('Axe'). 855 MyGame.Sample.Weapon.startWeapon(builder); 856 MyGame.Sample.Weapon.addName(builder, weaponTwo); 857 MyGame.Sample.Weapon.addDamage(builder, 5); 858 var axe = MyGame.Sample.Weapon.endWeapon(builder); 859 ``` 860 861=== "Kotlin" 862 863 ```kotlin 864 val weaponOneDamage: Short = 3; 865 val weaponTwoDamage: Short = 5; 866 867 // Use the `createWeapon()` helper function to create the weapons, since we 868 // set every field. 869 val sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage) 870 val axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage) 871 ``` 872 873=== "Lobster" 874 875 ```lobster 876 let sword = MyGame_Sample_WeaponBuilder { b } 877 .start() 878 .add_name(weapon_one) 879 .add_damage(3) 880 .end() 881 882 let axe = MyGame_Sample_WeaponBuilder { b } 883 .start() 884 .add_name(weapon_two) 885 .add_damage(5) 886 .end() 887 ``` 888 889=== "Lua" 890 891 ```lua 892 -- Create the first 'Weapon' 893 weapon.Start(builder) 894 weapon.AddName(builder, weaponOne) 895 weapon.AddDamage(builder, 3) 896 local sword = weapon.End(builder) 897 898 -- Create the second 'Weapon' 899 weapon.Start(builder) 900 weapon.AddName(builder, weaponTwo) 901 weapon.AddDamage(builder, 5) 902 local axe = weapon.End(builder) 903 ``` 904 905=== "PHP" 906 907 ```php 908 $sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one_name, 3); 909 $axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two_name, 5); 910 ``` 911 912=== "Python" 913 914 ```py 915 # Create the first `Weapon` ('Sword'). 916 MyGame.Sample.Weapon.Start(builder) 917 MyGame.Sample.Weapon.AddName(builder, weapon_one) 918 MyGame.Sample.Weapon.AddDamage(builder, 3) 919 sword = MyGame.Sample.Weapon.End(builder) 920 921 # Create the second `Weapon` ('Axe'). 922 MyGame.Sample.Weapon.Start(builder) 923 MyGame.Sample.Weapon.AddName(builder, weapon_two) 924 MyGame.Sample.Weapon.AddDamage(builder, 5) 925 axe = MyGame.Sample.Weapon.End(builder) 926 ``` 927 928=== "Rust" 929 930 ```rust 931 // Use the `Weapon::create` shortcut to create Weapons with named field 932 // arguments. 933 let sword = Weapon::create(&mut builder, &WeaponArgs{ 934 name: Some(weapon_one_name), 935 damage: 3, 936 }); 937 let axe = Weapon::create(&mut builder, &WeaponArgs{ 938 name: Some(weapon_two_name), 939 damage: 5, 940 }); 941 ``` 942 943=== "Swift" 944 945 ```swift 946 // start creating the weapon by calling startWeapon 947 let weapon1Start = Weapon.startWeapon(&builder) 948 Weapon.add(name: weapon1Name, &builder) 949 Weapon.add(damage: 3, &builder) 950 // end the object by passing the start point for the weapon 1 951 let sword = Weapon.endWeapon(&builder, start: weapon1Start) 952 953 let weapon2Start = Weapon.startWeapon(&builder) 954 Weapon.add(name: weapon2Name, &builder) 955 Weapon.add(damage: 5, &builder) 956 let axe = Weapon.endWeapon(&builder, start: weapon2Start) 957 ``` 958 959=== "TypeScript" 960 961 ```ts 962 // Create the first `Weapon` ('Sword'). 963 MyGame.Sample.Weapon.startWeapon(builder); 964 MyGame.Sample.Weapon.addName(builder, weaponOne); 965 MyGame.Sample.Weapon.addDamage(builder, 3); 966 let sword = MyGame.Sample.Weapon.endWeapon(builder); 967 968 // Create the second `Weapon` ('Axe'). 969 MyGame.Sample.Weapon.startWeapon(builder); 970 MyGame.Sample.Weapon.addName(builder, weaponTwo); 971 MyGame.Sample.Weapon.addDamage(builder, 5); 972 let axe = MyGame.Sample.Weapon.endWeapon(builder); 973 ``` 974 975 976The generated functions from `flatc`, like `CreateWeapon`, are just composed of 977various Builder API methods. So its not required to use the generated code, but 978it does make things much simpler and compact. 979 980Just like the `CreateString` methods, the table serialization functions return 981an offset to the location of the serialized `Weapon` table. 982 983Now that we have some `Weapons` serialized, we can serialize a `Monster`. 984Looking at the schema again, this table has a lot more fields of various types. 985Some of these need to be serialized beforehand, for the same reason we 986serialized the name string before the weapon table. 987 988!!! note inline end 989 990 There is no prescribed ordering of which table fields must be serialized 991 first, you could serialize in any order you want. You can also not serialize 992 a field to provide a `null` value, this is done by using an 0 offset value. 993 994```c title="monster.fbs" linenums="15" 995table Monster { 996 pos:Vec3; 997 mana:short = 150; 998 hp:short = 100; 999 name:string; 1000 friendly:bool = false (deprecated); 1001 inventory:[ubyte]; 1002 color:Color = Blue; 1003 weapons:[Weapon]; 1004 equipped:Equipment; 1005 path:[Vec3]; 1006} 1007``` 1008 1009#### Vectors 1010 1011The `weapons` field is a `vector` of `Weapon` tables. We already have two 1012`Weapons` serialized, so we just need to serialize a `vector` of those offsets. 1013The Builder provides multiple ways to create `vectors`. 1014 1015=== "C++" 1016 1017 ```c++ 1018 // Create a std::vector of the offsets we had previous made. 1019 std::vector<flatbuffers::Offset<Weapon>> weapons_vector; 1020 weapons_vector.push_back(sword); 1021 weapons_vector.push_back(axe); 1022 1023 // Then serialize that std::vector into the buffer and again get an Offset 1024 // to that vector. Use `auto` here since the full type is long, and it just 1025 // a "typed" number. 1026 auto weapons = builder.CreateVector(weapons_vector); 1027 ``` 1028 1029=== "C" 1030 1031 ```c 1032 // We use the internal builder stack to implement a dynamic vector. 1033 ns(Weapon_vec_start(B)); 1034 ns(Weapon_vec_push(B, sword)); 1035 ns(Weapon_vec_push(B, axe)); 1036 ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B)); 1037 ``` 1038 1039=== "C#" 1040 1041 ```c# 1042 // Create an array of the two weapon offsets. 1043 var weaps = new Offset<Weapon>[2]; 1044 weaps[0] = sword; 1045 weaps[1] = axe; 1046 1047 // Pass the `weaps` array into the `CreateWeaponsVector()` method to create 1048 // a FlatBuffer vector. 1049 var weapons = Monster.CreateWeaponsVector(builder, weaps); 1050 ``` 1051 1052=== "Dart" 1053 1054 ```dart 1055 // If using the Builder classes, serialize the `[sword,axe]` 1056 final weapons = builder.writeList([sword, axe]); 1057 1058 // If using the ObjectBuilders, just create an array from the two `Weapon`s 1059 final List<myGame.WeaponBuilder> weaps = [sword, axe]; 1060 ``` 1061 1062=== "Go" 1063 1064 ```go 1065 // Create a FlatBuffer vector and prepend the weapons. 1066 // Note: Since we prepend the data, prepend them in reverse order. 1067 sample.MonsterStartWeaponsVector(builder, 2) 1068 builder.PrependUOffsetT(axe) 1069 builder.PrependUOffsetT(sword) 1070 weapons := builder.EndVector(2) 1071 ``` 1072 1073=== "Java" 1074 1075 ```java 1076 // Place the two weapons into an array, and pass it to the 1077 // `createWeaponsVector()` method to create a FlatBuffer vector. 1078 int[] weaps = new int[2]; 1079 weaps[0] = sword; 1080 weaps[1] = axe; 1081 1082 // Pass the `weaps` array into the `createWeaponsVector()` method to create 1083 // a FlatBuffer vector. 1084 int weapons = Monster.createWeaponsVector(builder, weaps); 1085 ``` 1086 1087=== "JavaScript" 1088 1089 ```javascript 1090 // Create an array from the two `Weapon`s and pass it to the 1091 // `createWeaponsVector()` method to create a FlatBuffer vector. 1092 var weaps = [sword, axe]; 1093 var weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps); 1094 ``` 1095 1096=== "Kotlin" 1097 1098 ```kotlin 1099 // Place the two weapons into an array, and pass it to the 1100 // `createWeaponsVector()` method to create a FlatBuffer vector. 1101 val weaps = intArrayOf(sword, axe) 1102 1103 // Pass the `weaps` array into the `createWeaponsVector()` method to create 1104 // a FlatBuffer vector. 1105 val weapons = Monster.createWeaponsVector(builder, weaps) 1106 ``` 1107 1108=== "Lobster" 1109 1110 ```lobster 1111 let weapons = builder.MyGame_Sample_MonsterCreateWeaponsVector([sword, axe]) 1112 ``` 1113 1114=== "Lua" 1115 1116 ```lua 1117 -- Create a FlatBuffer vector and prepend the weapons. 1118 -- Note: Since we prepend the data, prepend them in reverse order. 1119 monster.StartWeaponsVector(builder, 2) 1120 builder:PrependUOffsetTRelative(axe) 1121 builder:PrependUOffsetTRelative(sword) 1122 local weapons = builder:EndVector(2) 1123 ``` 1124 1125=== "PHP" 1126 1127 ```php 1128 // Create an array from the two `Weapon`s and pass it to the 1129 // `CreateWeaponsVector()` method to create a FlatBuffer vector. 1130 $weaps = array($sword, $axe); 1131 $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps); 1132 ``` 1133 1134=== "Python" 1135 1136 ```py 1137 # Create a FlatBuffer vector and prepend the weapons. 1138 # Note: Since we prepend the data, prepend them in reverse order. 1139 MyGame.Sample.Monster.StartWeaponsVector(builder, 2) 1140 builder.PrependUOffsetTRelative(axe) 1141 builder.PrependUOffsetTRelative(sword) 1142 weapons = builder.EndVector() 1143 ``` 1144 1145=== "Rust" 1146 1147 ```rust 1148 // Create a FlatBuffer `vector` that contains offsets to the sword and axe 1149 // we created above. 1150 let weapons = builder.create_vector(&[sword, axe]); 1151 ``` 1152 1153=== "Swift" 1154 1155 ```swift 1156 // Create a FlatBuffer `vector` that contains offsets to the sword and axe 1157 // we created above. 1158 let weaponsOffset = builder.createVector(ofOffsets: [sword, axe]) 1159 ``` 1160 1161=== "TypeScript" 1162 1163 ```ts 1164 // Create an array from the two `Weapon`s and pass it to the 1165 // `createWeaponsVector()` method to create a FlatBuffer vector. 1166 let weaps = [sword, axe]; 1167 let weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps); 1168 ``` 1169 1170 1171While we are at it, let us serialize the other two vector fields: the 1172`inventory` field is just a vector of scalars, and the `path` field is a vector 1173of structs (which are scalar data as well). So these vectors can be serialized a 1174bit more directly. 1175 1176=== "C++" 1177 1178 ```c++ 1179 // Create a `vector` representing the inventory of the Orc. Each number 1180 // could correspond to an item that can be claimed after he is slain. 1181 unsigned char treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 1182 flatbuffers::Offset<flatbuffers::Vector<unsigned char>> inventory = 1183 builder.CreateVector(treasure, 10); 1184 1185 // Construct an array of two `Vec3` structs. 1186 Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) }; 1187 1188 // Serialize it as a vector of structs. 1189 flatbuffers::Offset<flatbuffers::Vector<Vec3>> path = 1190 builder.CreateVectorOfStructs(points, 2); 1191 ``` 1192 1193=== "C" 1194 1195 ```c 1196 // Create a `vector` representing the inventory of the Orc. Each number 1197 // could correspond to an item that can be claimed after he is slain. 1198 uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 1199 flatbuffers_uint8_vec_ref_t inventory; 1200 // `c_vec_len` is the convenience macro we defined earlier. 1201 inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure)); 1202 ``` 1203 1204=== "C#" 1205 1206 ```c# 1207 // Create a `vector` representing the inventory of the Orc. Each number 1208 // could correspond to an item that can be claimed after he is slain. 1209 // Note: Since we prepend the bytes, this loop iterates in reverse order. 1210 Monster.StartInventoryVector(builder, 10); 1211 for (int i = 9; i >= 0; i--) 1212 { 1213 builder.AddByte((byte)i); 1214 } 1215 Offset<Vector<byte>> inventory = builder.EndVector(); 1216 1217 // Start building a path vector of length 2. 1218 Monster.StartPathVector(fbb, 2); 1219 1220 // Serialize the individual Vec3 structs 1221 Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f); 1222 Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f); 1223 1224 // End the vector to get the offset 1225 Offset<Vector<Vec3>> path = fbb.EndVector(); 1226 ``` 1227 1228=== "Dart" 1229 1230 ```dart 1231 // Create a list representing the inventory of the Orc. Each number 1232 // could correspond to an item that can be claimed after he is slain. 1233 final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 1234 final inventory = builder.writeListUint8(treasure); 1235 1236 // Using the Builder classes, you can write a list of structs like so: 1237 // Note that the intended order should be reversed if order is important. 1238 final vec3Builder = new myGame.Vec3Builder(builder); 1239 vec3Builder.finish(4.0, 5.0, 6.0); 1240 vec3Builder.finish(1.0, 2.0, 3.0); 1241 final int path = builder.endStructVector(2); // the length of the vector 1242 ``` 1243 1244=== "Go" 1245 1246 ```go 1247 // Create a `vector` representing the inventory of the Orc. Each number 1248 // could correspond to an item that can be claimed after he is slain. 1249 // Note: Since we prepend the bytes, this loop iterates in reverse. 1250 sample.MonsterStartInventoryVector(builder, 10) 1251 for i := 9; i >= 0; i-- { 1252 builder.PrependByte(byte(i)) 1253 } 1254 inv := builder.EndVector(10) 1255 1256 sample.MonsterStartPathVector(builder, 2) 1257 sample.CreateVec3(builder, 1.0, 2.0, 3.0) 1258 sample.CreateVec3(builder, 4.0, 5.0, 6.0) 1259 path := builder.EndVector(2) 1260 ``` 1261 1262=== "Java" 1263 1264 ```java 1265 // Create a `vector` representing the inventory of the Orc. Each number 1266 // could correspond to an item that can be claimed after he is slain. 1267 byte[] treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 1268 int inv = Monster.createInventoryVector(builder, treasure); 1269 1270 Monster.startPathVector(fbb, 2); 1271 Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f); 1272 Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f); 1273 int path = fbb.endVector(); 1274 ``` 1275 1276=== "JavaScript" 1277 1278 ```javascript 1279 // Create a `vector` representing the inventory of the Orc. Each number 1280 // could correspond to an item that can be claimed after he is slain. 1281 var treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 1282 var inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure); 1283 1284 MyGame.Sample.Monster.startPathVector(builder, 2); 1285 MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0); 1286 MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0); 1287 var path = builder.endVector(); 1288 ``` 1289 1290=== "Kotlin" 1291 1292 ```kotlin 1293 // Create a `vector` representing the inventory of the Orc. Each number 1294 // could correspond to an item that can be claimed after he is slain. 1295 val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 1296 val inv = Monster.createInventoryVector(builder, treasure) 1297 1298 Monster.startPathVector(fbb, 2) 1299 Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f) 1300 Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f) 1301 val path = fbb.endVector() 1302 ``` 1303 1304=== "Lobster" 1305 1306 ```lobster 1307 // Inventory. 1308 let inv = builder.MyGame_Sample_MonsterCreateInventoryVector(map(10): _) 1309 1310 builder.MyGame_Sample_MonsterStartPathVector(2) 1311 builder.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0) 1312 builder.MyGame_Sample_CreateVec3(4.0, 5.0, 6.0) 1313 let path = builder.EndVector(2) 1314 ``` 1315 1316=== "Lua" 1317 1318 ```lua 1319 -- Create a `vector` representing the inventory of the Orc. Each number 1320 -- could correspond to an item that can be claimed after he is slain. 1321 -- Note: Since we prepend the bytes, this loop iterates in reverse. 1322 monster.StartInventoryVector(builder, 10) 1323 for i=10,1,-1 do 1324 builder:PrependByte(i) 1325 end 1326 local inv = builder:EndVector(10) 1327 1328 -- Create a FlatBuffer vector and prepend the path locations. 1329 -- Note: Since we prepend the data, prepend them in reverse order. 1330 monster.StartPathVector(builder, 2) 1331 vec3.CreateVec3(builder, 1.0, 2.0, 3.0) 1332 vec3.CreateVec3(builder, 4.0, 5.0, 6.0) 1333 local path = builder:EndVector(2) 1334 ``` 1335 1336=== "PHP" 1337 1338 ```php 1339 // Create a `vector` representing the inventory of the Orc. Each number 1340 // could correspond to an item that can be claimed after he is slain. 1341 $treasure = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); 1342 $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure); 1343 1344 \MyGame\Example\Monster::StartPathVector($builder, 2); 1345 \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0); 1346 \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0); 1347 $path = $builder->endVector(); 1348 ``` 1349 1350=== "Python" 1351 1352 ```py 1353 # Create a `vector` representing the inventory of the Orc. Each number 1354 # could correspond to an item that can be claimed after he is slain. 1355 # Note: Since we prepend the bytes, this loop iterates in reverse. 1356 MyGame.Sample.Monster.StartInventoryVector(builder, 10) 1357 for i in reversed(range(0, 10)): 1358 builder.PrependByte(i) 1359 inv = builder.EndVector() 1360 1361 MyGame.Sample.Monster.StartPathVector(builder, 2) 1362 MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0) 1363 MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0) 1364 path = builder.EndVector() 1365 ``` 1366 1367=== "Rust" 1368 1369 ```rust 1370 // Inventory. 1371 let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 1372 1373 // Create the path vector of Vec3 objects. 1374 let x = Vec3::new(1.0, 2.0, 3.0); 1375 let y = Vec3::new(4.0, 5.0, 6.0); 1376 let path = builder.create_vector(&[x, y]); 1377 ``` 1378 1379=== "Swift" 1380 1381 ```swift 1382 // create inventory 1383 let inventory: [Byte] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1384 let inventoryOffset = builder.createVector(inventory) 1385 1386 let path = fbb.createVector(ofStructs: [ 1387 Vec3(x: 1, y: 2, z: 3), 1388 Vec3(x: 4, y: 5, z: 6) 1389 ]) 1390 ``` 1391 1392=== "TypeScript" 1393 1394 ```ts 1395 // Create a `vector` representing the inventory of the Orc. Each number 1396 // could correspond to an item that can be claimed after he is slain. 1397 let treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 1398 let inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure); 1399 1400 MyGame.Sample.Monster.startPathVector(builder, 2); 1401 MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0); 1402 MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0); 1403 let path = builder.endVector(); 1404 ``` 1405 1406 1407#### Unions 1408 1409The last non-scalar data field for the `Monster` table is the `equipped` `union` 1410field. For this case, we will reuse an already serialized `Weapon` (the only 1411type in the union), without needing to reserialize it. Union fields implicitly 1412add a hidden `_type` field that stores the type of value stored in the union. 1413When serializing a union, you must explicitly set this type field, along with 1414providing the union value. 1415 1416We will also serialize the other scalar data at the same time, since we have all 1417the necessary values and Offsets to make a `Monster`. 1418 1419=== "C++" 1420 1421 ```c++ 1422 // Create the remaining data needed for the Monster. 1423 auto name = builder.CreateString("Orc"); 1424 1425 // Create the position struct 1426 auto position = Vec3(1.0f, 2.0f, 3.0f); 1427 1428 // Set his hit points to 300 and his mana to 150. 1429 int hp = 300; 1430 int mana = 150; 1431 1432 // Finally, create the monster using the `CreateMonster` helper function 1433 // to set all fields. 1434 // 1435 // Here we set the union field by using the `.Union()` method of the 1436 // `Offset<Weapon>` axe we already serialized above. We just have to specify 1437 // which type of object we put in the union, and do that with the 1438 // auto-generated `Equipment_Weapon` enum. 1439 flatbuffers::Offset<Monster> orc = 1440 CreateMonster(builder, &position, mana, hp, name, inventory, 1441 Color_Red, weapons, Equipment_Weapon, axe.Union(), 1442 path); 1443 1444 ``` 1445 1446=== "C" 1447 1448 ```c 1449 // Serialize a name for our monster, called "Orc". 1450 // The _str suffix indicates the source is an ascii-z string. 1451 flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc"); 1452 1453 // Set his hit points to 300 and his mana to 150. 1454 uint16_t hp = 300; 1455 uint16_t mana = 150; 1456 1457 // Define an equipment union. `create` calls in C has a single 1458 // argument for unions where C++ has both a type and a data argument. 1459 ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe)); 1460 ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f }; 1461 ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red), 1462 weapons, equipped, path)); 1463 ``` 1464 1465=== "C#" 1466 1467 ```c# 1468 // Create the remaining data needed for the Monster. 1469 var name = builder.CreateString("Orc"); 1470 1471 // Create our monster using `StartMonster()` and `EndMonster()`. 1472 Monster.StartMonster(builder); 1473 Monster.AddPos(builder, Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f)); 1474 Monster.AddHp(builder, (short)300); 1475 Monster.AddName(builder, name); 1476 Monster.AddInventory(builder, inv); 1477 Monster.AddColor(builder, Color.Red); 1478 Monster.AddWeapons(builder, weapons); 1479 // For union fields, we explicitly add the auto-generated enum for the type 1480 // of value stored in the union. 1481 Monster.AddEquippedType(builder, Equipment.Weapon); 1482 // And we just use the `.Value` property of the already serialized axe. 1483 Monster.AddEquipped(builder, axe.Value); // Axe 1484 Monster.AddPath(builder, path); 1485 Offset<Monster> orc = Monster.EndMonster(builder); 1486 ``` 1487 1488=== "Dart" 1489 1490 ```dart 1491 // Serialize a name for our monster, called "Orc". 1492 final int name = builder.writeString('Orc'); 1493 1494 // Using the Builder API: 1495 // Set his hit points to 300 and his mana to 150. 1496 final int hp = 300; 1497 final int mana = 150; 1498 1499 final monster = new myGame.MonsterBuilder(builder) 1500 ..begin() 1501 ..addNameOffset(name) 1502 ..addInventoryOffset(inventory) 1503 ..addWeaponsOffset(weapons) 1504 ..addEquippedType(myGame.EquipmentTypeId.Weapon) 1505 ..addEquippedOffset(axe) 1506 ..addHp(hp) 1507 ..addMana(mana) 1508 ..addPos(vec3Builder.finish(1.0, 2.0, 3.0)) 1509 ..addPathOffset(path) 1510 ..addColor(myGame.Color.Red); 1511 1512 final int orc = monster.finish(); 1513 ``` 1514 1515=== "Go" 1516 1517 ```go 1518 // Serialize a name for our monster, called "Orc". 1519 name := builder.CreateString("Orc") 1520 1521 // Create our monster using `MonsterStart()` and `MonsterEnd()`. 1522 sample.MonsterStart(builder) 1523 sample.MonsterAddPos(builder, sample.CreateVec3(builder, 1.0, 2.0, 3.0)) 1524 sample.MonsterAddHp(builder, 300) 1525 sample.MonsterAddName(builder, name) 1526 sample.MonsterAddInventory(builder, inv) 1527 sample.MonsterAddColor(builder, sample.ColorRed) 1528 sample.MonsterAddWeapons(builder, weapons) 1529 sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) 1530 sample.MonsterAddEquipped(builder, axe) 1531 sample.MonsterAddPath(builder, path) 1532 orc := sample.MonsterEnd(builder) 1533 ``` 1534 1535=== "Java" 1536 1537 ```java 1538 // Serialize a name for our monster, called "Orc". 1539 int name = builder.createString("Orc"); 1540 1541 // Create our monster using `startMonster()` and `endMonster()`. 1542 Monster.startMonster(builder); 1543 Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)); 1544 Monster.addName(builder, name); 1545 Monster.addColor(builder, Color.Red); 1546 Monster.addHp(builder, (short)300); 1547 Monster.addInventory(builder, inv); 1548 Monster.addWeapons(builder, weapons); 1549 Monster.addEquippedType(builder, Equipment.Weapon); 1550 Monster.addEquipped(builder, axe); 1551 Monster.addPath(builder, path); 1552 int orc = Monster.endMonster(builder); 1553 ``` 1554 1555=== "JavaScript" 1556 1557 ```javascript 1558 // Serialize a name for our monster, called 'Orc'. 1559 var name = builder.createString('Orc'); 1560 1561 // Create our monster by using `startMonster()` and `endMonster()`. 1562 MyGame.Sample.Monster.startMonster(builder); 1563 MyGame.Sample.Monster.addPos(builder, 1564 MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0)); 1565 MyGame.Sample.Monster.addHp(builder, 300); 1566 MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red) 1567 MyGame.Sample.Monster.addName(builder, name); 1568 MyGame.Sample.Monster.addInventory(builder, inv); 1569 MyGame.Sample.Monster.addWeapons(builder, weapons); 1570 MyGame.Sample.Monster.addEquippedType(builder, 1571 MyGame.Sample.Equipment.Weapon); 1572 MyGame.Sample.Monster.addEquipped(builder, axe); 1573 MyGame.Sample.Monster.addPath(builder, path); 1574 var orc = MyGame.Sample.Monster.endMonster(builder); 1575 ``` 1576 1577=== "Kotlin" 1578 1579 ```kotlin 1580 // Serialize a name for our monster, called "Orc". 1581 val name = builder.createString("Orc") 1582 1583 // Create our monster using `startMonster()` and `endMonster()`. 1584 Monster.startMonster(builder) 1585 Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)) 1586 Monster.addName(builder, name) 1587 Monster.addColor(builder, Color.Red) 1588 Monster.addHp(builder, 300.toShort()) 1589 Monster.addInventory(builder, inv) 1590 Monster.addWeapons(builder, weapons) 1591 Monster.addEquippedType(builder, Equipment.Weapon) 1592 Monster.addEquipped(builder, axe) 1593 Monster.addPath(builder, path) 1594 val orc = Monster.endMonster(builder) 1595 ``` 1596 1597=== "Lobster" 1598 1599 ```lobster 1600 // Name of the monster. 1601 let name = builder.CreateString("Orc") 1602 1603 let orc = MyGame_Sample_MonsterBuilder { b } 1604 .start() 1605 .add_pos(b.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0)) 1606 .add_hp(300) 1607 .add_name(name) 1608 .add_inventory(inv) 1609 .add_color(MyGame_Sample_Color_Red) 1610 .add_weapons(weapons) 1611 .add_equipped_type(MyGame_Sample_Equipment_Weapon) 1612 .add_equipped(weapon_offsets[1]) 1613 .add_path(path) 1614 .end() 1615 ``` 1616 1617=== "Lua" 1618 1619 ```lua 1620 -- Serialize a name for our monster, called 'orc' 1621 local name = builder:CreateString("Orc") 1622 1623 -- Create our monster by using Start() andEnd() 1624 monster.Start(builder) 1625 monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) 1626 monster.AddHp(builder, 300) 1627 monster.AddName(builder, name) 1628 monster.AddInventory(builder, inv) 1629 monster.AddColor(builder, color.Red) 1630 monster.AddWeapons(builder, weapons) 1631 monster.AddEquippedType(builder, equipment.Weapon) 1632 monster.AddEquipped(builder, axe) 1633 monster.AddPath(builder, path) 1634 local orc = monster.End(builder) 1635 ``` 1636 1637=== "PHP" 1638 1639 ```php 1640 // Serialize a name for our monster, called "Orc". 1641 $name = $builder->createString("Orc"); 1642 1643 // Create our monster by using `StartMonster()` and `EndMonster()`. 1644 \MyGame\Sample\Monster::StartMonster($builder); 1645 \MyGame\Sample\Monster::AddPos($builder, 1646 \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0)); 1647 \MyGame\Sample\Monster::AddHp($builder, 300); 1648 \MyGame\Sample\Monster::AddName($builder, $name); 1649 \MyGame\Sample\Monster::AddInventory($builder, $inv); 1650 \MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red); 1651 \MyGame\Sample\Monster::AddWeapons($builder, $weapons); 1652 \MyGame\Sample\Monster::AddEquippedType($builder, 1653 \MyGame\Sample\Equipment::Weapon); 1654 \MyGame\Sample\Monster::AddEquipped($builder, $axe); 1655 \MyGame\Sample\Monster::AddPath($builder, $path); 1656 $orc = \MyGame\Sample\Monster::EndMonster($builder); 1657 ``` 1658 1659=== "Python" 1660 1661 ```py 1662 # Serialize a name for our monster, called "Orc". 1663 name = builder.CreateString("Orc") 1664 1665 # Create our monster by using `Monster.Start()` and `Monster.End()`. 1666 MyGame.Sample.Monster.Start(builder) 1667 MyGame.Sample.Monster.AddPos(builder, 1668 MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) 1669 MyGame.Sample.Monster.AddHp(builder, 300) 1670 MyGame.Sample.Monster.AddName(builder, name) 1671 MyGame.Sample.Monster.AddInventory(builder, inv) 1672 MyGame.Sample.Monster.AddColor(builder, 1673 MyGame.Sample.Color.Color().Red) 1674 MyGame.Sample.Monster.AddWeapons(builder, weapons) 1675 MyGame.Sample.Monster.AddEquippedType( 1676 builder, MyGame.Sample.Equipment.Equipment().Weapon) 1677 MyGame.Sample.Monster.AddEquipped(builder, axe) 1678 MyGame.Sample.Monster.AddPath(builder, path) 1679 orc = MyGame.Sample.Monster.End(builder) 1680 ``` 1681 1682=== "Rust" 1683 1684 ```rust 1685 // Name of the Monster. 1686 let name = builder.create_string("Orc"); 1687 1688 // Create the monster using the `Monster::create` helper function. This 1689 // function accepts a `MonsterArgs` struct, which supplies all of the data 1690 // needed to build a `Monster`. To supply empty/default fields, just use the 1691 // Rust built-in `Default::default()` function, as demonstrated below. 1692 let orc = Monster::create(&mut builder, &MonsterArgs{ 1693 pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)), 1694 mana: 150, 1695 hp: 80, 1696 name: Some(name), 1697 inventory: Some(inventory), 1698 color: Color::Red, 1699 weapons: Some(weapons), 1700 equipped_type: Equipment::Weapon, 1701 equipped: Some(axe.as_union_value()), 1702 path: Some(path), 1703 ..Default::default() 1704 }); 1705 ``` 1706 1707=== "Swift" 1708 1709 ```swift 1710 // Name of the Monster. 1711 let name = builder.create(string: "Orc") 1712 1713 let orc = Monster.createMonster( 1714 &builder, 1715 pos: MyGame_Sample_Vec3(x: 1, y: 2, z: 3), 1716 hp: 300, 1717 nameOffset: name, 1718 inventoryVectorOffset: inventoryOffset, 1719 color: .red, 1720 weaponsVectorOffset: weaponsOffset, 1721 equippedType: .weapon, 1722 equippedOffset: axe) 1723 ``` 1724 1725=== "TypeScript" 1726 1727 ```ts 1728 // Serialize a name for our monster, called 'Orc'. 1729 let name = builder.createString('Orc'); 1730 1731 // Create our monster by using `startMonster()` and `endMonster()`. 1732 MyGame.Sample.Monster.startMonster(builder); 1733 MyGame.Sample.Monster.addPos(builder, 1734 MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0)); 1735 MyGame.Sample.Monster.addHp(builder, 300); 1736 MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red) 1737 MyGame.Sample.Monster.addName(builder, name); 1738 MyGame.Sample.Monster.addInventory(builder, inv); 1739 MyGame.Sample.Monster.addWeapons(builder, weapons); 1740 MyGame.Sample.Monster.addEquippedType(builder, 1741 MyGame.Sample.Equipment.Weapon); 1742 MyGame.Sample.Monster.addEquipped(builder, axe); 1743 MyGame.Sample.Monster.addPath(builder, path); 1744 let orc = MyGame.Sample.Monster.endMonster(builder); 1745 ``` 1746 1747 1748### Finishing 1749 1750At this point, we have serialized a `Monster` we've named "orc" to the 1751flatbuffer and have its offset. The `root_type` of the schema is also a 1752`Monster`, so we have everything we need to finish the serialization step. 1753 1754This is done by calling the appropriate `finish` method on the Builder, passing 1755in the orc offset to indicate this `table` is the "entry" point when 1756deserializing the buffer later. 1757 1758=== "C++" 1759 1760 ```c++ 1761 // Call `Finish()` to instruct the builder that this monster is complete. 1762 // You could also call `FinishMonsterBuffer(builder, orc);` 1763 builder.Finish(orc); 1764 ``` 1765 1766=== "C" 1767 1768 ```c 1769 // Because we used `Monster_create_as_root`, we do not need a `finish` call 1770 // in C. 1771 ``` 1772 1773=== "C#" 1774 1775 ```c# 1776 // Call `Finish()` to instruct the builder that this monster is complete. 1777 // You could also call `Monster.FinishMonsterBuffer(builder, orc);` 1778 builder.Finish(orc.Value); 1779 ``` 1780 1781=== "Dart" 1782 1783 ```dart 1784 // Call `finish()` to instruct the builder that this monster is complete. 1785 // See the next code section, as in Dart `finish` will also return the byte 1786 // array. 1787 ``` 1788 1789=== "Go" 1790 1791 ```go 1792 // Call `Finish()` to instruct the builder that this monster is complete. 1793 builder.Finish(orc) 1794 ``` 1795 1796=== "Java" 1797 1798 ```java 1799 // Call `finish()` to instruct the builder that this monster is complete. 1800 builder.finish(orc); 1801 ``` 1802 1803=== "JavaScript" 1804 1805 ```javascript 1806 // Call `finish()` to instruct the builder that this monster is complete. 1807 builder.finish(orc); 1808 ``` 1809 1810=== "Kotlin" 1811 1812 ```kotlin 1813 // Call `finish()` to instruct the builder that this monster is complete. 1814 builder.finish(orc) ; 1815 ``` 1816 1817=== "Lobster" 1818 1819 ```lobster 1820 // Call `Finish()` to instruct the builder that this monster is complete. 1821 builder.Finish(orc) 1822 ``` 1823 1824=== "Lua" 1825 1826 ```lua 1827 -- Call 'Finish()' to instruct the builder that this monster is complete. 1828 builder:Finish(orc) 1829 ``` 1830 1831=== "PHP" 1832 1833 ```php 1834 // Call `finish()` to instruct the builder that this monster is complete. 1835 $builder->finish($orc); 1836 ``` 1837 1838=== "Python" 1839 1840 ```py 1841 # Call `Finish()` to instruct the builder that this monster is complete. 1842 builder.Finish(orc) 1843 ``` 1844 1845=== "Rust" 1846 1847 ```rust 1848 // Call `finish()` to instruct the builder that this monster is complete. 1849 builder.finish(orc, None); 1850 ``` 1851 1852=== "Swift" 1853 1854 ```swift 1855 // Call `finish()` to instruct the builder that this monster is complete. 1856 builder.finish(offset: orc) 1857 ``` 1858 1859=== "TypeScript" 1860 1861 ```ts 1862 // Call `finish()` to instruct the builder that this monster is complete. 1863 builder.finish(orc); 1864 ``` 1865 1866 1867Once you finish a Builder, you can no longer serialize more data to it. 1868 1869#### Buffer Access 1870 1871The flatbuffer is now ready to be stored somewhere, sent over the network, 1872compressed, or whatever you would like to do with it. You access the raw buffer 1873like so: 1874 1875=== "C++" 1876 1877 ```c++ 1878 // This must be called after `Finish()`. 1879 uint8_t *buf = builder.GetBufferPointer(); 1880 1881 // Returns the size of the buffer that `GetBufferPointer()` points to. 1882 int size = builder.GetSize(); 1883 ``` 1884 1885=== "C" 1886 1887 ```c 1888 uint8_t *buf; 1889 size_t size; 1890 1891 // Allocate and extract a readable buffer from internal builder heap. 1892 // The returned buffer must be deallocated using `free`. 1893 // NOTE: Finalizing the buffer does NOT change the builder, it 1894 // just creates a snapshot of the builder content. 1895 buf = flatcc_builder_finalize_buffer(B, &size); 1896 // use buf 1897 free(buf); 1898 1899 // Optionally reset builder to reuse builder without deallocating 1900 // internal stack and heap. 1901 flatcc_builder_reset(B); 1902 // build next buffer. 1903 // ... 1904 1905 // Cleanup. 1906 flatcc_builder_clear(B); 1907 ``` 1908 1909=== "C#" 1910 1911 ```c# 1912 // This must be called after `Finish()`. 1913 // 1914 // The data in this ByteBuffer does NOT start at 0, but at buf.Position. 1915 // The end of the data is marked by buf.Length, so the size is 1916 // buf.Length - buf.Position. 1917 FlatBuffers.ByteBuffer dataBuffer = builder.DataBuffer; 1918 1919 // Alternatively this copies the above data out of the ByteBuffer for you: 1920 byte[] buf = builder.SizedByteArray(); 1921 ``` 1922 1923=== "Dart" 1924 1925 ```dart 1926 final Uint8List buf = builder.finish(orc); 1927 ``` 1928 1929=== "Go" 1930 1931 ```go 1932 // This must be called after `Finish()`. 1933 buf := builder.FinishedBytes() // Of type `byte[]`. 1934 ``` 1935 1936=== "Java" 1937 1938 ```java 1939 // This must be called after `finish()`. 1940 java.nio.ByteBuffer buf = builder.dataBuffer(); 1941 // The data in this ByteBuffer does NOT start at 0, but at buf.position(). 1942 // The number of bytes is buf.remaining(). 1943 1944 // Alternatively this copies the above data out of the ByteBuffer for you: 1945 byte[] buf = builder.sizedByteArray(); 1946 ``` 1947 1948=== "JavaScript" 1949 1950 ```javascript 1951 // This must be called after `finish()`. 1952 var buf = builder.asUint8Array(); // Of type `Uint8Array`. 1953 ``` 1954 1955=== "Kotlin" 1956 1957 ```kotlin 1958 // This must be called after `finish()`. 1959 val buf = builder.dataBuffer() 1960 // The data in this ByteBuffer does NOT start at 0, but at buf.position(). 1961 // The number of bytes is buf.remaining(). 1962 1963 // Alternatively this copies the above data out of the ByteBuffer for you: 1964 val buf = builder.sizedByteArray() 1965 ``` 1966 1967=== "Lobster" 1968 1969 ```lobster 1970 // This must be called after `Finish()`. 1971 let buf = builder.SizedCopy() // Of type `string`. 1972 ``` 1973 1974=== "Lua" 1975 1976 ```lua 1977 local bufAsString = builder:Output() 1978 ``` 1979 1980=== "PHP" 1981 1982 ```php 1983 // This must be called after `finish()`. 1984 $buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer` 1985 // The data in this ByteBuffer does NOT start at 0, but at 1986 // buf->getPosition(). 1987 // The end of the data is marked by buf->capacity(), so the size is 1988 // buf->capacity() - buf->getPosition(). 1989 ``` 1990 1991=== "Python" 1992 1993 ```py 1994 # This must be called after `Finish()`. 1995 buf = builder.Output() // Of type `bytearray`. 1996 ``` 1997 1998=== "Rust" 1999 2000 ```rust 2001 // This must be called after `finish()`. 2002 // `finished_data` returns a byte slice. 2003 let buf = builder.finished_data(); // Of type `&[u8]` 2004 ``` 2005 2006=== "Swift" 2007 2008 ```swift 2009 // This must be called after `finish()`. 2010 // `sizedByteArray` returns the finished buf of type [UInt8]. 2011 let buf = builder.sizedByteArray 2012 // or you can use to get an object of type Data 2013 let bufData = ByteBuffer(data: builder.data) 2014 ``` 2015 2016=== "TypeScript" 2017 2018 ```ts 2019 // This must be called after `finish()`. 2020 let buf = builder.asUint8Array(); // Of type `Uint8Array`. 2021 ``` 2022 2023 2024Now you can write the bytes to a file or send them over the network. The buffer 2025stays valid until the Builder is cleared or destroyed. 2026 2027Make sure your file mode (or transfer protocol) is set to BINARY, and not TEXT. 2028If you try to transfer a flatbuffer in TEXT mode, the buffer will be corrupted 2029and be hard to diagnose. 2030 2031## Deserialization 2032 2033Deserialization is a bit of a misnomer, since FlatBuffers doesn't deserialize 2034the whole buffer when accessed. It just "decodes" the data that is requested, 2035leaving all the other data untouched. It is up to the application to decide if 2036the data is copied out or even read in the first place. However, we continue to 2037use the word `deserialize` to mean accessing data from a binary flatbuffer. 2038 2039Now that we have successfully create an orc FlatBuffer, the data can be saved, 2040sent over a network, etc. At some point, the buffer will be accessed to obtain 2041the underlying data. 2042 2043The same application setup used for serialization is needed for deserialization 2044(see [application integration](#application-integration)). 2045 2046### Root Access 2047 2048All access to the data in the flatbuffer must first go through the root object. 2049There is only one root object per flatbuffer. The generated code provides 2050functions to get the root object given the buffer. 2051 2052=== "C++" 2053 2054 ```c++ 2055 uint8_t *buffer_pointer = /* the data you just read */; 2056 2057 // Get an view to the root object inside the buffer. 2058 Monster monster = GetMonster(buffer_pointer); 2059 ``` 2060 2061=== "C" 2062 2063 ```c 2064 // Note that we use the `table_t` suffix when reading a table object 2065 // as opposed to the `ref_t` suffix used during the construction of 2066 // the buffer. 2067 ns(Monster_table_t) monster = ns(Monster_as_root(buffer)); 2068 2069 // Note: root object pointers are NOT the same as the `buffer` pointer. 2070 ``` 2071 2072=== "C#" 2073 2074 ```c# 2075 byte[] bytes = /* the data you just read */ 2076 2077 // Get an view to the root object inside the buffer. 2078 Monster monster = Monster.GetRootAsMonster(new ByteBuffer(bytes)); 2079 ``` 2080 2081=== "Dart" 2082 2083 ```dart 2084 List<int> data = ... // the data, e.g. from file or network 2085 // A generated factory constructor that will read the data. 2086 myGame.Monster monster = new myGame.Monster(data); 2087 ``` 2088 2089=== "Go" 2090 2091 ```go 2092 var buf []byte = /* the data you just read */ 2093 2094 // Get an accessor to the root object inside the buffer. 2095 monster := sample.GetRootAsMonster(buf, 0) 2096 2097 // Note: We use `0` for the offset here, which is typical for most buffers 2098 // you would read. If you wanted to read from `builder.Bytes` directly, you 2099 // would need to pass in the offset of `builder.Head()`, as the builder 2100 // constructs the buffer backwards, so may not start at offset 0. 2101 ``` 2102 2103=== "Java" 2104 2105 ```java 2106 byte[] bytes = /* the data you just read */ 2107 java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(bytes); 2108 2109 // Get an accessor to the root object inside the buffer. 2110 Monster monster = Monster.getRootAsMonster(buf); 2111 ``` 2112 2113=== "JavaScript" 2114 2115 ```javascript 2116 // the data you just read, as a `Uint8Array` 2117 // Note that the example here uses `readFileSync` from the built-in `fs` 2118 // module, but other methods for accessing the file contents will also work. 2119 var bytes = new Uint8Array(readFileSync('./monsterdata.bin')); 2120 2121 var buf = new flatbuffers.ByteBuffer(bytes); 2122 2123 // Get an accessor to the root object inside the buffer. 2124 var monster = MyGame.Sample.Monster.getRootAsMonster(buf); 2125 ``` 2126 2127=== "Kotlin" 2128 2129 ```kotlin 2130 val bytes = /* the data you just read */ 2131 val buf = java.nio.ByteBuffer.wrap(bytes) 2132 2133 // Get an accessor to the root object inside the buffer. 2134 Monster monster = Monster.getRootAsMonster(buf) 2135 ``` 2136 2137=== "Lobster" 2138 2139 ```lobster 2140 buf = /* the data you just read, in a string */ 2141 2142 // Get an accessor to the root object inside the buffer. 2143 let monster = MyGame_Sample_GetRootAsMonster(buf) 2144 ``` 2145 2146=== "Lua" 2147 2148 ```lua 2149 local bufAsString = -- The data you just read in 2150 2151 -- Convert the string representation into binary array Lua structure 2152 local buf = flatbuffers.binaryArray.New(bufAsString) 2153 2154 -- Get an accessor to the root object insert the buffer 2155 local mon = monster.GetRootAsMonster(buf, 0) 2156 ``` 2157 2158=== "PHP" 2159 2160 ```php 2161 $bytes = /* the data you just read, in a string */ 2162 $buf = Google\FlatBuffers\ByteBuffer::wrap($bytes); 2163 2164 // Get an accessor to the root object inside the buffer. 2165 $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf); 2166 ``` 2167 2168=== "Python" 2169 2170 ```py 2171 buf = /* the data you just read, in an object of type "bytearray" */ 2172 2173 # Get an accessor to the root object inside the buffer. 2174 monster = MyGame.Sample.Monster.Monster.GetRootAs(buf, 0) 2175 2176 # Note: We use `0` for the offset here, which is typical for most buffers 2177 # you would read. If you wanted to read from the `builder.Bytes` directly, 2178 # you would need to pass in the offset of `builder.Head()`, as the builder 2179 # constructs the buffer backwards, so may not start at offset 0. 2180 ``` 2181 2182=== "Rust" 2183 2184 ```rust 2185 let buf = /* the data you just read, in a &[u8] */ 2186 2187 // Get an accessor to the root object inside the buffer. 2188 let monster = root_as_monster(buf).unwrap(); 2189 ``` 2190 2191=== "Swift" 2192 2193 ```swift 2194 // create a ByteBuffer(:) from an [UInt8] or Data() 2195 var buf = // Get your data 2196 // Get an accessor to the root object inside the buffer. 2197 let monster: Monster = try! getCheckedRoot(byteBuffer: &byteBuffer) 2198 // let monster: Monster = getRoot(byteBuffer: &byteBuffer) 2199 ``` 2200 2201=== "TypeScript" 2202 2203 ```ts 2204 // the data you just read, as a `Uint8Array`. 2205 // Note that the example here uses `readFileSync` from the built-in `fs` 2206 // module, but other methods for accessing the file contents will also work. 2207 let bytes = new Uint8Array(readFileSync('./monsterdata.bin')); 2208 2209 let buf = new flatbuffers.ByteBuffer(bytes); 2210 2211 // Get an accessor to the root object inside the buffer. 2212 let monster = MyGame.Sample.Monster.getRootAsMonster(buf); 2213 ``` 2214 2215 2216Again, make sure you read the bytes in BINARY mode, otherwise the buffer may be 2217corrupted. 2218 2219In most languages, the returned object is just a "view" of the data with helpful 2220accessors. Data is typically not copied out of the backing buffer. This also 2221means the backing buffer must remain alive for the duration of the views. 2222 2223### Table Access 2224 2225If you look in the generated files emitted by `flatc`, you will see it generated 2226, for each `table`, accessors of all its non-`deprecated` fields. For example, 2227some of the accessors of the `Monster` root table would look like: 2228 2229=== "C++" 2230 2231 ```c++ 2232 auto hp = monster->hp(); 2233 auto mana = monster->mana(); 2234 auto name = monster->name()->c_str(); 2235 ``` 2236 2237=== "C" 2238 2239 ```c 2240 uint16_t hp = ns(Monster_hp(monster)); 2241 uint16_t mana = ns(Monster_mana(monster)); 2242 flatbuffers_string_t name = ns(Monster_name(monster)); 2243 ``` 2244 2245=== "C#" 2246 2247 ```c# 2248 // For C#, unlike most other languages support by FlatBuffers, most values 2249 // (except for vectors and unions) are available as properties instead of 2250 // accessor methods. 2251 var hp = monster.Hp; 2252 var mana = monster.Mana; 2253 var name = monster.Name; 2254 ``` 2255 2256=== "Dart" 2257 2258 ```dart 2259 // For Dart, unlike other languages support by FlatBuffers, most values 2260 // are available as properties instead of accessor methods. 2261 var hp = monster.hp; 2262 var mana = monster.mana; 2263 var name = monster.name; 2264 ``` 2265 2266=== "Go" 2267 2268 ```go 2269 hp := monster.Hp() 2270 mana := monster.Mana() 2271 name := string(monster.Name()) // Note: `monster.Name()` returns a byte[]. 2272 ``` 2273 2274=== "Java" 2275 2276 ```java 2277 short hp = monster.hp(); 2278 short mana = monster.mana(); 2279 String name = monster.name(); 2280 ``` 2281 2282=== "JavaScript" 2283 2284 ```javascript 2285 var hp = monster.hp(); 2286 var mana = monster.mana(); 2287 var name = monster.name(); 2288 ``` 2289 2290=== "Kotlin" 2291 2292 ```kotlin 2293 val hp = monster.hp 2294 val mana = monster.mana 2295 val name = monster.name 2296 ``` 2297 2298=== "Lobster" 2299 2300 ```lobster 2301 let hp = monster.hp 2302 let mana = monster.mana 2303 let name = monster.name 2304 ``` 2305 2306=== "Lua" 2307 2308 ```lua 2309 local hp = mon:Hp() 2310 local mana = mon:Mana() 2311 local name = mon:Name() 2312 ``` 2313 2314=== "PHP" 2315 2316 ```php 2317 $hp = $monster->getHp(); 2318 $mana = $monster->getMana(); 2319 $name = monster->getName(); 2320 ``` 2321 2322=== "Python" 2323 2324 ```py 2325 hp = monster.Hp() 2326 mana = monster.Mana() 2327 name = monster.Name() 2328 ``` 2329 2330=== "Rust" 2331 2332 ```rust 2333 // Get and test some scalar types from the FlatBuffer. 2334 let hp = monster.hp(); 2335 let mana = monster.mana(); 2336 let name = monster.name(); 2337 ``` 2338 2339=== "Swift" 2340 2341 ```swift 2342 let hp = monster.hp 2343 let mana = monster.mana 2344 let name = monster.name // returns an optional string 2345 ``` 2346 2347=== "TypeScript" 2348 2349 ```ts 2350 let hp = monster.hp(); 2351 let mana = monster.mana(); 2352 let name = monster.name(); 2353 ``` 2354 2355 2356These accessors should hold the values `300`, `150`, and `"Orc"` respectively. 2357 2358The default value of `150` wasn't stored in the `mana` field, but we are still 2359able to retrieve it. That is because the generated accessors return a hard-coded 2360default value when it doesn't find the value in the buffer. 2361 2362#### Nested Object Access 2363 2364Accessing nested objects is very similar, with the nested field pointing to 2365another object type. Be careful, the field could be `null` if not present. 2366 2367For example, accessing the `pos` `struct`, which is type `Vec3` you would do: 2368 2369=== "C++" 2370 2371 ```c++ 2372 auto pos = monster->pos(); 2373 auto x = pos->x(); 2374 auto y = pos->y(); 2375 auto z = pos->z(); 2376 ``` 2377 2378=== "C" 2379 2380 ```c 2381 ns(Vec3_struct_t) pos = ns(Monster_pos(monster)); 2382 float x = ns(Vec3_x(pos)); 2383 float y = ns(Vec3_y(pos)); 2384 float z = ns(Vec3_z(pos)); 2385 ``` 2386 2387=== "C#" 2388 2389 ```c# 2390 var pos = monster.Pos.Value; 2391 var x = pos.X; 2392 var y = pos.Y; 2393 var z = pos.Z; 2394 ``` 2395 2396=== "Dart" 2397 2398 ```dart 2399 myGame.Vec3 pos = monster.pos; 2400 double x = pos.x; 2401 double y = pos.y; 2402 double z = pos.z; 2403 ``` 2404 2405=== "Go" 2406 2407 ```go 2408 pos := monster.Pos(nil) 2409 x := pos.X() 2410 y := pos.Y() 2411 z := pos.Z() 2412 2413 // Note: Whenever you access a new object, like in `Pos()`, a new temporary 2414 // accessor object gets created. If your code is very performance sensitive, 2415 // you can pass in a pointer to an existing `Vec3` instead of `nil`. This 2416 // allows you to reuse it across many calls to reduce the amount of object 2417 // allocation/garbage collection. 2418 ``` 2419 2420=== "Java" 2421 2422 ```java 2423 Vec3 pos = monster.pos(); 2424 float x = pos.x(); 2425 float y = pos.y(); 2426 float z = pos.z(); 2427 ``` 2428 2429=== "JavaScript" 2430 2431 ```javascript 2432 var pos = monster.pos(); 2433 var x = pos.x(); 2434 var y = pos.y(); 2435 var z = pos.z(); 2436 ``` 2437 2438=== "Kotlin" 2439 2440 ```kotlin 2441 val pos = monster.pos!! 2442 val x = pos.x 2443 val y = pos.y 2444 val z = pos.z 2445 ``` 2446 2447=== "Lobster" 2448 2449 ```lobster 2450 let pos = monster.pos 2451 let x = pos.x 2452 let y = pos.y 2453 let z = pos.z 2454 ``` 2455 2456=== "Lua" 2457 2458 ```lua 2459 local pos = mon:Pos() 2460 local x = pos:X() 2461 local y = pos:Y() 2462 local z = pos:Z() 2463 ``` 2464 2465=== "PHP" 2466 2467 ```php 2468 $pos = $monster->getPos(); 2469 $x = $pos->getX(); 2470 $y = $pos->getY(); 2471 $z = $pos->getZ(); 2472 ``` 2473 2474=== "Python" 2475 2476 ```py 2477 pos = monster.Pos() 2478 x = pos.X() 2479 y = pos.Y() 2480 z = pos.Z() 2481 ``` 2482 2483=== "Rust" 2484 2485 ```rust 2486 let pos = monster.pos().unwrap(); 2487 let x = pos.x(); 2488 let y = pos.y(); 2489 let z = pos.z(); 2490 ``` 2491 2492=== "Swift" 2493 2494 ```swift 2495 let pos = monster.pos 2496 let x = pos.x 2497 let y = pos.y 2498 let z = pos.z 2499 ``` 2500 2501=== "TypeScript" 2502 2503 ```ts 2504 let pos = monster.pos(); 2505 let x = pos.x(); 2506 let y = pos.y(); 2507 let z = pos.z(); 2508 ``` 2509 2510 2511Where `x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0` respectively. 2512 2513### Vector Access 2514 2515Similarly, we can access elements of the `inventory` `vector` by indexing it. 2516You can also iterate over the length of the vector. 2517 2518=== "C++" 2519 2520 ```c++ 2521 flatbuffers::Vector<unsigned char> inv = monster->inventory(); 2522 auto inv_len = inv->size(); 2523 auto third_item = inv->Get(2); 2524 ``` 2525 2526=== "C" 2527 2528 ```c 2529 // If `inv` hasn't been set, it will be null. It is valid get 2530 // the length of null which will be 0, useful for iteration. 2531 flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster)); 2532 size_t inv_len = flatbuffers_uint8_vec_len(inv); 2533 ``` 2534 2535=== "C#" 2536 2537 ```c# 2538 int invLength = monster.InventoryLength; 2539 var thirdItem = monster.Inventory(2); 2540 ``` 2541 2542=== "Dart" 2543 2544 ```dart 2545 int invLength = monster.inventory.length; 2546 var thirdItem = monster.inventory[2]; 2547 ``` 2548 2549=== "Go" 2550 2551 ```go 2552 invLength := monster.InventoryLength() 2553 thirdItem := monster.Inventory(2) 2554 ``` 2555 2556=== "Java" 2557 2558 ```java 2559 int invLength = monster.inventoryLength(); 2560 byte thirdItem = monster.inventory(2); 2561 ``` 2562 2563=== "JavaScript" 2564 2565 ```javascript 2566 var invLength = monster.inventoryLength(); 2567 var thirdItem = monster.inventory(2); 2568 ``` 2569 2570=== "Kotlin" 2571 2572 ```kotlin 2573 val invLength = monster.inventoryLength 2574 val thirdItem = monster.inventory(2)!! 2575 ``` 2576 2577=== "Lobster" 2578 2579 ```lobster 2580 let inv_len = monster.inventory_length 2581 let third_item = monster.inventory(2) 2582 ``` 2583 2584=== "Lua" 2585 2586 ```lua 2587 local invLength = mon:InventoryLength() 2588 local thirdItem = mon:Inventory(3) -- Lua is 1-based 2589 ``` 2590 2591=== "PHP" 2592 2593 ```php 2594 $inv_len = $monster->getInventoryLength(); 2595 $third_item = $monster->getInventory(2); 2596 ``` 2597 2598=== "Python" 2599 2600 ```py 2601 inv_len = monster.InventoryLength() 2602 third_item = monster.Inventory(2) 2603 ``` 2604 2605=== "Rust" 2606 2607 ```rust 2608 // Get and test an element from the `inventory` FlatBuffer's `vector`. 2609 let inv = monster.inventory().unwrap(); 2610 2611 // Note that this vector is returned as a slice, because direct access for 2612 // this type, a `u8` vector, is safe on all platforms: 2613 let third_item = inv[2]; 2614 ``` 2615 2616=== "Swift" 2617 2618 ```swift 2619 // Get a the count of objects in the vector 2620 let count = monster.inventoryCount 2621 2622 // get item at index 4 2623 let object = monster.inventory(at: 4) 2624 2625 // or you can fetch the entire array 2626 let inv = monster.inventory 2627 // inv[4] should equal object 2628 ``` 2629 2630=== "TypeScript" 2631 2632 ```ts 2633 let invLength = monster.inventoryLength(); 2634 let thirdItem = monster.inventory(2); 2635 ``` 2636 2637 2638For vectors of tables, you can access the elements like any other vector, except 2639you need to handle the result as a FlatBuffer table. Here we iterate over the 2640`weapons` vector that is houses `Weapon` `tables`. 2641 2642=== "C++" 2643 2644 ```c++ 2645 flatbuffers::Vector<Weapon> weapons = monster->weapons(); 2646 auto weapon_len = weapons->size(); 2647 auto second_weapon_name = weapons->Get(1)->name()->str(); 2648 auto second_weapon_damage = weapons->Get(1)->damage() 2649 ``` 2650 2651=== "C" 2652 2653 ```c 2654 ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster)); 2655 size_t weapons_len = ns(Weapon_vec_len(weapons)); 2656 // We can use `const char *` instead of `flatbuffers_string_t`. 2657 const char *second_weapon_name = 2658 ns(Weapon_name(ns(Weapon_vec_at(weapons, 1)))); 2659 uint16_t second_weapon_damage = 2660 ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1)))); 2661 ``` 2662 2663=== "C#" 2664 2665 ```c# 2666 int weaponsLength = monster.WeaponsLength; 2667 var secondWeaponName = monster.Weapons(1).Name; 2668 var secondWeaponDamage = monster.Weapons(1).Damage; 2669 ``` 2670 2671=== "Dart" 2672 2673 ```dart 2674 int weaponsLength = monster.weapons.length; 2675 var secondWeaponName = monster.weapons[1].name; 2676 var secondWeaponDamage = monster.Weapons[1].damage; 2677 ``` 2678 2679=== "Go" 2680 2681 ```go 2682 weaponLength := monster.WeaponsLength() 2683 // We need a `sample.Weapon` to pass into `monster.Weapons()` 2684 // to capture the output of the function.k 2685 weapon := new(sample.Weapon) 2686 if monster.Weapons(weapon, 1) { 2687 secondWeaponName := weapon.Name() 2688 secondWeaponDamage := weapon.Damage() 2689 } 2690 ``` 2691 2692=== "Java" 2693 2694 ```java 2695 int weaponsLength = monster.weaponsLength(); 2696 String secondWeaponName = monster.weapons(1).name(); 2697 short secondWeaponDamage = monster.weapons(1).damage(); 2698 ``` 2699 2700=== "JavaScript" 2701 2702 ```javascript 2703 var weaponsLength = monster.weaponsLength(); 2704 var secondWeaponName = monster.weapons(1).name(); 2705 var secondWeaponDamage = monster.weapons(1).damage(); 2706 ``` 2707 2708=== "Kotlin" 2709 2710 ```kotlin 2711 val weaponsLength = monster.weaponsLength 2712 val secondWeaponName = monster.weapons(1)!!.name 2713 val secondWeaponDamage = monster.weapons(1)!!.damage 2714 ``` 2715 2716=== "Lobster" 2717 2718 ```lobster 2719 let weapons_length = monster.weapons_length 2720 let second_weapon_name = monster.weapons(1).name 2721 let second_weapon_damage = monster.weapons(1).damage 2722 ``` 2723 2724=== "Lua" 2725 2726 ```lua 2727 local weaponsLength = mon:WeaponsLength() 2728 local secondWeaponName = mon:Weapon(2):Name() 2729 local secondWeaponDamage = mon:Weapon(2):Damage() 2730 ``` 2731 2732=== "PHP" 2733 2734 ```php 2735 $weapons_len = $monster->getWeaponsLength(); 2736 $second_weapon_name = $monster->getWeapons(1)->getName(); 2737 $second_weapon_damage = $monster->getWeapons(1)->getDamage(); 2738 ``` 2739 2740=== "Python" 2741 2742 ```py 2743 weapons_length = monster.WeaponsLength() 2744 second_weapon_name = monster.Weapons(1).Name() 2745 second_weapon_damage = monster.Weapons(1).Damage() 2746 ``` 2747 2748=== "Rust" 2749 2750 ```rust 2751 // Get and test the `weapons` FlatBuffers's `vector`. 2752 let weps = monster.weapons().unwrap(); 2753 let weps_len = weps.len(); 2754 2755 let wep2 = weps.get(1); 2756 let second_weapon_name = wep2.name(); 2757 let second_weapon_damage = wep2.damage(); 2758 ``` 2759 2760=== "Swift" 2761 2762 ```swift 2763 // Get the count of weapon objects 2764 let wepsCount = monster.weaponsCount 2765 2766 let weapon2 = monster.weapons(at: 1) 2767 let weaponName = weapon2.name 2768 let weaponDmg = weapon2.damage 2769 ``` 2770 2771=== "TypeScript" 2772 2773 ```ts 2774 let weaponsLength = monster.weaponsLength(); 2775 let secondWeaponName = monster.weapons(1).name(); 2776 let secondWeaponDamage = monster.weapons(1).damage(); 2777 ``` 2778 2779 2780### Union Access 2781 2782Lastly , we can access our `equipped` `union` field. Just like when we created 2783the union, we need to get both parts of the union: the type and the data. 2784 2785We can access the type to dynamically cast the data as needed (since the union 2786only stores a FlatBuffer `table`). 2787 2788=== "C++" 2789 2790 ```c++ 2791 auto union_type = monster.equipped_type(); 2792 2793 if (union_type == Equipment_Weapon) { 2794 // Requires `static_cast` to type `const Weapon*`. 2795 auto weapon = static_cast<const Weapon*>(monster->equipped()); 2796 2797 auto weapon_name = weapon->name()->str(); // "Axe" 2798 auto weapon_damage = weapon->damage(); // 5 2799 } 2800 ``` 2801 2802=== "C" 2803 2804 ```c 2805 // Access union type field. 2806 if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) { 2807 // Cast to appropriate type: 2808 // C allows for silent void pointer assignment, so we need no 2809 // explicit cast. 2810 ns(Weapon_table_t) weapon = ns(Monster_equipped(monster)); 2811 const char *weapon_name = ns(Weapon_name(weapon)); // "Axe" 2812 uint16_t weapon_damage = ns(Weapon_damage(weapon)); // 5 2813 } 2814 ``` 2815 2816=== "C#" 2817 2818 ```c# 2819 var unionType = monster.EquippedType; 2820 2821 if (unionType == Equipment.Weapon) { 2822 var weapon = monster.Equipped<Weapon>().Value; 2823 2824 var weaponName = weapon.Name; // "Axe" 2825 var weaponDamage = weapon.Damage; // 5 2826 } 2827 ``` 2828 2829=== "Dart" 2830 2831 ```dart 2832 var unionType = monster.equippedType.value; 2833 2834 if (unionType == myGame.EquipmentTypeId.Weapon.value) { 2835 myGame.Weapon weapon = mon.equipped as myGame.Weapon; 2836 2837 var weaponName = weapon.name; // "Axe" 2838 var weaponDamage = weapon.damage; // 5 2839 } 2840 ``` 2841 2842=== "Go" 2843 2844 ```go 2845 // We need a `flatbuffers.Table` to capture the output of the 2846 // `monster.Equipped()` function. 2847 unionTable := new(flatbuffers.Table) 2848 2849 if monster.Equipped(unionTable) { 2850 unionType := monster.EquippedType() 2851 2852 if unionType == sample.EquipmentWeapon { 2853 // Create a `sample.Weapon` object that can be initialized with the 2854 // contents of the `flatbuffers.Table` (`unionTable`), which was 2855 // populated by `monster.Equipped()`. 2856 unionWeapon = new(sample.Weapon) 2857 unionWeapon.Init(unionTable.Bytes, unionTable.Pos) 2858 2859 weaponName = unionWeapon.Name() 2860 weaponDamage = unionWeapon.Damage() 2861 } 2862 } 2863 ``` 2864 2865=== "Java" 2866 2867 ```java 2868 int unionType = monster.EquippedType(); 2869 2870 if (unionType == Equipment.Weapon) { 2871 // Requires an explicit cast to `Weapon`. 2872 Weapon weapon = (Weapon)monster.equipped(new Weapon()); 2873 2874 String weaponName = weapon.name(); // "Axe" 2875 short weaponDamage = weapon.damage(); // 5 2876 } 2877 ``` 2878 2879=== "JavaScript" 2880 2881 ```javascript 2882 var unionType = monster.equippedType(); 2883 2884 if (unionType == MyGame.Sample.Equipment.Weapon) { 2885 // 'Axe' 2886 var weaponName = monster.equipped(new MyGame.Sample.Weapon()).name(); 2887 // 5 2888 var weaponDamage = 2889 monster.equipped(new MyGame.Sample.Weapon()).damage(); 2890 } 2891 ``` 2892 2893=== "Kotlin" 2894 2895 ```kotlin 2896 val unionType = monster.EquippedType 2897 2898 if (unionType == Equipment.Weapon) { 2899 // Requires an explicit cast to `Weapon`. 2900 val weapon = monster.equipped(Weapon()) as Weapon 2901 2902 val weaponName = weapon.name // "Axe" 2903 val weaponDamage = weapon.damage // 5 2904 } 2905 ``` 2906 2907=== "Lobster" 2908 2909 ```lobster 2910 union_type = monster.equipped_type 2911 2912 if union_type == MyGame_Sample_Equipment_Weapon: 2913 // `monster.equipped_as_Weapon` returns a FlatBuffer handle much like 2914 // normal table fields, but this is only valid to call if we already 2915 // know it is the correct type. 2916 let union_weapon = monster.equipped_as_Weapon 2917 2918 let weapon_name = union_weapon.name // "Axe" 2919 let weapon_damage = union_weapon.damage // 5 2920 ``` 2921 2922=== "Lua" 2923 2924 ```lua 2925 local unionType = mon:EquippedType() 2926 2927 if unionType == equipment.Weapon then 2928 local unionWeapon = weapon.New() 2929 unionWeapon:Init(mon:Equipped().bytes, mon:Equipped().pos) 2930 2931 local weaponName = unionWeapon:Name() -- 'Axe' 2932 local weaponDamage = unionWeapon:Damage() -- 5 2933 end 2934 ``` 2935 2936=== "PHP" 2937 2938 ```php 2939 $union_type = $monster->getEquippedType(); 2940 2941 if ($union_type == \MyGame\Sample\Equipment::Weapon) { 2942 // "Axe" 2943 $weapon_name = 2944 $monster->getEquipped(new \MyGame\Sample\Weapon())->getName(); 2945 // 5 2946 $weapon_damage = 2947 $monster->getEquipped(new \MyGame\Sample\Weapon())->getDamage(); 2948 } 2949 ``` 2950 2951=== "Python" 2952 2953 ```py 2954 union_type = monster.EquippedType() 2955 2956 if union_type == MyGame.Sample.Equipment.Equipment().Weapon: 2957 # `monster.Equipped()` returns a `flatbuffers.Table`, which can be used 2958 # to initialize a `MyGame.Sample.Weapon.Weapon()`. 2959 union_weapon = MyGame.Sample.Weapon.Weapon() 2960 union_weapon.Init(monster.Equipped().Bytes, monster.Equipped().Pos) 2961 2962 weapon_name = union_weapon.Name() // 'Axe' 2963 weapon_damage = union_weapon.Damage() // 5 2964 ``` 2965 2966=== "Rust" 2967 2968 ```rust 2969 // Get and test the `Equipment` union (`equipped` field). 2970 // `equipped_as_weapon` returns a FlatBuffer handle much like normal table 2971 // fields, but this will return `None` if the union is not actually of that 2972 // type. 2973 if monster.equipped_type() == Equipment::Weapon { 2974 let equipped = monster.equipped_as_weapon().unwrap(); 2975 let weapon_name = equipped.name(); 2976 let weapon_damage = equipped.damage(); 2977 ``` 2978 2979=== "Swift" 2980 2981 ```swift 2982 // Get and check if the monster has an equipped item 2983 if monster.equippedType == .weapon { 2984 let _weapon = monster.equipped(type: Weapon.self) 2985 let name = _weapon.name // should return "Axe" 2986 let dmg = _weapon.damage // should return 5 2987 } 2988 ``` 2989 2990=== "TypeScript" 2991 2992 ```ts 2993 let unionType = monster.equippedType(); 2994 2995 if (unionType == MyGame.Sample.Equipment.Weapon) { 2996 // 'Axe' 2997 let weaponName = monster.equipped(new MyGame.Sample.Weapon()).name(); 2998 // 5 2999 let weaponDamage = monster.equipped(new MyGame.Sample.Weapon()).damage(); 3000 } 3001 ``` 3002