aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Field <dfield@gmail.com>2018-05-18 14:06:15 -0400
committerWouter van Oortmerssen <aardappel@gmail.com>2018-05-18 11:06:15 -0700
commit88912640d08bab0588c5804d2990173006b57207 (patch)
tree5d451dd37682d66d40b85e4c3eeadd78e1a2a385
parentc43a0beff0ab4e1d5c5fe5044dfb30f24974eaff (diff)
downloadflatbuffers-88912640d08bab0588c5804d2990173006b57207.tar.gz
Add [Dart] support (#4676)
* Add [Dart] support * fix enum vectors * Allow for opt out of string interning * fix comment style, make interning opt in * remove Offset<T>, prefer int * avoid creating unnecessary vtable objects * start work on tests - do not generate builder if struct has 0 fields - add int64 * support reading structs properly * correctly handle reading vectors of structs, dartfmt * support structs, fix unnecessary prepares * fix bool customizations * undo unintentional removal of file * docs updates, complete tutorial, bug fix for codegen * more documentation * Update docs, add to doxygen file * update package structure, add samples script/code * rearrange sample * Tests * Add readme for pub * cleanup package for pub * update docs for renamed file * remove custom matcher, use `closeTo` instead * remove unintentional file * remove unintended file checkin * use auto, move method, cleanup * refactor to ObjectBuilders, add Builders * Update tests, examples * Add files missing from previous commit * documentation and example updates * Update LICENSE, make dartanalyzer happy, fix minor bugs, get rid of duplicate files, publish script * fix sample for slightly different schema * Update pubspec.yaml
-rw-r--r--.gitignore7
-rw-r--r--BUILD1
-rw-r--r--CMakeLists.txt1
-rw-r--r--dart/LICENSE233
-rw-r--r--dart/README.md13
-rw-r--r--dart/example/example.dart155
-rw-r--r--dart/example/monster_my_game.sample_generated.dart440
-rw-r--r--dart/lib/flat_buffers.dart1241
-rwxr-xr-xdart/publish.sh28
-rw-r--r--dart/pubspec.yaml18
-rw-r--r--dart/test/flat_buffers_test.dart573
-rw-r--r--dart/test/monster_test_my_game.example2_generated.dart60
-rw-r--r--dart/test/monster_test_my_game.example_generated.dart1332
-rw-r--r--dart/test/monster_test_my_game_generated.dart60
-rw-r--r--docs/source/Compiler.md2
-rw-r--r--docs/source/DartUsage.md108
-rw-r--r--docs/source/Support.md35
-rw-r--r--docs/source/Tutorial.md259
-rw-r--r--docs/source/doxyfile1
-rw-r--r--docs/source/doxygen_layout.xml2
-rw-r--r--include/flatbuffers/idl.h11
-rwxr-xr-xsamples/dart_sample.sh52
-rw-r--r--src/flatc_main.cpp3
-rw-r--r--src/idl_gen_dart.cpp890
-rwxr-xr-xtests/DartTest.sh34
-rw-r--r--tests/TestAll.sh4
-rwxr-xr-xtests/generate_code.sh4
27 files changed, 5547 insertions, 20 deletions
diff --git a/.gitignore b/.gitignore
index f5ff92c2..8f026d3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,7 @@ grpctest
grpctest.exe
snapshot.sh
tags
+tests/dart_gen
tests/go_gen
tests/monsterdata_java_wire.mon
tests/monsterdata_java_wire_sp.mon
@@ -94,3 +95,9 @@ js/flatbuffers.mjs
build.ninja
rules.ninja
.vscode
+dart/.pub/
+dart/.packages
+dart/pubspec.lock
+dart/.dart_tool/
+dart/build/
+dart/doc/api/
diff --git a/BUILD b/BUILD
index 4b109915..7610efca 100644
--- a/BUILD
+++ b/BUILD
@@ -86,6 +86,7 @@ cc_binary(
"grpc/src/compiler/schema_interface.h",
"src/flatc_main.cpp",
"src/idl_gen_cpp.cpp",
+ "src/idl_gen_dart.cpp",
"src/idl_gen_general.cpp",
"src/idl_gen_go.cpp",
"src/idl_gen_grpc.cpp",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a3388ddc..90860c35 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,6 +45,7 @@ set(FlatBuffers_Library_SRCS
set(FlatBuffers_Compiler_SRCS
${FlatBuffers_Library_SRCS}
src/idl_gen_cpp.cpp
+ src/idl_gen_dart.cpp
src/idl_gen_general.cpp
src/idl_gen_go.cpp
src/idl_gen_js.cpp
diff --git a/dart/LICENSE b/dart/LICENSE
new file mode 100644
index 00000000..b2ae013b
--- /dev/null
+++ b/dart/LICENSE
@@ -0,0 +1,233 @@
+The code in lib/flat_buffers.dart is based on code that was releases under the
+following license:
+
+Copyright 2012, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+To the extent permissible, the changes to that code and the other assets in
+this package are licensed under the Apache2 license:
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/dart/README.md b/dart/README.md
new file mode 100644
index 00000000..11bc0c48
--- /dev/null
+++ b/dart/README.md
@@ -0,0 +1,13 @@
+# FlatBuffers for Dart
+
+This package is used to read and write FlatBuffer files in Dart.
+
+Most consumers will want to use the [`flatc`](https://github.com/google/flatbuffers)
+compiler to generate Dart code from a FlatBuffers IDL schema. For example, the
+`monster_my_game.sample_generated.dart` was generated with `flatc` from
+`monster.fbs` in the example folder. The generated classes can be used to read
+or write binary files that are interoperable with other languages and platforms
+supported by FlatBuffers, as illustrated in the `example.dart` in the
+examples folder.
+
+Additional documentation and examples are available [at the FlatBuffers site](https://google.github.io/flatbuffers/index.html) \ No newline at end of file
diff --git a/dart/example/example.dart b/dart/example/example.dart
new file mode 100644
index 00000000..d95bb31f
--- /dev/null
+++ b/dart/example/example.dart
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2018 Dan Field. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+import './monster_my_game.sample_generated.dart' as myGame;
+
+// Example how to use FlatBuffers to create and read binary buffers.
+
+void main() {
+ builderTest();
+ objectBuilderTest();
+}
+
+void builderTest() {
+ final builder = new fb.Builder(initialSize: 1024);
+ 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();
+
+ // 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);
+ final weapons = builder.writeList([sword, axe]);
+
+ // Struct builders are very easy to reuse.
+ final vec3Builder = new myGame.Vec3Builder(builder);
+
+ vec3Builder.finish(4.0, 5.0, 6.0);
+ vec3Builder.finish(1.0, 2.0, 3.0);
+ // 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))
+ ..addColor(myGame.Color.Red);
+
+ final int monsteroff = monster.finish();
+ final buffer = builder.finish(monsteroff);
+ if (verify(buffer)) {
+ print(
+ "The FlatBuffer was successfully created with a builder and verified!");
+ }
+}
+
+void objectBuilderTest() {
+ // Create the builder here so we can use it for both weapons and equipped
+ // the actual data will only be written to the buffer once.
+ var axe = new myGame.WeaponObjectBuilder(name: 'Axe', damage: 5);
+
+ var monsterBuilder = new myGame.MonsterObjectBuilder(
+ pos: new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
+ mana: 150,
+ hp: 300,
+ name: 'Orc',
+ inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ color: myGame.Color.Red,
+ weapons: [new myGame.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
+ equippedType: myGame.EquipmentTypeId.Weapon,
+ equipped: axe,
+ );
+
+ var buffer = monsterBuilder.toBytes();
+
+ // We now have a FlatBuffer we can store on disk or send over a network.
+
+ // ** file/network code goes here :) **
+
+ // Instead, we're going to access it right away (as if we just received it).
+ if (verify(buffer)) {
+ print(
+ "The FlatBuffer was successfully created with an object builder and verified!");
+ }
+}
+
+bool verify(List<int> buffer) {
+ // Get access to the root:
+ var monster = new myGame.Monster(buffer);
+
+ // Get and test some scalar types from the FlatBuffer.
+ assert(monster.hp == 80);
+ assert(monster.mana == 150); // default
+ assert(monster.name == "MyMonster");
+
+ // Get and test a field of the FlatBuffer's `struct`.
+ var pos = monster.pos;
+ assert(pos != null);
+ assert(pos.z == 3.0);
+
+ // Get a test an element from the `inventory` FlatBuffer's `vector`.
+ var inv = monster.inventory;
+ assert(inv != null);
+ assert(inv.length == 10);
+ assert(inv[9] == 9);
+
+ // Get and test the `weapons` FlatBuffers's `vector`.
+ var expected_weapon_names = ["Sword", "Axe"];
+ var expected_weapon_damages = [3, 5];
+ var weps = monster.weapons;
+ for (int i = 0; i < weps.length; i++) {
+ assert(weps[i].name == expected_weapon_names[i]);
+ assert(weps[i].damage == expected_weapon_damages[i]);
+ }
+
+ // Get and test the `Equipment` union (`equipped` field).
+ assert(monster.equippedType.value == myGame.EquipmentTypeId.Weapon.value);
+ assert(monster.equippedType == myGame.EquipmentTypeId.Weapon);
+
+ assert(monster.equipped is myGame.Weapon);
+ var equipped = monster.equipped as myGame.Weapon;
+ assert(equipped.name == "Axe");
+ assert(equipped.damage == 5);
+
+ print(monster);
+ return true;
+}
diff --git a/dart/example/monster_my_game.sample_generated.dart b/dart/example/monster_my_game.sample_generated.dart
new file mode 100644
index 00000000..2c7c10d2
--- /dev/null
+++ b/dart/example/monster_my_game.sample_generated.dart
@@ -0,0 +1,440 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, non_constant_identifier_names
+
+library my_game.sample;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+
+class Color {
+ final int value;
+ const Color._(this.value);
+
+ factory Color.fromValue(int value) {
+ if (value == null) return null;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum Color');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 2;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const Color Red = const Color._(0);
+ static const Color Green = const Color._(1);
+ static const Color Blue = const Color._(2);
+ static get values => {0: Red,1: Green,2: Blue,};
+
+ static const fb.Reader<Color> reader = const _ColorReader();
+
+ @override
+ String toString() {
+ return 'Color{value: $value}';
+ }
+}
+
+class _ColorReader extends fb.Reader<Color> {
+ const _ColorReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ Color read(fb.BufferContext bc, int offset) =>
+ new Color.fromValue(const fb.Int8Reader().read(bc, offset));
+}
+
+class EquipmentTypeId {
+ final int value;
+ const EquipmentTypeId._(this.value);
+
+ factory EquipmentTypeId.fromValue(int value) {
+ if (value == null) return null;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum EquipmentTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 1;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const EquipmentTypeId NONE = const EquipmentTypeId._(0);
+ static const EquipmentTypeId Weapon = const EquipmentTypeId._(1);
+ static get values => {0: NONE,1: Weapon,};
+
+ static const fb.Reader<EquipmentTypeId> reader = const _EquipmentTypeIdReader();
+
+ @override
+ String toString() {
+ return 'EquipmentTypeId{value: $value}';
+ }
+}
+
+class _EquipmentTypeIdReader extends fb.Reader<EquipmentTypeId> {
+ const _EquipmentTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ EquipmentTypeId read(fb.BufferContext bc, int offset) =>
+ new EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class Vec3 {
+ Vec3._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Vec3> reader = const _Vec3Reader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
+ double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
+ double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
+
+ @override
+ String toString() {
+ return 'Vec3{x: $x, y: $y, z: $z}';
+ }
+}
+
+class _Vec3Reader extends fb.StructReader<Vec3> {
+ const _Vec3Reader();
+
+ @override
+ int get size => 12;
+
+ @override
+ Vec3 createObject(fb.BufferContext bc, int offset) =>
+ new Vec3._(bc, offset);
+}
+
+class Vec3Builder {
+ Vec3Builder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(double x, double y, double z) {
+ fbBuilder.putFloat32(z);
+ fbBuilder.putFloat32(y);
+ fbBuilder.putFloat32(x);
+ return fbBuilder.offset;
+ }
+
+}
+
+class Vec3ObjectBuilder extends fb.ObjectBuilder {
+ final double _x;
+ final double _y;
+ final double _z;
+
+ Vec3ObjectBuilder({
+ double x,
+ double y,
+ double z,
+ })
+ : _x = x,
+ _y = y,
+ _z = z;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.putFloat32(_z);
+ fbBuilder.putFloat32(_y);
+ fbBuilder.putFloat32(_x);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+ int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
+ int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
+ List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
+ Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
+ List<Weapon> get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGet(_bc, _bcOffset, 18, null);
+ EquipmentTypeId get equippedType => new EquipmentTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 20, null));
+ dynamic get equipped {
+ switch (equippedType?.value) {
+ case 1: return Weapon.reader.vTableGet(_bc, _bcOffset, 22, null);
+ default: return null;
+ }
+ }
+ List<Vec3> get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGet(_bc, _bcOffset, 24, null);
+
+ @override
+ String toString() {
+ return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, weapons: $weapons, equippedType: $equippedType, equipped: $equipped, path: $path}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterBuilder {
+ MonsterBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addPos(int offset) {
+ fbBuilder.addStruct(0, offset);
+ return fbBuilder.offset;
+ }
+ int addMana(int mana) {
+ fbBuilder.addInt16(1, mana);
+ return fbBuilder.offset;
+ }
+ int addHp(int hp) {
+ fbBuilder.addInt16(2, hp);
+ return fbBuilder.offset;
+ }
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(3, offset);
+ return fbBuilder.offset;
+ }
+ int addInventoryOffset(int offset) {
+ fbBuilder.addOffset(5, offset);
+ return fbBuilder.offset;
+ }
+ int addColor(Color color) {
+ fbBuilder.addInt8(6, color?.value);
+ return fbBuilder.offset;
+ }
+ int addWeaponsOffset(int offset) {
+ fbBuilder.addOffset(7, offset);
+ return fbBuilder.offset;
+ }
+ int addEquippedType(EquipmentTypeId equippedType) {
+ fbBuilder.addUint8(8, equippedType?.value);
+ return fbBuilder.offset;
+ }
+ int addEquippedOffset(int offset) {
+ fbBuilder.addOffset(9, offset);
+ return fbBuilder.offset;
+ }
+ int addPathOffset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+ final Vec3ObjectBuilder _pos;
+ final int _mana;
+ final int _hp;
+ final String _name;
+ final List<int> _inventory;
+ final Color _color;
+ final List<WeaponObjectBuilder> _weapons;
+ final EquipmentTypeId _equippedType;
+ final dynamic _equipped;
+ final List<Vec3ObjectBuilder> _path;
+
+ MonsterObjectBuilder({
+ Vec3ObjectBuilder pos,
+ int mana,
+ int hp,
+ String name,
+ List<int> inventory,
+ Color color,
+ List<WeaponObjectBuilder> weapons,
+ EquipmentTypeId equippedType,
+ dynamic equipped,
+ List<Vec3ObjectBuilder> path,
+ })
+ : _pos = pos,
+ _mana = mana,
+ _hp = hp,
+ _name = name,
+ _inventory = inventory,
+ _color = color,
+ _weapons = weapons,
+ _equippedType = equippedType,
+ _equipped = equipped,
+ _path = path;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+ final int inventoryOffset = _inventory?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_inventory)
+ : null;
+ final int weaponsOffset = _weapons?.isNotEmpty == true
+ ? fbBuilder.writeList(_weapons.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
+ final int pathOffset = _path?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_path)
+ : null;
+
+ fbBuilder.startTable();
+ if (_pos != null) {
+ fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+ }
+ fbBuilder.addInt16(1, _mana);
+ fbBuilder.addInt16(2, _hp);
+ if (nameOffset != null) {
+ fbBuilder.addOffset(3, nameOffset);
+ }
+ if (inventoryOffset != null) {
+ fbBuilder.addOffset(5, inventoryOffset);
+ }
+ fbBuilder.addInt8(6, _color?.value);
+ if (weaponsOffset != null) {
+ fbBuilder.addOffset(7, weaponsOffset);
+ }
+ fbBuilder.addUint8(8, _equippedType?.value);
+ if (equippedOffset != null) {
+ fbBuilder.addOffset(9, equippedOffset);
+ }
+ if (pathOffset != null) {
+ fbBuilder.addOffset(10, pathOffset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Weapon {
+ Weapon._(this._bc, this._bcOffset);
+ factory Weapon(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Weapon> reader = const _WeaponReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
+ int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, null);
+
+ @override
+ String toString() {
+ return 'Weapon{name: $name, damage: $damage}';
+ }
+}
+
+class _WeaponReader extends fb.TableReader<Weapon> {
+ const _WeaponReader();
+
+ @override
+ Weapon createObject(fb.BufferContext bc, int offset) =>
+ new Weapon._(bc, offset);
+}
+
+class WeaponBuilder {
+ WeaponBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addDamage(int damage) {
+ fbBuilder.addInt16(1, damage);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class WeaponObjectBuilder extends fb.ObjectBuilder {
+ final String _name;
+ final int _damage;
+
+ WeaponObjectBuilder({
+ String name,
+ int damage,
+ })
+ : _name = name,
+ _damage = damage;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+
+ fbBuilder.startTable();
+ if (nameOffset != null) {
+ fbBuilder.addOffset(0, nameOffset);
+ }
+ fbBuilder.addInt16(1, _damage);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/dart/lib/flat_buffers.dart b/dart/lib/flat_buffers.dart
new file mode 100644
index 00000000..baef5a35
--- /dev/null
+++ b/dart/lib/flat_buffers.dart
@@ -0,0 +1,1241 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:math';
+import 'dart:typed_data';
+
+const int _sizeofUint8 = 1;
+const int _sizeofUint16 = 2;
+const int _sizeofUint32 = 4;
+const int _sizeofUint64 = 8;
+const int _sizeofInt8 = 1;
+const int _sizeofInt16 = 2;
+const int _sizeofInt32 = 4;
+const int _sizeofInt64 = 8;
+const int _sizeofFloat32 = 4;
+const int _sizeofFloat64 = 8;
+
+/// Callback used to invoke a struct builder's finish method.
+///
+/// This callback is used by other struct's `finish` methods to write the nested
+/// struct's fields inline.
+typedef void StructBuilder();
+
+/// Buffer with data and some context about it.
+class BufferContext {
+ final ByteData _buffer;
+
+ factory BufferContext.fromBytes(List<int> byteList) {
+ Uint8List uint8List = _asUint8List(byteList);
+ ByteData buf = new ByteData.view(uint8List.buffer, uint8List.offsetInBytes);
+ return new BufferContext._(buf);
+ }
+
+ BufferContext._(this._buffer);
+
+ int derefObject(int offset) {
+ return offset + _getUint32(offset);
+ }
+
+ Uint8List _asUint8LIst(int offset, int length) =>
+ _buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length);
+
+ double _getFloat64(int offset) =>
+ _buffer.getFloat64(offset, Endianness.LITTLE_ENDIAN);
+
+ double _getFloat32(int offset) =>
+ _buffer.getFloat32(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getInt64(int offset) =>
+ _buffer.getInt64(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getInt32(int offset) =>
+ _buffer.getInt32(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getInt16(int offset) =>
+ _buffer.getInt16(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getInt8(int offset) => _buffer.getInt8(offset);
+
+ int _getUint64(int offset) =>
+ _buffer.getUint64(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getUint32(int offset) =>
+ _buffer.getUint32(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getUint16(int offset) =>
+ _buffer.getUint16(offset, Endianness.LITTLE_ENDIAN);
+
+ int _getUint8(int offset) => _buffer.getUint8(offset);
+
+ /// If the [byteList] is already a [Uint8List] return it.
+ /// Otherwise return a [Uint8List] copy of the [byteList].
+ static Uint8List _asUint8List(List<int> byteList) {
+ if (byteList is Uint8List) {
+ return byteList;
+ } else {
+ return new Uint8List.fromList(byteList);
+ }
+ }
+}
+
+/// Class implemented by typed builders generated by flatc.
+abstract class ObjectBuilder {
+ int _firstOffset;
+
+ /// Can be used to write the data represented by this builder to the [Builder]
+ /// and reuse the offset created in multiple tables.
+ ///
+ /// Note that this method assumes you call it using the same [Builder] instance
+ /// every time. The returned offset is only good for the [Builder] used in the
+ /// first call to this method.
+ int getOrCreateOffset(Builder fbBuilder) {
+ _firstOffset ??= finish(fbBuilder);
+ return _firstOffset;
+ }
+
+ /// Writes the data in this helper to the [Builder].
+ int finish(Builder fbBuilder);
+
+ /// Convenience method that will create a new [Builder], [finish]es the data,
+ /// and returns the buffer as a [Uint8List] of bytes.
+ Uint8List toBytes();
+}
+
+/// Class that helps building flat buffers.
+class Builder {
+ final int initialSize;
+
+ /// The list of existing VTable(s).
+ //final List<_VTable> _vTables = <_VTable>[];
+ final List<int> _vTables = <int>[];
+
+ ByteData _buf;
+
+ /// The maximum alignment that has been seen so far. If [_buf] has to be
+ /// reallocated in the future (to insert room at its start for more bytes) the
+ /// reallocation will need to be a multiple of this many bytes.
+ int _maxAlign;
+
+ /// The number of bytes that have been written to the buffer so far. The
+ /// most recently written byte is this many bytes from the end of [_buf].
+ int _tail;
+
+ /// The location of the end of the current table, measured in bytes from the
+ /// end of [_buf], or `null` if a table is not currently being built.
+ int _currentTableEndTail;
+
+ _VTable _currentVTable;
+
+ /// Map containing all strings that have been written so far. This allows us
+ /// to avoid duplicating strings.
+ ///
+ /// Allocated only if `internStrings` is set to true on the constructor.
+ Map<String, int> _strings;
+
+ /// Creates a new FlatBuffers Builder.
+ ///
+ /// `initialSize` is the initial array size in bytes. The [Builder] will
+ /// automatically grow the array if/as needed. `internStrings`, if set to
+ /// true, will cause [writeString] to pool strings in the buffer so that
+ /// identical strings will always use the same offset in tables.
+ Builder({this.initialSize: 1024, bool internStrings = false}) {
+ if (internStrings == true) {
+ _strings = new Map<String, int>();
+ }
+ reset();
+ }
+
+ /// Add the [field] with the given boolean [value]. The field is not added if
+ /// the [value] is equal to [def]. Booleans are stored as 8-bit fields with
+ /// `0` for `false` and `1` for `true`.
+ void addBool(int field, bool value, [bool def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint8, 1);
+ _trackField(field);
+ _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit signed integer [value]. The field is
+ /// not added if the [value] is equal to [def].
+ void addInt32(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt32, 1);
+ _trackField(field);
+ _setInt32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit signed integer [value]. The field is
+ /// not added if the [value] is equal to [def].
+ void addInt16(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt16, 1);
+ _trackField(field);
+ _setInt16AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 8-bit signed integer [value]. The field is
+ /// not added if the [value] is equal to [def].
+ void addInt8(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt8, 1);
+ _trackField(field);
+ _setInt8AtTail(_buf, _tail, value);
+ }
+ }
+
+ void addStruct(int field, int offset) {
+ _ensureCurrentVTable();
+ _trackField(field);
+ _currentVTable.addField(field, offset);
+ }
+
+ /// Add the [field] referencing an object with the given [offset].
+ void addOffset(int field, int offset) {
+ _ensureCurrentVTable();
+ if (offset != null) {
+ _prepare(_sizeofUint32, 1);
+ _trackField(field);
+ _setUint32AtTail(_buf, _tail, _tail - offset);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint32(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint32, 1);
+ _trackField(field);
+ _setUint32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint16(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint16, 1);
+ _trackField(field);
+ _setUint16AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 8-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint8(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint8, 1);
+ _trackField(field);
+ _setUint8AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit float [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addFloat32(int field, double value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofFloat32, 1);
+ _trackField(field);
+ _setFloat32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 64-bit double [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addFloat64(int field, double value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofFloat64, 1);
+ _trackField(field);
+ _setFloat64AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 64-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint64(int field, int value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint64, 1);
+ _trackField(field);
+ _setUint64AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 64-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addInt64(int field, int value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt64, 1);
+ _trackField(field);
+ _setInt64AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// End the current table and return its offset.
+ int endTable() {
+ if (_currentVTable == null) {
+ throw new StateError('Start a table before ending it.');
+ }
+ // Prepare for writing the VTable.
+ _prepare(_sizeofInt32, 1);
+ int tableTail = _tail;
+ // Prepare the size of the current table.
+ _currentVTable.tableSize = tableTail - _currentTableEndTail;
+ // Prepare the VTable to use for the current table.
+ int vTableTail;
+ {
+ _currentVTable.computeFieldOffsets(tableTail);
+ // Try to find an existing compatible VTable.
+ // Search backward - more likely to have recently used one
+ for (int i = _vTables.length - 1; i >= 0; i--) {
+ final int vt2Offset = _vTables[i];
+ final int vt2Start = _buf.lengthInBytes - vt2Offset;
+ final int vt2Size = _buf.getUint16(vt2Start, Endianness.LITTLE_ENDIAN);
+
+ if (_currentVTable._vTableSize == vt2Size &&
+ _currentVTable._offsetsMatch(vt2Start, _buf)) {
+ vTableTail = vt2Offset;
+ break;
+ }
+ }
+ // Write a new VTable.
+ if (vTableTail == null) {
+ _prepare(_sizeofUint16, _currentVTable.numOfUint16);
+ vTableTail = _tail;
+ _currentVTable.tail = vTableTail;
+ _currentVTable.output(_buf, _buf.lengthInBytes - _tail);
+ _vTables.add(_currentVTable.tail);
+ }
+ }
+ // Set the VTable offset.
+ _setInt32AtTail(_buf, tableTail, vTableTail - tableTail);
+ // Done with this table.
+ _currentVTable = null;
+ return tableTail;
+ }
+
+ /// This method low level method can be used to return a raw piece of the buffer
+ /// after using the the put* methods.
+ ///
+ /// Most clients should prefer calling [finish].
+ Uint8List lowFinish() {
+ int alignedTail = _tail + ((-_tail) % _maxAlign);
+ return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
+ }
+
+ /// Finish off the creation of the buffer. The given [offset] is used as the
+ /// root object offset, and usually references directly or indirectly every
+ /// written object. If [fileIdentifier] is specified (and not `null`), it is
+ /// interpreted as a 4-byte Latin-1 encoded string that should be placed at
+ /// bytes 4-7 of the file.
+ Uint8List finish(int offset, [String fileIdentifier]) {
+ _prepare(max(_sizeofUint32, _maxAlign), fileIdentifier == null ? 1 : 2);
+ int alignedTail = _tail + ((-_tail) % _maxAlign);
+ _setUint32AtTail(_buf, alignedTail, alignedTail - offset);
+ if (fileIdentifier != null) {
+ for (int i = 0; i < 4; i++) {
+ _setUint8AtTail(_buf, alignedTail - _sizeofUint32 - i,
+ fileIdentifier.codeUnitAt(i));
+ }
+ }
+ return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
+ }
+
+ /// Writes a Float64 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putFloat64(double value) {
+ _prepare(_sizeofFloat64, 1);
+ _setFloat32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Float32 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putFloat32(double value) {
+ _prepare(_sizeofFloat32, 1);
+ _setFloat32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Int64 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt64(int value) {
+ _prepare(_sizeofInt64, 1);
+ _setInt64AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint32 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt32(int value) {
+ _prepare(_sizeofInt32, 1);
+ _setInt32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint16 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt16(int value) {
+ _prepare(_sizeofInt16, 1);
+ _setInt16AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint8 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt8(int value) {
+ _prepare(_sizeofInt8, 1);
+ _buf.setInt8(_buf.lengthInBytes - _tail, value);
+ }
+
+ /// Writes a Uint64 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint64(int value) {
+ _prepare(_sizeofUint64, 1);
+ _setUint64AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint32 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint32(int value) {
+ _prepare(_sizeofUint32, 1);
+ _setUint32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint16 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint16(int value) {
+ _prepare(_sizeofUint16, 1);
+ _setUint16AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint8 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint8(int value) {
+ _prepare(_sizeofUint8, 1);
+ _buf.setUint8(_buf.lengthInBytes - _tail, value);
+ }
+
+ /// Reset the builder and make it ready for filling a new buffer.
+ void reset() {
+ _buf = new ByteData(initialSize);
+ _maxAlign = 1;
+ _tail = 0;
+ _currentVTable = null;
+ if (_strings != null) {
+ _strings = new Map<String, int>();
+ }
+ }
+
+ /// Start a new table. Must be finished with [endTable] invocation.
+ void startTable() {
+ if (_currentVTable != null) {
+ throw new StateError('Inline tables are not supported.');
+ }
+ _currentVTable = new _VTable();
+ _currentTableEndTail = _tail;
+ }
+
+ /// Finish a Struct vector. Most callers should preferto use [writeListOfStructs].
+ ///
+ /// Most callers should prefer [writeListOfStructs].
+ int endStructVector(int count) {
+ putUint32(count);
+ return _tail;
+ }
+
+ /// Writes a list of Structs to the buffer, returning the offset
+ int writeListOfStructs(List<ObjectBuilder> structBuilders) {
+ _ensureNoVTable();
+ for (int i = structBuilders.length - 1; i >= 0; i--) {
+ structBuilders[i].finish(this);
+ }
+ return endStructVector(structBuilders.length);
+ }
+
+ /// Write the given list of [values].
+ int writeList(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint32AtTail(_buf, tail, tail - value);
+ tail -= _sizeofUint32;
+ }
+ return result;
+ }
+
+ /// Write the given list of 64-bit float [values].
+ int writeListFloat64(List<double> values) {
+ _ensureNoVTable();
+ _prepare(4, 1 + (2 * values.length));
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (double value in values) {
+ _setFloat64AtTail(_buf, tail, value);
+ tail -= _sizeofFloat64;
+ }
+ return result;
+ }
+
+ /// Write the given list of 32-bit float [values].
+ int writeListFloat32(List<double> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofFloat32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (double value in values) {
+ _setFloat32AtTail(_buf, tail, value);
+ tail -= _sizeofFloat32;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 64-bit integer [values].
+ int writeListInt64(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt64AtTail(_buf, tail, value);
+ tail -= _sizeofInt64;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 64-bit integer [values].
+ int writeListUint64(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint64AtTail(_buf, tail, value);
+ tail -= _sizeofUint64;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 32-bit integer [values].
+ int writeListInt32(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt32AtTail(_buf, tail, value);
+ tail -= _sizeofInt32;
+ }
+ return result;
+ }
+
+ /// Write the given list of unsigned 32-bit integer [values].
+ int writeListUint32(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint32AtTail(_buf, tail, value);
+ tail -= _sizeofUint32;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 16-bit integer [values].
+ int writeListInt16(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt16AtTail(_buf, tail, value);
+ tail -= _sizeofInt16;
+ }
+ return result;
+ }
+
+ /// Write the given list of unsigned 16-bit integer [values].
+ int writeListUint16(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint16AtTail(_buf, tail, value);
+ tail -= _sizeofUint16;
+ }
+ return result;
+ }
+
+ /// Write the given list of bools as unsigend 8-bit integer [values].
+ int writeListBool(List<bool> values) {
+ return writeListUint8(values?.map((b) => b ? 1 : 0)?.toList());
+ }
+
+ /// Write the given list of signed 8-bit integer [values].
+ int writeListInt8(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt8AtTail(_buf, tail, value);
+ tail -= _sizeofUint8;
+ }
+ return result;
+ }
+
+ /// Write the given list of unsigned 8-bit integer [values].
+ int writeListUint8(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint8AtTail(_buf, tail, value);
+ tail -= _sizeofUint8;
+ }
+ return result;
+ }
+
+ /// Write the given string [value] and return its offset, or `null` if
+ /// the [value] is `null`.
+ int writeString(String value) {
+ _ensureNoVTable();
+ if (value != null) {
+ if (_strings != null) {
+ return _strings.putIfAbsent(value, () => _writeString(value));
+ } else {
+ return _writeString(value);
+ }
+ }
+ return null;
+ }
+
+ int _writeString(String value) {
+ // TODO(scheglov) optimize for ASCII strings
+ List<int> bytes = UTF8.encode(value);
+ int length = bytes.length;
+ _prepare(4, 1, additionalBytes: length);
+ final int result = _tail;
+ _setUint32AtTail(_buf, _tail, length);
+ int offset = _buf.lengthInBytes - _tail + 4;
+ for (int i = 0; i < length; i++) {
+ _buf.setUint8(offset++, bytes[i]);
+ }
+ return result;
+ }
+
+ /// Throw an exception if there is not currently a vtable.
+ void _ensureCurrentVTable() {
+ if (_currentVTable == null) {
+ throw new StateError('Start a table before adding values.');
+ }
+ }
+
+ /// Throw an exception if there is currently a vtable.
+ void _ensureNoVTable() {
+ if (_currentVTable != null) {
+ throw new StateError(
+ 'Cannot write a non-scalar value while writing a table.');
+ }
+ }
+
+ /// The number of bytes that have been written to the buffer so far. The
+ /// most recently written byte is this many bytes from the end of the buffer.
+ int get offset => _tail;
+
+ /// Zero-pads the buffer, which may be required for some struct layouts.
+ void pad(int howManyBytes) {
+ for (int i = 0; i < howManyBytes; i++) putUint8(0);
+ }
+
+ /// Prepare for writing the given `count` of scalars of the given `size`.
+ /// Additionally allocate the specified `additionalBytes`. Update the current
+ /// tail pointer to point at the allocated space.
+ void _prepare(int size, int count, {int additionalBytes = 0}) {
+ // Update the alignment.
+ if (_maxAlign < size) {
+ _maxAlign = size;
+ }
+ // Prepare amount of required space.
+ int dataSize = size * count + additionalBytes;
+ int alignDelta = (-(_tail + dataSize)) % size;
+ int bufSize = alignDelta + dataSize;
+ // Ensure that we have the required amount of space.
+ {
+ int oldCapacity = _buf.lengthInBytes;
+ if (_tail + bufSize > oldCapacity) {
+ int desiredNewCapacity = (oldCapacity + bufSize) * 2;
+ int deltaCapacity = desiredNewCapacity - oldCapacity;
+ deltaCapacity += (-deltaCapacity) % _maxAlign;
+ int newCapacity = oldCapacity + deltaCapacity;
+ ByteData newBuf = new ByteData(newCapacity);
+ newBuf.buffer
+ .asUint8List()
+ .setAll(deltaCapacity, _buf.buffer.asUint8List());
+ _buf = newBuf;
+ }
+ }
+ // Update the tail pointer.
+ _tail += bufSize;
+ }
+
+ /// Record the offset of the given [field].
+ void _trackField(int field) {
+ _currentVTable.addField(field, _tail);
+ }
+
+ static void _setFloat64AtTail(ByteData _buf, int tail, double x) {
+ _buf.setFloat64(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setFloat32AtTail(ByteData _buf, int tail, double x) {
+ _buf.setFloat32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setUint64AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint64(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setInt64AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt64(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setInt32AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setUint32AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setInt16AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt16(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setUint16AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint16(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+ }
+
+ static void _setInt8AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt8(_buf.lengthInBytes - tail, x);
+ }
+
+ static void _setUint8AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint8(_buf.lengthInBytes - tail, x);
+ }
+}
+
+/// Reader of lists of boolean values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class BoolListReader extends Reader<List<bool>> {
+ const BoolListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<bool> read(BufferContext bc, int offset) =>
+ new _FbBoolList(bc, bc.derefObject(offset));
+}
+
+/// The reader of booleans.
+class BoolReader extends Reader<bool> {
+ const BoolReader() : super();
+
+ @override
+ int get size => _sizeofUint8;
+
+ @override
+ bool read(BufferContext bc, int offset) => bc._getInt8(offset) != 0;
+}
+
+/// The reader of lists of 64-bit float values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Float64ListReader extends Reader<List<double>> {
+ const Float64ListReader();
+
+ @override
+ int get size => _sizeofFloat64;
+
+ @override
+ List<double> read(BufferContext bc, int offset) =>
+ new _FbFloat64List(bc, bc.derefObject(offset));
+}
+
+class Float32ListReader extends Reader<List<double>> {
+ const Float32ListReader();
+
+ @override
+ int get size => _sizeofFloat32;
+
+ @override
+ List<double> read(BufferContext bc, int offset) =>
+ new _FbFloat32List(bc, bc.derefObject(offset));
+}
+
+class Float64Reader extends Reader<double> {
+ const Float64Reader();
+
+ @override
+ int get size => _sizeofFloat64;
+
+ @override
+ double read(BufferContext bc, int offset) => bc._getFloat64(offset);
+}
+
+class Float32Reader extends Reader<double> {
+ const Float32Reader();
+
+ @override
+ int get size => _sizeofFloat32;
+
+ @override
+ double read(BufferContext bc, int offset) => bc._getFloat32(offset);
+}
+
+class Int64Reader extends Reader<int> {
+ const Int64Reader() : super();
+ @override
+ int get size => _sizeofInt64;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt64(offset);
+}
+
+/// The reader of signed 32-bit integers.
+class Int32Reader extends Reader<int> {
+ const Int32Reader() : super();
+
+ @override
+ int get size => _sizeofInt32;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt32(offset);
+}
+
+/// The reader of signed 32-bit integers.
+class Int16Reader extends Reader<int> {
+ const Int16Reader() : super();
+
+ @override
+ int get size => _sizeofInt16;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt16(offset);
+}
+
+/// The reader of 8-bit signed integers.
+class Int8Reader extends Reader<int> {
+ const Int8Reader() : super();
+
+ @override
+ int get size => _sizeofInt8;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt8(offset);
+}
+
+/// The reader of lists of objects.
+///
+/// The returned unmodifiable lists lazily read objects on access.
+class ListReader<E> extends Reader<List<E>> {
+ final Reader<E> _elementReader;
+
+ const ListReader(this._elementReader);
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<E> read(BufferContext bc, int offset) =>
+ new _FbGenericList<E>(_elementReader, bc, bc.derefObject(offset));
+}
+
+/// Object that can read a value at a [BufferContext].
+abstract class Reader<T> {
+ const Reader();
+
+ /// The size of the value in bytes.
+ int get size;
+
+ /// Read the value at the given [offset] in [bc].
+ T read(BufferContext bc, int offset);
+
+ /// Read the value of the given [field] in the given [object].
+ T vTableGet(BufferContext object, int offset, int field, [T defaultValue]) {
+ int vTableSOffset = object._getInt32(offset);
+ int vTableOffset = offset - vTableSOffset;
+ int vTableSize = object._getUint16(vTableOffset);
+ int vTableFieldOffset = field;
+ if (vTableFieldOffset < vTableSize) {
+ int fieldOffsetInObject =
+ object._getUint16(vTableOffset + vTableFieldOffset);
+ if (fieldOffsetInObject != 0) {
+ return read(object, offset + fieldOffsetInObject);
+ }
+ }
+ return defaultValue;
+ }
+}
+
+/// The reader of string values.
+class StringReader extends Reader<String> {
+ const StringReader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ String read(BufferContext bc, int offset) {
+ int strOffset = bc.derefObject(offset);
+ int length = bc._getUint32(strOffset);
+ Uint8List bytes = bc._asUint8LIst(strOffset + 4, length);
+ if (_isLatin(bytes)) {
+ return new String.fromCharCodes(bytes);
+ }
+ return UTF8.decode(bytes);
+ }
+
+ static bool _isLatin(Uint8List bytes) {
+ int length = bytes.length;
+ for (int i = 0; i < length; i++) {
+ if (bytes[i] > 127) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+/// An abstract reader for structs.
+abstract class StructReader<T> extends Reader<T> {
+ const StructReader();
+
+ /// Return the object at `offset`.
+ T createObject(BufferContext bc, int offset);
+
+ T read(BufferContext bp, int offset) {
+ return createObject(bp, offset);
+ }
+}
+
+/// An abstract reader for tables.
+abstract class TableReader<T> extends Reader<T> {
+ const TableReader();
+
+ @override
+ int get size => 4;
+
+ /// Return the object at [offset].
+ T createObject(BufferContext bc, int offset);
+
+ @override
+ T read(BufferContext bp, int offset) {
+ int objectOffset = bp.derefObject(offset);
+ return createObject(bp, objectOffset);
+ }
+}
+
+/// Reader of lists of unsigned 32-bit integer values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Uint32ListReader extends Reader<List<int>> {
+ const Uint32ListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<int> read(BufferContext bc, int offset) =>
+ new _FbUint32List(bc, bc.derefObject(offset));
+}
+
+/// The reader of unsigned 64-bit integers.
+///
+/// WARNING: May have compatibility issues with JavaScript
+class Uint64Reader extends Reader<int> {
+ const Uint64Reader() : super();
+
+ @override
+ int get size => _sizeofUint64;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint64(offset);
+}
+
+/// The reader of unsigned 32-bit integers.
+class Uint32Reader extends Reader<int> {
+ const Uint32Reader() : super();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint32(offset);
+}
+
+/// Reader of lists of unsigned 32-bit integer values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Uint16ListReader extends Reader<List<int>> {
+ const Uint16ListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<int> read(BufferContext bc, int offset) =>
+ new _FbUint16List(bc, bc.derefObject(offset));
+}
+
+/// The reader of unsigned 32-bit integers.
+class Uint16Reader extends Reader<int> {
+ const Uint16Reader() : super();
+
+ @override
+ int get size => _sizeofUint16;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint16(offset);
+}
+
+/// Reader of lists of unsigned 8-bit integer values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Uint8ListReader extends Reader<List<int>> {
+ const Uint8ListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<int> read(BufferContext bc, int offset) =>
+ new _FbUint8List(bc, bc.derefObject(offset));
+}
+
+/// The reader of unsigned 8-bit integers.
+class Uint8Reader extends Reader<int> {
+ const Uint8Reader() : super();
+
+ @override
+ int get size => _sizeofUint8;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint8(offset);
+}
+
+/// The list backed by 64-bit values - Uint64 length and Float64.
+class _FbFloat64List extends _FbList<double> {
+ _FbFloat64List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ double operator [](int i) {
+ return bc._getFloat64(offset + 4 + 8 * i);
+ }
+}
+
+/// The list backed by 32-bit values - Float32.
+class _FbFloat32List extends _FbList<double> {
+ _FbFloat32List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ double operator [](int i) {
+ return bc._getFloat32(offset + 4 + 4 * i);
+ }
+}
+
+/// List backed by a generic object which may have any size.
+class _FbGenericList<E> extends _FbList<E> {
+ final Reader<E> elementReader;
+
+ List<E> _items;
+
+ _FbGenericList(this.elementReader, BufferContext bp, int offset)
+ : super(bp, offset);
+
+ @override
+ E operator [](int i) {
+ _items ??= new List<E>(length);
+ E item = _items[i];
+ if (item == null) {
+ item = elementReader.read(bc, offset + 4 + elementReader.size * i);
+ _items[i] = item;
+ }
+ return item;
+ }
+}
+
+/// The base class for immutable lists read from flat buffers.
+abstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
+ final BufferContext bc;
+ final int offset;
+ int _length;
+
+ _FbList(this.bc, this.offset);
+
+ @override
+ int get length {
+ _length ??= bc._getUint32(offset);
+ return _length;
+ }
+
+ @override
+ void set length(int i) =>
+ throw new StateError('Attempt to modify immutable list');
+
+ @override
+ void operator []=(int i, E e) =>
+ throw new StateError('Attempt to modify immutable list');
+}
+
+/// List backed by 32-bit unsigned integers.
+class _FbUint32List extends _FbList<int> {
+ _FbUint32List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ int operator [](int i) {
+ return bc._getUint32(offset + 4 + 4 * i);
+ }
+}
+
+/// List backed by 16-bit unsigned integers.
+class _FbUint16List extends _FbList<int> {
+ _FbUint16List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ int operator [](int i) {
+ return bc._getUint16(offset + 4 + 2 * i);
+ }
+}
+
+/// List backed by 8-bit unsigned integers.
+class _FbUint8List extends _FbList<int> {
+ _FbUint8List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ int operator [](int i) {
+ return bc._getUint8(offset + 4 + i);
+ }
+}
+
+/// List backed by 8-bit unsigned integers.
+class _FbBoolList extends _FbList<bool> {
+ _FbBoolList(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ bool operator [](int i) {
+ return bc._getUint8(offset + 4 + i) == 1 ? true : false;
+ }
+}
+
+/// Class that describes the structure of a table.
+class _VTable {
+ static const int _metadataLength = 4;
+
+ final List<int> fieldTails = <int>[];
+ final List<int> fieldOffsets = <int>[];
+
+ /// The size of the table that uses this VTable.
+ int tableSize;
+
+ /// The tail of this VTable. It is used to share the same VTable between
+ /// multiple tables of identical structure.
+ int tail;
+
+ int get _vTableSize => numOfUint16 * _sizeofUint16;
+
+ int get numOfUint16 => 1 + 1 + fieldTails.length;
+
+ void addField(int field, int offset) {
+ while (fieldTails.length <= field) {
+ fieldTails.add(null);
+ }
+ fieldTails[field] = offset;
+ }
+
+ bool _offsetsMatch(int vt2Start, ByteData buf) {
+ for (int i = 0; i < fieldOffsets.length; i++) {
+ if (fieldOffsets[i] !=
+ buf.getUint16(
+ vt2Start + _metadataLength + (2 * i), Endianness.LITTLE_ENDIAN)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// Fill the [fieldOffsets] field.
+ void computeFieldOffsets(int tableTail) {
+ assert(fieldOffsets.isEmpty);
+ for (int fieldTail in fieldTails) {
+ int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
+ fieldOffsets.add(fieldOffset);
+ }
+ }
+
+ /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
+ /// and have at least [numOfUint16] 16-bit words available.
+ void output(ByteData buf, int bufOffset) {
+ // VTable size.
+ buf.setUint16(bufOffset, numOfUint16 * 2, Endianness.LITTLE_ENDIAN);
+ bufOffset += 2;
+ // Table size.
+ buf.setUint16(bufOffset, tableSize, Endianness.LITTLE_ENDIAN);
+ bufOffset += 2;
+ // Field offsets.
+ for (int fieldOffset in fieldOffsets) {
+ buf.setUint16(bufOffset, fieldOffset, Endianness.LITTLE_ENDIAN);
+ bufOffset += 2;
+ }
+ }
+}
diff --git a/dart/publish.sh b/dart/publish.sh
new file mode 100755
index 00000000..167a4a34
--- /dev/null
+++ b/dart/publish.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note to pub consumers: this file is used to assist with publishing the
+# pub package from the flatbuffers repository and is not meant for general use.
+# As pub does not currently provide a way to exclude files, it is included here.
+
+command -v pub >/dev/null 2>&1 || { echo >&2 "Require `pub` but it's not installed. Aborting."; exit 1; }
+
+cp ../samples/monster.fbs example/
+cp ../tests/monster_test.fbs test/
+pub publish
+
+rm example/monster.fbs
+rm test/monster_test.fbs \ No newline at end of file
diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml
new file mode 100644
index 00000000..c71f831d
--- /dev/null
+++ b/dart/pubspec.yaml
@@ -0,0 +1,18 @@
+name: flat_buffers
+version: 1.9.0
+description: >
+ FlatBuffers reading and writing library for Dart. Use the flatc compiler to
+ generate Dart classes for a FlatBuffers schema, and this library to assist with
+ reading and writing the binary format.
+
+ Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
+authors:
+- Dan Field <dfield@gmail.com>
+- Konstantin Scheglov
+- Paul Berry
+homepage: https://github.com/google/flatbuffers
+documentation: https://google.github.io/flatbuffers/index.html
+dev_dependencies:
+ test: ^0.12.33
+ test_reflective_loader: ^0.1.4
+ path: ^1.5.1
diff --git a/dart/test/flat_buffers_test.dart b/dart/test/flat_buffers_test.dart
new file mode 100644
index 00000000..9fbbf8ae
--- /dev/null
+++ b/dart/test/flat_buffers_test.dart
@@ -0,0 +1,573 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+import 'dart:io' as io;
+
+import 'package:path/path.dart' as path;
+
+import 'package:flat_buffers/flat_buffers.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import './monster_test_my_game.example_generated.dart' as example;
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(BuilderTest);
+ defineReflectiveTests(CheckOtherLangaugesData);
+ });
+}
+
+int indexToField(int index) {
+ return (1 + 1 + index) * 2;
+}
+
+@reflectiveTest
+class CheckOtherLangaugesData {
+ test_cppData() async {
+ List<int> data = await new io.File(path.join(
+ path.dirname(io.Platform.script.path),
+ 'monsterdata_test.mon',
+ ))
+ .readAsBytes();
+ example.Monster mon = new example.Monster(data);
+ expect(mon.hp, 80);
+ expect(mon.mana, 150);
+ expect(mon.name, 'MyMonster');
+ expect(mon.pos.x, 1.0);
+ expect(mon.pos.y, 2.0);
+ expect(mon.pos.z, 3.0);
+ expect(mon.pos.test1, 3.0);
+ expect(mon.pos.test2.value, 2.0);
+ expect(mon.pos.test3.a, 5);
+ expect(mon.pos.test3.b, 6);
+ expect(mon.testType.value, example.AnyTypeId.Monster.value);
+ expect(mon.test is example.Monster, true);
+ final monster2 = mon.test as example.Monster;
+ expect(monster2.name, "Fred");
+
+ expect(mon.inventory.length, 5);
+ expect(mon.inventory.reduce((cur, next) => cur + next), 10);
+ expect(mon.test4.length, 2);
+ expect(
+ mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100);
+ expect(mon.testarrayofstring.length, 2);
+ expect(mon.testarrayofstring[0], "test1");
+ expect(mon.testarrayofstring[1], "test2");
+
+ // this will fail if accessing any field fails.
+ expect(mon.toString(),
+ 'Monster{pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], color: Color{value: 8}, testType: AnyTypeId{value: 1}, test: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: null, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: null, testhashs32Fnv1: null, testhashu32Fnv1: null, testhashs64Fnv1: null, testhashu64Fnv1: null, testhashs32Fnv1a: null, testhashu32Fnv1a: null, testhashs64Fnv1a: null, testhashu64Fnv1a: null, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: null, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: null, vectorOfCoOwningReferences: null, nonOwningReference: null, vectorOfNonOwningReferences: null}, test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], testarrayofstring: [test1, test2], testarrayoftables: null, enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: null, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: null, testhashs32Fnv1: null, testhashu32Fnv1: null, testhashs64Fnv1: null, testhashu64Fnv1: null, testhashs32Fnv1a: null, testhashu32Fnv1a: null, testhashs64Fnv1a: null, testhashu64Fnv1a: null, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: null, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: null, vectorOfCoOwningReferences: null, nonOwningReference: null, vectorOfNonOwningReferences: null}, testnestedflatbuffer: null, testempty: null, testbool: null, testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, testhashs64Fnv1: 7930699090847568257, testhashu64Fnv1: 7930699090847568257, testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, testhashs64Fnv1a: 4898026182817603057, testhashu64Fnv1a: 4898026182817603057, testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], vectorOfLongs: [1, 100, 10000, 1000000, 100000000], vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: null, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: null, vectorOfCoOwningReferences: null, nonOwningReference: null, vectorOfNonOwningReferences: null}');
+ }
+}
+
+@reflectiveTest
+class BuilderTest {
+ void test_monsterBuilder() {
+ final fbBuilder = new Builder();
+ final str = fbBuilder.writeString('MyMonster');
+
+ fbBuilder.writeString('test1');
+ fbBuilder.writeString('test2');
+ final testArrayOfString = fbBuilder.endStructVector(2);
+
+ final fred = fbBuilder.writeString('Fred');
+
+ final List<int> treasure = [0, 1, 2, 3, 4];
+ final inventory = fbBuilder.writeListUint8(treasure);
+
+ final monBuilder = new example.MonsterBuilder(fbBuilder)
+ ..begin()
+ ..addNameOffset(fred);
+ final mon2 = monBuilder.finish();
+
+ final testBuilder = new example.TestBuilder(fbBuilder);
+ testBuilder.finish(10, 20);
+ testBuilder.finish(30, 40);
+ final test4 = fbBuilder.endStructVector(2);
+
+
+ monBuilder
+ ..begin()
+ ..addPos(
+ new example.Vec3Builder(fbBuilder).finish(
+ 1.0,
+ 2.0,
+ 3.0,
+ 3.0,
+ example.Color.Green,
+ () => testBuilder.finish(5, 6),
+ ),
+ )
+ ..addHp(80)
+ ..addNameOffset(str)
+ ..addInventoryOffset(inventory)
+ ..addTestType(example.AnyTypeId.Monster)
+ ..addTestOffset(mon2)
+ ..addTest4Offset(test4)
+ ..addTestarrayofstringOffset(testArrayOfString);
+ final mon = monBuilder.finish();
+ fbBuilder.finish(mon);
+ }
+
+ void test_error_addInt32_withoutStartTable() {
+ Builder builder = new Builder();
+ expect(() {
+ builder.addInt32(0, 0);
+ }, throwsStateError);
+ }
+
+ void test_error_addOffset_withoutStartTable() {
+ Builder builder = new Builder();
+ expect(() {
+ builder.addOffset(0, 0);
+ }, throwsStateError);
+ }
+
+ void test_error_endTable_withoutStartTable() {
+ Builder builder = new Builder();
+ expect(() {
+ builder.endTable();
+ }, throwsStateError);
+ }
+
+ void test_error_startTable_duringTable() {
+ Builder builder = new Builder();
+ builder.startTable();
+ expect(() {
+ builder.startTable();
+ }, throwsStateError);
+ }
+
+ void test_error_writeString_duringTable() {
+ Builder builder = new Builder();
+ builder.startTable();
+ expect(() {
+ builder.writeString('12345');
+ }, throwsStateError);
+ }
+
+ void test_file_identifier() {
+ Uint8List byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ int offset = builder.endTable();
+ byteList = builder.finish(offset, 'Az~ÿ');
+ }
+ // Convert byteList to a ByteData so that we can read data from it.
+ ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
+ // First 4 bytes are an offset to the table data.
+ int tableDataLoc = byteData.getUint32(0, Endianness.LITTLE_ENDIAN);
+ // Next 4 bytes are the file identifier.
+ expect(byteData.getUint8(4), 65); // 'a'
+ expect(byteData.getUint8(5), 122); // 'z'
+ expect(byteData.getUint8(6), 126); // '~'
+ expect(byteData.getUint8(7), 255); // 'ÿ'
+ // First 4 bytes of the table data are a backwards offset to the vtable.
+ int vTableLoc = tableDataLoc -
+ byteData.getInt32(tableDataLoc, Endianness.LITTLE_ENDIAN);
+ // First 2 bytes of the vtable are the size of the vtable in bytes, which
+ // should be 4.
+ expect(byteData.getUint16(vTableLoc, Endianness.LITTLE_ENDIAN), 4);
+ // Next 2 bytes are the size of the object in bytes (including the vtable
+ // pointer), which should be 4.
+ expect(byteData.getUint16(vTableLoc + 2, Endianness.LITTLE_ENDIAN), 4);
+ }
+
+ void test_low() {
+ Builder builder = new Builder(initialSize: 0);
+ expect((builder..putUint8(1)).lowFinish(), [1]);
+ expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint8(3)).lowFinish(),
+ [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint8(4)).lowFinish(),
+ [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint8(5)).lowFinish(),
+ [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint32(6)).lowFinish(),
+ [6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ }
+
+ void test_table_default() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ builder.addInt32(0, 10, 10);
+ builder.addInt32(1, 20, 10);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buffer = new BufferContext.fromBytes(byteList);
+ int objectOffset = buffer.derefObject(0);
+ // was not written, so uses the new default value
+ expect(
+ const Int32Reader()
+ .vTableGet(buffer, objectOffset, indexToField(0), 15),
+ 15);
+ // has the written value
+ expect(
+ const Int32Reader()
+ .vTableGet(buffer, objectOffset, indexToField(1), 15),
+ 20);
+ }
+
+ void test_table_format() {
+ Uint8List byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ builder.addInt32(0, 10);
+ builder.addInt32(1, 20);
+ builder.addInt32(2, 30);
+ byteList = builder.finish(builder.endTable());
+ }
+ // Convert byteList to a ByteData so that we can read data from it.
+ ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
+ // First 4 bytes are an offset to the table data.
+ int tableDataLoc = byteData.getUint32(0, Endianness.LITTLE_ENDIAN);
+ // First 4 bytes of the table data are a backwards offset to the vtable.
+ int vTableLoc = tableDataLoc -
+ byteData.getInt32(tableDataLoc, Endianness.LITTLE_ENDIAN);
+ // First 2 bytes of the vtable are the size of the vtable in bytes, which
+ // should be 10.
+ expect(byteData.getUint16(vTableLoc, Endianness.LITTLE_ENDIAN), 10);
+ // Next 2 bytes are the size of the object in bytes (including the vtable
+ // pointer), which should be 16.
+ expect(byteData.getUint16(vTableLoc + 2, Endianness.LITTLE_ENDIAN), 16);
+ // Remaining 6 bytes are the offsets within the object where the ints are
+ // located.
+ for (int i = 0; i < 3; i++) {
+ int offset =
+ byteData.getUint16(vTableLoc + 4 + 2 * i, Endianness.LITTLE_ENDIAN);
+ expect(byteData.getInt32(tableDataLoc + offset, Endianness.LITTLE_ENDIAN),
+ 10 + 10 * i);
+ }
+ }
+
+ void test_table_string() {
+ String latinString = 'test';
+ String unicodeString = 'Проба пера';
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int latinStringOffset = builder.writeString(latinString);
+ int unicodeStringOffset = builder.writeString(unicodeString);
+ builder.startTable();
+ builder.addOffset(0, latinStringOffset);
+ builder.addOffset(1, unicodeStringOffset);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ int objectOffset = buf.derefObject(0);
+ expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)),
+ latinString);
+ expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)),
+ unicodeString);
+ }
+
+ void test_table_types() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int stringOffset = builder.writeString('12345');
+ builder.startTable();
+ builder.addBool(0, true);
+ builder.addInt8(1, 10);
+ builder.addInt32(2, 20);
+ builder.addOffset(3, stringOffset);
+ builder.addInt32(4, 40);
+ builder.addUint32(5, 0x9ABCDEF0);
+ builder.addUint8(6, 0x9A);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ int objectOffset = buf.derefObject(0);
+ expect(
+ const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true);
+ expect(
+ const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10);
+ expect(
+ const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20);
+ expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)),
+ '12345');
+ expect(
+ const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40);
+ expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)),
+ 0x9ABCDEF0);
+ expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)),
+ 0x9A);
+ }
+
+ void test_writeList_of_Uint32() {
+ List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint32(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint32ListReader().read(buf, 0);
+ expect(items, hasLength(4));
+ expect(items, orderedEquals(values));
+ }
+
+ void test_writeList_ofBool() {
+ void verifyListBooleans(int len, List<int> trueBits) {
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ List<bool> values = new List<bool>.filled(len, false);
+ for (int bit in trueBits) {
+ values[bit] = true;
+ }
+ int offset = builder.writeListBool(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<bool> items = const BoolListReader().read(buf, 0);
+ expect(items, hasLength(len));
+ for (int i = 0; i < items.length; i++) {
+ expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
+ }
+ }
+
+ verifyListBooleans(0, <int>[]);
+ verifyListBooleans(1, <int>[]);
+ verifyListBooleans(1, <int>[0]);
+ verifyListBooleans(31, <int>[0, 1]);
+ verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
+ verifyListBooleans(31, <int>[0, 30]);
+ verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
+ verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
+ verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
+ verifyListBooleans(63, <int>[]);
+ verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
+ verifyListBooleans(63, new List<int>.generate(63, (i) => i));
+ verifyListBooleans(64, <int>[]);
+ verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
+ verifyListBooleans(64, <int>[1, 2, 62]);
+ verifyListBooleans(64, <int>[0, 1, 2, 63]);
+ verifyListBooleans(64, new List<int>.generate(64, (i) => i));
+ verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
+ }
+
+ void test_writeList_ofInt32() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0);
+ expect(items, hasLength(5));
+ expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
+ }
+
+ void test_writeList_ofFloat64() {
+ List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListFloat64(values);
+ byteList = builder.finish(offset);
+ }
+
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<double> items = const Float64ListReader().read(buf, 0);
+
+ expect(items, hasLength(values.length));
+ for (int i = 0; i < values.length; i++) {
+ expect(values[i], closeTo(items[i], .001));
+ }
+ }
+
+ void test_writeList_ofFloat32() {
+ List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListFloat32(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<double> items = const Float32ListReader().read(buf, 0);
+ expect(items, hasLength(5));
+ for (int i = 0; i < values.length; i++) {
+ expect(values[i], closeTo(items[i], .001));
+ }
+ }
+
+ void test_writeList_ofObjects() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ // write the object #1
+ int object1;
+ {
+ builder.startTable();
+ builder.addInt32(0, 10);
+ builder.addInt32(1, 20);
+ object1 = builder.endTable();
+ }
+ // write the object #1
+ int object2;
+ {
+ builder.startTable();
+ builder.addInt32(0, 100);
+ builder.addInt32(1, 200);
+ object2 = builder.endTable();
+ }
+ // write the list
+ int offset = builder.writeList([object1, object2]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<TestPointImpl> items =
+ const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0);
+ expect(items, hasLength(2));
+ expect(items[0].x, 10);
+ expect(items[0].y, 20);
+ expect(items[1].x, 100);
+ expect(items[1].y, 200);
+ }
+
+ void test_writeList_ofStrings_asRoot() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int str1 = builder.writeString('12345');
+ int str2 = builder.writeString('ABC');
+ int offset = builder.writeList([str1, str2]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<String> items =
+ const ListReader<String>(const StringReader()).read(buf, 0);
+ expect(items, hasLength(2));
+ expect(items, contains('12345'));
+ expect(items, contains('ABC'));
+ }
+
+ void test_writeList_ofStrings_inObject() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int listOffset = builder.writeList(
+ [builder.writeString('12345'), builder.writeString('ABC')]);
+ builder.startTable();
+ builder.addOffset(0, listOffset);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0);
+ List<String> items = reader.items;
+ expect(items, hasLength(2));
+ expect(items, contains('12345'));
+ expect(items, contains('ABC'));
+ }
+
+ void test_writeList_ofUint32() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint32ListReader().read(buf, 0);
+ expect(items, hasLength(3));
+ expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
+ }
+
+ void test_writeList_ofUint16() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint16(<int>[1, 2, 60000]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint16ListReader().read(buf, 0);
+ expect(items, hasLength(3));
+ expect(items, orderedEquals(<int>[1, 2, 60000]));
+ }
+
+ void test_writeList_ofUint8() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint8ListReader().read(buf, 0);
+ expect(items, hasLength(5));
+ expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
+ }
+}
+
+class StringListWrapperImpl {
+ final BufferContext bp;
+ final int offset;
+
+ StringListWrapperImpl(this.bp, this.offset);
+
+ List<String> get items => const ListReader<String>(const StringReader())
+ .vTableGet(bp, offset, indexToField(0));
+}
+
+class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
+ const StringListWrapperReader();
+
+ @override
+ StringListWrapperImpl createObject(BufferContext object, int offset) {
+ return new StringListWrapperImpl(object, offset);
+ }
+}
+
+class TestPointImpl {
+ final BufferContext bp;
+ final int offset;
+
+ TestPointImpl(this.bp, this.offset);
+
+ int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
+
+ int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
+}
+
+class TestPointReader extends TableReader<TestPointImpl> {
+ const TestPointReader();
+
+ @override
+ TestPointImpl createObject(BufferContext object, int offset) {
+ return new TestPointImpl(object, offset);
+ }
+}
diff --git a/dart/test/monster_test_my_game.example2_generated.dart b/dart/test/monster_test_my_game.example2_generated.dart
new file mode 100644
index 00000000..eed14bc2
--- /dev/null
+++ b/dart/test/monster_test_my_game.example2_generated.dart
@@ -0,0 +1,60 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game.example2;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import './monster_test_my_game_generated.dart' as my_game;
+import './monster_test_my_game.example_generated.dart' as my_game_example;
+
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+
+ @override
+ String toString() {
+ return 'Monster{}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+
+ MonsterObjectBuilder();
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/dart/test/monster_test_my_game.example_generated.dart b/dart/test/monster_test_my_game.example_generated.dart
new file mode 100644
index 00000000..d85b5919
--- /dev/null
+++ b/dart/test/monster_test_my_game.example_generated.dart
@@ -0,0 +1,1332 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game.example;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import './monster_test_my_game.example2_generated.dart' as my_game_example2;
+import './monster_test_my_game_generated.dart' as my_game;
+
+class Color {
+ final int value;
+ const Color._(this.value);
+
+ factory Color.fromValue(int value) {
+ if (value == null) return null;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum Color');
+ }
+ return values[value];
+ }
+
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const Color Red = const Color._(1);
+ static const Color Green = const Color._(2);
+ static const Color Blue = const Color._(8);
+ static get values => {1: Red,2: Green,8: Blue,};
+
+ static const fb.Reader<Color> reader = const _ColorReader();
+
+ @override
+ String toString() {
+ return 'Color{value: $value}';
+ }
+}
+
+class _ColorReader extends fb.Reader<Color> {
+ const _ColorReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ Color read(fb.BufferContext bc, int offset) =>
+ new Color.fromValue(const fb.Int8Reader().read(bc, offset));
+}
+
+class AnyTypeId {
+ final int value;
+ const AnyTypeId._(this.value);
+
+ factory AnyTypeId.fromValue(int value) {
+ if (value == null) return null;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyTypeId NONE = const AnyTypeId._(0);
+ static const AnyTypeId Monster = const AnyTypeId._(1);
+ static const AnyTypeId TestSimpleTableWithEnum = const AnyTypeId._(2);
+ static const AnyTypeId MyGame_Example2_Monster = const AnyTypeId._(3);
+ static get values => {0: NONE,1: Monster,2: TestSimpleTableWithEnum,3: MyGame_Example2_Monster,};
+
+ static const fb.Reader<AnyTypeId> reader = const _AnyTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyTypeId{value: $value}';
+ }
+}
+
+class _AnyTypeIdReader extends fb.Reader<AnyTypeId> {
+ const _AnyTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class Test {
+ Test._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Test> reader = const _TestReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get a => const fb.Int16Reader().read(_bc, _bcOffset + 0);
+ int get b => const fb.Int8Reader().read(_bc, _bcOffset + 2);
+
+ @override
+ String toString() {
+ return 'Test{a: $a, b: $b}';
+ }
+}
+
+class _TestReader extends fb.StructReader<Test> {
+ const _TestReader();
+
+ @override
+ int get size => 4;
+
+ @override
+ Test createObject(fb.BufferContext bc, int offset) =>
+ new Test._(bc, offset);
+}
+
+class TestBuilder {
+ TestBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int a, int b) {
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(b);
+ fbBuilder.putInt16(a);
+ return fbBuilder.offset;
+ }
+
+}
+
+class TestObjectBuilder extends fb.ObjectBuilder {
+ final int _a;
+ final int _b;
+
+ TestObjectBuilder({
+ int a,
+ int b,
+ })
+ : _a = a,
+ _b = b;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(_b);
+ fbBuilder.putInt16(_a);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class TestSimpleTableWithEnum {
+ TestSimpleTableWithEnum._(this._bc, this._bcOffset);
+ factory TestSimpleTableWithEnum(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TestSimpleTableWithEnum> reader = const _TestSimpleTableWithEnumReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 4, 2));
+
+ @override
+ String toString() {
+ return 'TestSimpleTableWithEnum{color: $color}';
+ }
+}
+
+class _TestSimpleTableWithEnumReader extends fb.TableReader<TestSimpleTableWithEnum> {
+ const _TestSimpleTableWithEnumReader();
+
+ @override
+ TestSimpleTableWithEnum createObject(fb.BufferContext bc, int offset) =>
+ new TestSimpleTableWithEnum._(bc, offset);
+}
+
+class TestSimpleTableWithEnumBuilder {
+ TestSimpleTableWithEnumBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addColor(Color color) {
+ fbBuilder.addInt8(0, color?.value);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TestSimpleTableWithEnumObjectBuilder extends fb.ObjectBuilder {
+ final Color _color;
+
+ TestSimpleTableWithEnumObjectBuilder({
+ Color color,
+ })
+ : _color = color;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addInt8(0, _color?.value);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Vec3 {
+ Vec3._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Vec3> reader = const _Vec3Reader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
+ double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
+ double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
+ double get test1 => const fb.Float64Reader().read(_bc, _bcOffset + 16);
+ Color get test2 => new Color.fromValue(const fb.Int8Reader().read(_bc, _bcOffset + 24));
+ Test get test3 => Test.reader.read(_bc, _bcOffset + 26);
+
+ @override
+ String toString() {
+ return 'Vec3{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}';
+ }
+}
+
+class _Vec3Reader extends fb.StructReader<Vec3> {
+ const _Vec3Reader();
+
+ @override
+ int get size => 32;
+
+ @override
+ Vec3 createObject(fb.BufferContext bc, int offset) =>
+ new Vec3._(bc, offset);
+}
+
+class Vec3Builder {
+ Vec3Builder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(double x, double y, double z, double test1, Color test2, fb.StructBuilder test3) {
+ fbBuilder.pad(2);
+ test3();
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(test2?.value);
+ fbBuilder.putFloat64(test1);
+ fbBuilder.pad(4);
+ fbBuilder.putFloat32(z);
+ fbBuilder.putFloat32(y);
+ fbBuilder.putFloat32(x);
+ return fbBuilder.offset;
+ }
+
+}
+
+class Vec3ObjectBuilder extends fb.ObjectBuilder {
+ final double _x;
+ final double _y;
+ final double _z;
+ final double _test1;
+ final Color _test2;
+ final TestObjectBuilder _test3;
+
+ Vec3ObjectBuilder({
+ double x,
+ double y,
+ double z,
+ double test1,
+ Color test2,
+ TestObjectBuilder test3,
+ })
+ : _x = x,
+ _y = y,
+ _z = z,
+ _test1 = test1,
+ _test2 = test2,
+ _test3 = test3;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.pad(2);
+ _test3.finish(fbBuilder);
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(_test2?.value);
+ fbBuilder.putFloat64(_test1);
+ fbBuilder.pad(4);
+ fbBuilder.putFloat32(_z);
+ fbBuilder.putFloat32(_y);
+ fbBuilder.putFloat32(_x);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Ability {
+ Ability._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Ability> reader = const _AbilityReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get id => const fb.Uint32Reader().read(_bc, _bcOffset + 0);
+ int get distance => const fb.Uint32Reader().read(_bc, _bcOffset + 4);
+
+ @override
+ String toString() {
+ return 'Ability{id: $id, distance: $distance}';
+ }
+}
+
+class _AbilityReader extends fb.StructReader<Ability> {
+ const _AbilityReader();
+
+ @override
+ int get size => 8;
+
+ @override
+ Ability createObject(fb.BufferContext bc, int offset) =>
+ new Ability._(bc, offset);
+}
+
+class AbilityBuilder {
+ AbilityBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int id, int distance) {
+ fbBuilder.putUint32(distance);
+ fbBuilder.putUint32(id);
+ return fbBuilder.offset;
+ }
+
+}
+
+class AbilityObjectBuilder extends fb.ObjectBuilder {
+ final int _id;
+ final int _distance;
+
+ AbilityObjectBuilder({
+ int id,
+ int distance,
+ })
+ : _id = id,
+ _distance = distance;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.putUint32(_distance);
+ fbBuilder.putUint32(_id);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Stat {
+ Stat._(this._bc, this._bcOffset);
+ factory Stat(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Stat> reader = const _StatReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ String get id => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
+ int get val => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 6, null);
+ int get count => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 8, null);
+
+ @override
+ String toString() {
+ return 'Stat{id: $id, val: $val, count: $count}';
+ }
+}
+
+class _StatReader extends fb.TableReader<Stat> {
+ const _StatReader();
+
+ @override
+ Stat createObject(fb.BufferContext bc, int offset) =>
+ new Stat._(bc, offset);
+}
+
+class StatBuilder {
+ StatBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addIdOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addVal(int val) {
+ fbBuilder.addInt64(1, val);
+ return fbBuilder.offset;
+ }
+ int addCount(int count) {
+ fbBuilder.addUint16(2, count);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class StatObjectBuilder extends fb.ObjectBuilder {
+ final String _id;
+ final int _val;
+ final int _count;
+
+ StatObjectBuilder({
+ String id,
+ int val,
+ int count,
+ })
+ : _id = id,
+ _val = val,
+ _count = count;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int idOffset = fbBuilder.writeString(_id);
+
+ fbBuilder.startTable();
+ if (idOffset != null) {
+ fbBuilder.addOffset(0, idOffset);
+ }
+ fbBuilder.addInt64(1, _val);
+ fbBuilder.addUint16(2, _count);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Referrable {
+ Referrable._(this._bc, this._bcOffset);
+ factory Referrable(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Referrable> reader = const _ReferrableReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get id => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 4, null);
+
+ @override
+ String toString() {
+ return 'Referrable{id: $id}';
+ }
+}
+
+class _ReferrableReader extends fb.TableReader<Referrable> {
+ const _ReferrableReader();
+
+ @override
+ Referrable createObject(fb.BufferContext bc, int offset) =>
+ new Referrable._(bc, offset);
+}
+
+class ReferrableBuilder {
+ ReferrableBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addId(int id) {
+ fbBuilder.addUint64(0, id);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class ReferrableObjectBuilder extends fb.ObjectBuilder {
+ final int _id;
+
+ ReferrableObjectBuilder({
+ int id,
+ })
+ : _id = id;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addUint64(0, _id);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+/// an example documentation comment: monster object
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+ int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
+ int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
+ List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
+ Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 8));
+ AnyTypeId get testType => new AnyTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 18, null));
+ dynamic get test {
+ switch (testType?.value) {
+ case 1: return Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+ case 2: return TestSimpleTableWithEnum.reader.vTableGet(_bc, _bcOffset, 20, null);
+ case 3: return my_game_example2.Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+ default: return null;
+ }
+ }
+ List<Test> get test4 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 22, null);
+ List<String> get testarrayofstring => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 24, null);
+/// an example documentation comment: this will end up in the generated code
+/// multiline too
+ List<Monster> get testarrayoftables => const fb.ListReader<Monster>(Monster.reader).vTableGet(_bc, _bcOffset, 26, null);
+ Monster get enemy => Monster.reader.vTableGet(_bc, _bcOffset, 28, null);
+ List<int> get testnestedflatbuffer => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 30, null);
+ Stat get testempty => Stat.reader.vTableGet(_bc, _bcOffset, 32, null);
+ bool get testbool => const fb.BoolReader().vTableGet(_bc, _bcOffset, 34, null);
+ int get testhashs32Fnv1 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 36, null);
+ int get testhashu32Fnv1 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 38, null);
+ int get testhashs64Fnv1 => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 40, null);
+ int get testhashu64Fnv1 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 42, null);
+ int get testhashs32Fnv1a => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 44, null);
+ int get testhashu32Fnv1a => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 46, null);
+ int get testhashs64Fnv1a => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 48, null);
+ int get testhashu64Fnv1a => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 50, null);
+ List<bool> get testarrayofbools => const fb.ListReader<bool>(const fb.BoolReader()).vTableGet(_bc, _bcOffset, 52, null);
+ double get testf => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 54, 3.14159);
+ double get testf2 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 56, 3.0);
+ double get testf3 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 58, 0.0);
+ List<String> get testarrayofstring2 => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 60, null);
+ List<Ability> get testarrayofsortedstruct => const fb.ListReader<Ability>(Ability.reader).vTableGet(_bc, _bcOffset, 62, null);
+ List<int> get flex => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 64, null);
+ List<Test> get test5 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 66, null);
+ List<int> get vectorOfLongs => const fb.ListReader<int>(const fb.Int64Reader()).vTableGet(_bc, _bcOffset, 68, null);
+ List<double> get vectorOfDoubles => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 70, null);
+ my_game.InParentNamespace get parentNamespaceTest => my_game.InParentNamespace.reader.vTableGet(_bc, _bcOffset, 72, null);
+ List<Referrable> get vectorOfReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 74, null);
+ int get singleWeakReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 76, null);
+ List<int> get vectorOfWeakReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 78, null);
+ List<Referrable> get vectorOfStrongReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 80, null);
+ int get coOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 82, null);
+ List<int> get vectorOfCoOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 84, null);
+ int get nonOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 86, null);
+ List<int> get vectorOfNonOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 88, null);
+
+ @override
+ String toString() {
+ return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterBuilder {
+ MonsterBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addPos(int offset) {
+ fbBuilder.addStruct(0, offset);
+ return fbBuilder.offset;
+ }
+ int addMana(int mana) {
+ fbBuilder.addInt16(1, mana);
+ return fbBuilder.offset;
+ }
+ int addHp(int hp) {
+ fbBuilder.addInt16(2, hp);
+ return fbBuilder.offset;
+ }
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(3, offset);
+ return fbBuilder.offset;
+ }
+ int addInventoryOffset(int offset) {
+ fbBuilder.addOffset(5, offset);
+ return fbBuilder.offset;
+ }
+ int addColor(Color color) {
+ fbBuilder.addInt8(6, color?.value);
+ return fbBuilder.offset;
+ }
+ int addTestType(AnyTypeId testType) {
+ fbBuilder.addUint8(7, testType?.value);
+ return fbBuilder.offset;
+ }
+ int addTestOffset(int offset) {
+ fbBuilder.addOffset(8, offset);
+ return fbBuilder.offset;
+ }
+ int addTest4Offset(int offset) {
+ fbBuilder.addOffset(9, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofstringOffset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayoftablesOffset(int offset) {
+ fbBuilder.addOffset(11, offset);
+ return fbBuilder.offset;
+ }
+ int addEnemyOffset(int offset) {
+ fbBuilder.addOffset(12, offset);
+ return fbBuilder.offset;
+ }
+ int addTestnestedflatbufferOffset(int offset) {
+ fbBuilder.addOffset(13, offset);
+ return fbBuilder.offset;
+ }
+ int addTestemptyOffset(int offset) {
+ fbBuilder.addOffset(14, offset);
+ return fbBuilder.offset;
+ }
+ int addTestbool(bool testbool) {
+ fbBuilder.addBool(15, testbool);
+ return fbBuilder.offset;
+ }
+ int addTesthashs32Fnv1(int testhashs32Fnv1) {
+ fbBuilder.addInt32(16, testhashs32Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashu32Fnv1(int testhashu32Fnv1) {
+ fbBuilder.addUint32(17, testhashu32Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashs64Fnv1(int testhashs64Fnv1) {
+ fbBuilder.addInt64(18, testhashs64Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashu64Fnv1(int testhashu64Fnv1) {
+ fbBuilder.addUint64(19, testhashu64Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashs32Fnv1a(int testhashs32Fnv1a) {
+ fbBuilder.addInt32(20, testhashs32Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashu32Fnv1a(int testhashu32Fnv1a) {
+ fbBuilder.addUint32(21, testhashu32Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashs64Fnv1a(int testhashs64Fnv1a) {
+ fbBuilder.addInt64(22, testhashs64Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashu64Fnv1a(int testhashu64Fnv1a) {
+ fbBuilder.addUint64(23, testhashu64Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofboolsOffset(int offset) {
+ fbBuilder.addOffset(24, offset);
+ return fbBuilder.offset;
+ }
+ int addTestf(double testf) {
+ fbBuilder.addFloat32(25, testf);
+ return fbBuilder.offset;
+ }
+ int addTestf2(double testf2) {
+ fbBuilder.addFloat32(26, testf2);
+ return fbBuilder.offset;
+ }
+ int addTestf3(double testf3) {
+ fbBuilder.addFloat32(27, testf3);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofstring2Offset(int offset) {
+ fbBuilder.addOffset(28, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofsortedstructOffset(int offset) {
+ fbBuilder.addOffset(29, offset);
+ return fbBuilder.offset;
+ }
+ int addFlexOffset(int offset) {
+ fbBuilder.addOffset(30, offset);
+ return fbBuilder.offset;
+ }
+ int addTest5Offset(int offset) {
+ fbBuilder.addOffset(31, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfLongsOffset(int offset) {
+ fbBuilder.addOffset(32, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfDoublesOffset(int offset) {
+ fbBuilder.addOffset(33, offset);
+ return fbBuilder.offset;
+ }
+ int addParentNamespaceTestOffset(int offset) {
+ fbBuilder.addOffset(34, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfReferrablesOffset(int offset) {
+ fbBuilder.addOffset(35, offset);
+ return fbBuilder.offset;
+ }
+ int addSingleWeakReference(int singleWeakReference) {
+ fbBuilder.addUint64(36, singleWeakReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfWeakReferencesOffset(int offset) {
+ fbBuilder.addOffset(37, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfStrongReferrablesOffset(int offset) {
+ fbBuilder.addOffset(38, offset);
+ return fbBuilder.offset;
+ }
+ int addCoOwningReference(int coOwningReference) {
+ fbBuilder.addUint64(39, coOwningReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfCoOwningReferencesOffset(int offset) {
+ fbBuilder.addOffset(40, offset);
+ return fbBuilder.offset;
+ }
+ int addNonOwningReference(int nonOwningReference) {
+ fbBuilder.addUint64(41, nonOwningReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfNonOwningReferencesOffset(int offset) {
+ fbBuilder.addOffset(42, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+ final Vec3ObjectBuilder _pos;
+ final int _mana;
+ final int _hp;
+ final String _name;
+ final List<int> _inventory;
+ final Color _color;
+ final AnyTypeId _testType;
+ final dynamic _test;
+ final List<TestObjectBuilder> _test4;
+ final List<String> _testarrayofstring;
+ final List<MonsterObjectBuilder> _testarrayoftables;
+ final MonsterObjectBuilder _enemy;
+ final List<int> _testnestedflatbuffer;
+ final StatObjectBuilder _testempty;
+ final bool _testbool;
+ final int _testhashs32Fnv1;
+ final int _testhashu32Fnv1;
+ final int _testhashs64Fnv1;
+ final int _testhashu64Fnv1;
+ final int _testhashs32Fnv1a;
+ final int _testhashu32Fnv1a;
+ final int _testhashs64Fnv1a;
+ final int _testhashu64Fnv1a;
+ final List<bool> _testarrayofbools;
+ final double _testf;
+ final double _testf2;
+ final double _testf3;
+ final List<String> _testarrayofstring2;
+ final List<AbilityObjectBuilder> _testarrayofsortedstruct;
+ final List<int> _flex;
+ final List<TestObjectBuilder> _test5;
+ final List<int> _vectorOfLongs;
+ final List<double> _vectorOfDoubles;
+ final my_game.InParentNamespaceObjectBuilder _parentNamespaceTest;
+ final List<ReferrableObjectBuilder> _vectorOfReferrables;
+ final int _singleWeakReference;
+ final List<int> _vectorOfWeakReferences;
+ final List<ReferrableObjectBuilder> _vectorOfStrongReferrables;
+ final int _coOwningReference;
+ final List<int> _vectorOfCoOwningReferences;
+ final int _nonOwningReference;
+ final List<int> _vectorOfNonOwningReferences;
+
+ MonsterObjectBuilder({
+ Vec3ObjectBuilder pos,
+ int mana,
+ int hp,
+ String name,
+ List<int> inventory,
+ Color color,
+ AnyTypeId testType,
+ dynamic test,
+ List<TestObjectBuilder> test4,
+ List<String> testarrayofstring,
+ List<MonsterObjectBuilder> testarrayoftables,
+ MonsterObjectBuilder enemy,
+ List<int> testnestedflatbuffer,
+ StatObjectBuilder testempty,
+ bool testbool,
+ int testhashs32Fnv1,
+ int testhashu32Fnv1,
+ int testhashs64Fnv1,
+ int testhashu64Fnv1,
+ int testhashs32Fnv1a,
+ int testhashu32Fnv1a,
+ int testhashs64Fnv1a,
+ int testhashu64Fnv1a,
+ List<bool> testarrayofbools,
+ double testf,
+ double testf2,
+ double testf3,
+ List<String> testarrayofstring2,
+ List<AbilityObjectBuilder> testarrayofsortedstruct,
+ List<int> flex,
+ List<TestObjectBuilder> test5,
+ List<int> vectorOfLongs,
+ List<double> vectorOfDoubles,
+ my_game.InParentNamespaceObjectBuilder parentNamespaceTest,
+ List<ReferrableObjectBuilder> vectorOfReferrables,
+ int singleWeakReference,
+ List<int> vectorOfWeakReferences,
+ List<ReferrableObjectBuilder> vectorOfStrongReferrables,
+ int coOwningReference,
+ List<int> vectorOfCoOwningReferences,
+ int nonOwningReference,
+ List<int> vectorOfNonOwningReferences,
+ })
+ : _pos = pos,
+ _mana = mana,
+ _hp = hp,
+ _name = name,
+ _inventory = inventory,
+ _color = color,
+ _testType = testType,
+ _test = test,
+ _test4 = test4,
+ _testarrayofstring = testarrayofstring,
+ _testarrayoftables = testarrayoftables,
+ _enemy = enemy,
+ _testnestedflatbuffer = testnestedflatbuffer,
+ _testempty = testempty,
+ _testbool = testbool,
+ _testhashs32Fnv1 = testhashs32Fnv1,
+ _testhashu32Fnv1 = testhashu32Fnv1,
+ _testhashs64Fnv1 = testhashs64Fnv1,
+ _testhashu64Fnv1 = testhashu64Fnv1,
+ _testhashs32Fnv1a = testhashs32Fnv1a,
+ _testhashu32Fnv1a = testhashu32Fnv1a,
+ _testhashs64Fnv1a = testhashs64Fnv1a,
+ _testhashu64Fnv1a = testhashu64Fnv1a,
+ _testarrayofbools = testarrayofbools,
+ _testf = testf,
+ _testf2 = testf2,
+ _testf3 = testf3,
+ _testarrayofstring2 = testarrayofstring2,
+ _testarrayofsortedstruct = testarrayofsortedstruct,
+ _flex = flex,
+ _test5 = test5,
+ _vectorOfLongs = vectorOfLongs,
+ _vectorOfDoubles = vectorOfDoubles,
+ _parentNamespaceTest = parentNamespaceTest,
+ _vectorOfReferrables = vectorOfReferrables,
+ _singleWeakReference = singleWeakReference,
+ _vectorOfWeakReferences = vectorOfWeakReferences,
+ _vectorOfStrongReferrables = vectorOfStrongReferrables,
+ _coOwningReference = coOwningReference,
+ _vectorOfCoOwningReferences = vectorOfCoOwningReferences,
+ _nonOwningReference = nonOwningReference,
+ _vectorOfNonOwningReferences = vectorOfNonOwningReferences;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+ final int inventoryOffset = _inventory?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_inventory)
+ : null;
+ final int testOffset = _test?.getOrCreateOffset(fbBuilder);
+ final int test4Offset = _test4?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_test4)
+ : null;
+ final int testarrayofstringOffset = _testarrayofstring?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayofstring.map((b) => fbBuilder.writeString(b)).toList())
+ : null;
+ final int testarrayoftablesOffset = _testarrayoftables?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayoftables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int enemyOffset = _enemy?.getOrCreateOffset(fbBuilder);
+ final int testnestedflatbufferOffset = _testnestedflatbuffer?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_testnestedflatbuffer)
+ : null;
+ final int testemptyOffset = _testempty?.getOrCreateOffset(fbBuilder);
+ final int testarrayofboolsOffset = _testarrayofbools?.isNotEmpty == true
+ ? fbBuilder.writeListBool(_testarrayofbools)
+ : null;
+ final int testarrayofstring2Offset = _testarrayofstring2?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayofstring2.map((b) => fbBuilder.writeString(b)).toList())
+ : null;
+ final int testarrayofsortedstructOffset = _testarrayofsortedstruct?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_testarrayofsortedstruct)
+ : null;
+ final int flexOffset = _flex?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_flex)
+ : null;
+ final int test5Offset = _test5?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_test5)
+ : null;
+ final int vectorOfLongsOffset = _vectorOfLongs?.isNotEmpty == true
+ ? fbBuilder.writeListInt64(_vectorOfLongs)
+ : null;
+ final int vectorOfDoublesOffset = _vectorOfDoubles?.isNotEmpty == true
+ ? fbBuilder.writeListFloat64(_vectorOfDoubles)
+ : null;
+ final int parentNamespaceTestOffset = _parentNamespaceTest?.getOrCreateOffset(fbBuilder);
+ final int vectorOfReferrablesOffset = _vectorOfReferrables?.isNotEmpty == true
+ ? fbBuilder.writeList(_vectorOfReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int vectorOfWeakReferencesOffset = _vectorOfWeakReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfWeakReferences)
+ : null;
+ final int vectorOfStrongReferrablesOffset = _vectorOfStrongReferrables?.isNotEmpty == true
+ ? fbBuilder.writeList(_vectorOfStrongReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int vectorOfCoOwningReferencesOffset = _vectorOfCoOwningReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfCoOwningReferences)
+ : null;
+ final int vectorOfNonOwningReferencesOffset = _vectorOfNonOwningReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfNonOwningReferences)
+ : null;
+
+ fbBuilder.startTable();
+ if (_pos != null) {
+ fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+ }
+ fbBuilder.addInt16(1, _mana);
+ fbBuilder.addInt16(2, _hp);
+ if (nameOffset != null) {
+ fbBuilder.addOffset(3, nameOffset);
+ }
+ if (inventoryOffset != null) {
+ fbBuilder.addOffset(5, inventoryOffset);
+ }
+ fbBuilder.addInt8(6, _color?.value);
+ fbBuilder.addUint8(7, _testType?.value);
+ if (testOffset != null) {
+ fbBuilder.addOffset(8, testOffset);
+ }
+ if (test4Offset != null) {
+ fbBuilder.addOffset(9, test4Offset);
+ }
+ if (testarrayofstringOffset != null) {
+ fbBuilder.addOffset(10, testarrayofstringOffset);
+ }
+ if (testarrayoftablesOffset != null) {
+ fbBuilder.addOffset(11, testarrayoftablesOffset);
+ }
+ if (enemyOffset != null) {
+ fbBuilder.addOffset(12, enemyOffset);
+ }
+ if (testnestedflatbufferOffset != null) {
+ fbBuilder.addOffset(13, testnestedflatbufferOffset);
+ }
+ if (testemptyOffset != null) {
+ fbBuilder.addOffset(14, testemptyOffset);
+ }
+ fbBuilder.addBool(15, _testbool);
+ fbBuilder.addInt32(16, _testhashs32Fnv1);
+ fbBuilder.addUint32(17, _testhashu32Fnv1);
+ fbBuilder.addInt64(18, _testhashs64Fnv1);
+ fbBuilder.addUint64(19, _testhashu64Fnv1);
+ fbBuilder.addInt32(20, _testhashs32Fnv1a);
+ fbBuilder.addUint32(21, _testhashu32Fnv1a);
+ fbBuilder.addInt64(22, _testhashs64Fnv1a);
+ fbBuilder.addUint64(23, _testhashu64Fnv1a);
+ if (testarrayofboolsOffset != null) {
+ fbBuilder.addOffset(24, testarrayofboolsOffset);
+ }
+ fbBuilder.addFloat32(25, _testf);
+ fbBuilder.addFloat32(26, _testf2);
+ fbBuilder.addFloat32(27, _testf3);
+ if (testarrayofstring2Offset != null) {
+ fbBuilder.addOffset(28, testarrayofstring2Offset);
+ }
+ if (testarrayofsortedstructOffset != null) {
+ fbBuilder.addOffset(29, testarrayofsortedstructOffset);
+ }
+ if (flexOffset != null) {
+ fbBuilder.addOffset(30, flexOffset);
+ }
+ if (test5Offset != null) {
+ fbBuilder.addOffset(31, test5Offset);
+ }
+ if (vectorOfLongsOffset != null) {
+ fbBuilder.addOffset(32, vectorOfLongsOffset);
+ }
+ if (vectorOfDoublesOffset != null) {
+ fbBuilder.addOffset(33, vectorOfDoublesOffset);
+ }
+ if (parentNamespaceTestOffset != null) {
+ fbBuilder.addOffset(34, parentNamespaceTestOffset);
+ }
+ if (vectorOfReferrablesOffset != null) {
+ fbBuilder.addOffset(35, vectorOfReferrablesOffset);
+ }
+ fbBuilder.addUint64(36, _singleWeakReference);
+ if (vectorOfWeakReferencesOffset != null) {
+ fbBuilder.addOffset(37, vectorOfWeakReferencesOffset);
+ }
+ if (vectorOfStrongReferrablesOffset != null) {
+ fbBuilder.addOffset(38, vectorOfStrongReferrablesOffset);
+ }
+ fbBuilder.addUint64(39, _coOwningReference);
+ if (vectorOfCoOwningReferencesOffset != null) {
+ fbBuilder.addOffset(40, vectorOfCoOwningReferencesOffset);
+ }
+ fbBuilder.addUint64(41, _nonOwningReference);
+ if (vectorOfNonOwningReferencesOffset != null) {
+ fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class TypeAliases {
+ TypeAliases._(this._bc, this._bcOffset);
+ factory TypeAliases(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TypeAliases> reader = const _TypeAliasesReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get i8 => const fb.Int8Reader().vTableGet(_bc, _bcOffset, 4, null);
+ int get u8 => const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 6, null);
+ int get i16 => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, null);
+ int get u16 => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 10, null);
+ int get i32 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 12, null);
+ int get u32 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 14, null);
+ int get i64 => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 16, null);
+ int get u64 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 18, null);
+ double get f32 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 20, 0.0);
+ double get f64 => const fb.Float64Reader().vTableGet(_bc, _bcOffset, 22, 0.0);
+ List<int> get v8 => const fb.ListReader<int>(const fb.Int8Reader()).vTableGet(_bc, _bcOffset, 24, null);
+ List<double> get vf64 => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 26, null);
+
+ @override
+ String toString() {
+ return 'TypeAliases{i8: $i8, u8: $u8, i16: $i16, u16: $u16, i32: $i32, u32: $u32, i64: $i64, u64: $u64, f32: $f32, f64: $f64, v8: $v8, vf64: $vf64}';
+ }
+}
+
+class _TypeAliasesReader extends fb.TableReader<TypeAliases> {
+ const _TypeAliasesReader();
+
+ @override
+ TypeAliases createObject(fb.BufferContext bc, int offset) =>
+ new TypeAliases._(bc, offset);
+}
+
+class TypeAliasesBuilder {
+ TypeAliasesBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addI8(int i8) {
+ fbBuilder.addInt8(0, i8);
+ return fbBuilder.offset;
+ }
+ int addU8(int u8) {
+ fbBuilder.addUint8(1, u8);
+ return fbBuilder.offset;
+ }
+ int addI16(int i16) {
+ fbBuilder.addInt16(2, i16);
+ return fbBuilder.offset;
+ }
+ int addU16(int u16) {
+ fbBuilder.addUint16(3, u16);
+ return fbBuilder.offset;
+ }
+ int addI32(int i32) {
+ fbBuilder.addInt32(4, i32);
+ return fbBuilder.offset;
+ }
+ int addU32(int u32) {
+ fbBuilder.addUint32(5, u32);
+ return fbBuilder.offset;
+ }
+ int addI64(int i64) {
+ fbBuilder.addInt64(6, i64);
+ return fbBuilder.offset;
+ }
+ int addU64(int u64) {
+ fbBuilder.addUint64(7, u64);
+ return fbBuilder.offset;
+ }
+ int addF32(double f32) {
+ fbBuilder.addFloat32(8, f32);
+ return fbBuilder.offset;
+ }
+ int addF64(double f64) {
+ fbBuilder.addFloat64(9, f64);
+ return fbBuilder.offset;
+ }
+ int addV8Offset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+ int addVf64Offset(int offset) {
+ fbBuilder.addOffset(11, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TypeAliasesObjectBuilder extends fb.ObjectBuilder {
+ final int _i8;
+ final int _u8;
+ final int _i16;
+ final int _u16;
+ final int _i32;
+ final int _u32;
+ final int _i64;
+ final int _u64;
+ final double _f32;
+ final double _f64;
+ final List<int> _v8;
+ final List<double> _vf64;
+
+ TypeAliasesObjectBuilder({
+ int i8,
+ int u8,
+ int i16,
+ int u16,
+ int i32,
+ int u32,
+ int i64,
+ int u64,
+ double f32,
+ double f64,
+ List<int> v8,
+ List<double> vf64,
+ })
+ : _i8 = i8,
+ _u8 = u8,
+ _i16 = i16,
+ _u16 = u16,
+ _i32 = i32,
+ _u32 = u32,
+ _i64 = i64,
+ _u64 = u64,
+ _f32 = f32,
+ _f64 = f64,
+ _v8 = v8,
+ _vf64 = vf64;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int v8Offset = _v8?.isNotEmpty == true
+ ? fbBuilder.writeListInt8(_v8)
+ : null;
+ final int vf64Offset = _vf64?.isNotEmpty == true
+ ? fbBuilder.writeListFloat64(_vf64)
+ : null;
+
+ fbBuilder.startTable();
+ fbBuilder.addInt8(0, _i8);
+ fbBuilder.addUint8(1, _u8);
+ fbBuilder.addInt16(2, _i16);
+ fbBuilder.addUint16(3, _u16);
+ fbBuilder.addInt32(4, _i32);
+ fbBuilder.addUint32(5, _u32);
+ fbBuilder.addInt64(6, _i64);
+ fbBuilder.addUint64(7, _u64);
+ fbBuilder.addFloat32(8, _f32);
+ fbBuilder.addFloat64(9, _f64);
+ if (v8Offset != null) {
+ fbBuilder.addOffset(10, v8Offset);
+ }
+ if (vf64Offset != null) {
+ fbBuilder.addOffset(11, vf64Offset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/dart/test/monster_test_my_game_generated.dart b/dart/test/monster_test_my_game_generated.dart
new file mode 100644
index 00000000..425bae33
--- /dev/null
+++ b/dart/test/monster_test_my_game_generated.dart
@@ -0,0 +1,60 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import './monster_test_my_game.example2_generated.dart' as my_game_example2;
+import './monster_test_my_game.example_generated.dart' as my_game_example;
+
+class InParentNamespace {
+ InParentNamespace._(this._bc, this._bcOffset);
+ factory InParentNamespace(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<InParentNamespace> reader = const _InParentNamespaceReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+
+ @override
+ String toString() {
+ return 'InParentNamespace{}';
+ }
+}
+
+class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
+ const _InParentNamespaceReader();
+
+ @override
+ InParentNamespace createObject(fb.BufferContext bc, int offset) =>
+ new InParentNamespace._(bc, offset);
+}
+
+class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
+
+ InParentNamespaceObjectBuilder();
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md
index 1c0b50e6..6401c44d 100644
--- a/docs/source/Compiler.md
+++ b/docs/source/Compiler.md
@@ -35,6 +35,8 @@ For any schema input files, one or more generators can be specified:
- `--grpc`: Generate RPC stub code for GRPC.
+- `--dart`: Generate Dart code.
+
For any data input files:
- `--binary`, `-b` : If data is contained in this file, generate a
diff --git a/docs/source/DartUsage.md b/docs/source/DartUsage.md
new file mode 100644
index 00000000..6be97726
--- /dev/null
+++ b/docs/source/DartUsage.md
@@ -0,0 +1,108 @@
+Use in Dart {#flatbuffers_guide_use_dart}
+===========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Dart, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
+to general FlatBuffers usage in all of the supported languages (including Dart).
+This page is designed to cover the nuances of FlatBuffers usage, specific to
+Dart.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Dart library code location
+
+The code for the FlatBuffers Go library can be found at
+`flatbuffers/dart`. You can browse the library code on the [FlatBuffers
+GitHub page](https://github.com/google/flatbuffers/tree/master/dart).
+
+## Testing the FlatBuffers Dart library
+
+The code to test the Dart library can be found at `flatbuffers/tests`.
+The test code itself is located in [dart_test.dart](https://github.com/google/
+flatbuffers/blob/master/tests/dart_test.dart).
+
+To run the tests, use the [DartTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/DartTest.sh) shell script.
+
+*Note: The shell script requires the [Dart SDK](https://www.dartlang.org/tools/sdk)
+to be installed.*
+
+## Using the FlatBuffers Dart library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Dart.*
+
+FlatBuffers supports reading and writing binary FlatBuffers in Dart.
+
+To use FlatBuffers in your own code, first generate Dart classes from your
+schema with the `--dart` option to `flatc`. Then you can include both FlatBuffers
+and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Dart: First,
+include the library and generated code. Then read a FlatBuffer binary file into
+a `List<int>`, which you pass to the factory constructor for `Monster`:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
+import 'dart:io' as io;
+
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+import './monster_my_game.sample_generated.dart' as myGame;
+
+List<int> data = await new io.File('monster.dat').readAsBytes();
+var monster = new myGame.Monster(data);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
+var hp = monster.hp;
+var pos = monster.pos;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+## Differences from the Dart SDK Front End flat_buffers
+
+The work in this repository is signfiicantly based on the implementation used
+internally by the Dart SDK in the front end/analyzer package. Several
+significant changes have been made.
+
+1. Support for packed boolean lists has been removed. This is not standard
+ in other implementations and is not compatible with them. Do note that,
+ like in the JavaScript implementation, __null values in boolean lists
+ will be treated as false__. It is also still entirely possible to pack data
+ in a single scalar field, but that would have to be done on the application
+ side.
+2. The SDK implementation supports enums with regular Dart enums, which
+ works if enums are always indexed at 1; however, FlatBuffers does not
+ require that. This implementation uses specialized enum-like classes to
+ ensure proper mapping from FlatBuffers to Dart and other platforms.
+3. The SDK implementation does not appear to support FlatBuffer structs or
+ vectors of structs - it treated everything as a built-in scalar or a table.
+ This implementation treats structs in a way that is compatible with other
+ non-Dart implementations, and properly handles vectors of structs. Many of
+ the methods prefixed with 'low' have been prepurposed to support this.
+4. The SDK implementation treats int64 and uint64 as float64s. This
+ implementation does not. This may cause problems with JavaScript
+ compatibility - however, it should be possible to use the JavaScript
+ implementation, or to do a customized implementation that treats all 64 bit
+ numbers as floats. Supporting the Dart VM and Flutter was a more important
+ goal of this implementation. Support for 16 bit integers was also added.
+5. The code generation in this offers an "ObjectBuilder", which generates code
+ very similar to the SDK classes that consume FlatBuffers, as well as Builder
+ classes, which produces code which more closely resembles the builders in
+ other languages. The ObjectBuilder classes are easier to use, at the cost of
+ additional references allocated.
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Dart, though you could use the C++ parser through Dart Native Extensions.
+Please see the C++ documentation for more on text parsing (note that this is
+not currently an option in Flutter - follow [this issue](https://github.com/flutter/flutter/issues/7053)
+for the latest).
+
+<br>
diff --git a/docs/source/Support.md b/docs/source/Support.md
index e1fc5633..d41a8dd8 100644
--- a/docs/source/Support.md
+++ b/docs/source/Support.md
@@ -18,23 +18,24 @@ In general:
NOTE: this table is a start, it needs to be extended.
-Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Ruby
------------------------------- | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ----
-Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP
-JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No
-Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No
-Reflection | Yes | No | No | No | No | No | No | Basic | No | No
-Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No
-Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ?
-Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | ?
-Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ?
-Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | ?
-Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | ?
-Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | ?
-Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | ?
-Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | ?
-Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ?
-Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | kr | mik* | ch* | rw
+Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Ruby | Dart
+------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ---- | ----
+Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP | Yes
+JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | No
+Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No
+Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No
+Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No
+Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? | Yes
+Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | ? | No
+Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | ?
+Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | ? | Yes
+Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | ? | Yes
+Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | ? | Yes
+Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | ? | Flutter
+Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter
+Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | ?
+Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | kr | mik* | ch* | rw | dnfield
+
* ev = evolutional
* js = jonsimantov
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index 1c54829f..1424e82c 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -30,6 +30,7 @@ Please select your desired language for our quest:
<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>
</form>
\endhtmlonly
@@ -132,6 +133,9 @@ For your chosen language, please cross-reference with:
<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>
## Writing the Monsters' FlatBuffer Schema
@@ -312,6 +316,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
flatcc/samples/monster/build.sh
~~~
</div>
+<div class="language-dart">
+~~~{.sh}
+ cd flatbuffers/sample
+ ./../flatc --dart samples/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)
@@ -421,6 +431,14 @@ The first step is to import/include the library, generated files, etc.
#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>
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
@@ -491,6 +509,15 @@ which will grow automatically if needed:
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>
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`.
@@ -633,6 +660,51 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
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 genearted 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>
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
@@ -760,6 +832,26 @@ traversal. This is generally easy to do on any tree structures.
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>
We serialized two built-in data types (`string` and `vector`) and captured
their return values. These values are offsets into the serialized data,
@@ -863,6 +955,15 @@ offsets.
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-cpp">
<br>
@@ -943,6 +1044,25 @@ for the `path` field above:
// 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 lenght 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>
We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself:
@@ -1095,6 +1215,58 @@ can serialize the monster itself:
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>
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
@@ -1226,6 +1398,17 @@ Here is a repetition these lines, to help highlight them more clearly:
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>
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
@@ -1291,6 +1474,12 @@ appropriate `finish` method.
// 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>
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
@@ -1383,6 +1572,11 @@ like so:
flatcc_builder_clear(B);
~~~
</div>
+<div class="language-dart">
+~~~{.dart}
+ final Uint8List buf = builder.finish(orc);
+~~~
+</div>
Now you can write the bytes to a file, send them over the network..
**Make sure your file mode (or tranfer protocol) is set to BINARY, not text.**
@@ -1490,6 +1684,12 @@ before:
#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>
Then, assuming you have a buffer of bytes received from disk,
network, etc., you can create start accessing the buffer like so:
@@ -1591,6 +1791,13 @@ won't work**
// 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>
If you look in the generated files from the schema compiler, you will see it generated
accessors for all non-`deprecated` fields. For example:
@@ -1611,7 +1818,7 @@ accessors for all non-`deprecated` fields. For example:
</div>
<div class="language-csharp">
~~~{.cs}
- // For C#, unlike other languages support by FlatBuffers, most values (except for
+ // For C#, unlike most other languages support by FlatBuffers, most values (except for
// vectors and unions) are available as propreties instead of asccessor methods.
var hp = monster.Hp
var mana = monster.Mana
@@ -1660,6 +1867,15 @@ accessors for all non-`deprecated` fields. For example:
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 propreties instead of asccessor methods.
+ var hp = monster.hp;
+ var mana = monster.mana;
+ var name = monster.name;
+~~~
+</div>
These should hold `300`, `150`, and `"Orc"` respectively.
@@ -1745,6 +1961,14 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
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>
`x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively.
@@ -1811,6 +2035,12 @@ FlatBuffers `vector`.
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>
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`:
@@ -1885,6 +2115,13 @@ except your need to handle the result as a FlatBuffer `table`:
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>
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.
@@ -2008,6 +2245,18 @@ We can access the type to dynamically cast the data as needed (since the
}
~~~
</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>
## Mutating FlatBuffers
@@ -2083,6 +2332,11 @@ mutators like so:
(except in-place vector sorting is possible).>
~~~
</div>
+<div class="language-dart">
+~~~{.dart}
+ <API for mutating FlatBuffers not yet available in Dart.>
+~~~
+</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
@@ -2192,5 +2446,8 @@ For your chosen language, see:
<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>
<br>
diff --git a/docs/source/doxyfile b/docs/source/doxyfile
index 64af6710..fb9b695c 100644
--- a/docs/source/doxyfile
+++ b/docs/source/doxyfile
@@ -751,6 +751,7 @@ INPUT = "FlatBuffers.md" \
"Schemas.md" \
"CppUsage.md" \
"CUsage.md" \
+ "DartUsage.md" \
"GoUsage.md" \
"JavaCsharpUsage.md" \
"JavaScriptUsage.md" \
diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml
index 1096cfff..c7233143 100644
--- a/docs/source/doxygen_layout.xml
+++ b/docs/source/doxygen_layout.xml
@@ -39,6 +39,8 @@
title="Use in PHP"/>
<tab type="user" url="@ref flatbuffers_guide_use_python"
title="Use in Python"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_dart"
+ title="Use in Dart"/>
<tab type="user" url="@ref flexbuffers"
title="Schema-less version"/>
<tab type="usergroup" url="" title="gRPC">
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index c261b74a..a40c5c19 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -405,6 +405,7 @@ struct IDLOptions {
kBinary = 1 << 8,
kTs = 1 << 9,
kJsonSchema = 1 << 10,
+ kDart = 1 << 11,
kMAX
};
@@ -767,6 +768,10 @@ extern bool GenerateCPP(const Parser &parser,
const std::string &path,
const std::string &file_name);
+extern bool GenerateDart(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
// See idl_gen_js.
extern bool GenerateJS(const Parser &parser,
@@ -823,6 +828,12 @@ extern std::string CPPMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name);
+// Generate a make rule for the generated Dart code
+// see idl_gen_dart.cpp
+extern std::string DartMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
// Generate a make rule for the generated Java/C#/... files.
// See idl_gen_general.cpp.
extern std::string GeneralMakeRule(const Parser &parser,
diff --git a/samples/dart_sample.sh b/samples/dart_sample.sh
new file mode 100755
index 00000000..56160666
--- /dev/null
+++ b/samples/dart_sample.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# Copyright 2018 Dan Field. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `Node.js` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+cd ../dart/example
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../../flatc ]; then
+ ../../flatc --dart ../../samples/monster.fbs
+elif [ -e ../../Debug/flatc ]; then
+ ../../Debug/flatc --dart ../../samples/monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the Dart sample.
+
+# Execute the sample.
+dart example.dart
+
+# Cleanup temporary files.
+git checkout monster_my_game.sample_generated.dart
+
+cd ../../samples
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index d093020e..1fed8952 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -58,6 +58,9 @@ int main(int argc, const char *argv[]) {
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript", true, nullptr,
flatbuffers::IDLOptions::kJs,
"Generate JavaScript code for tables/structs", flatbuffers::JSMakeRule },
+ { flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
+ flatbuffers::IDLOptions::kDart,
+ "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
{ flatbuffers::GenerateJS, "-T", "--ts", "TypeScript", true, nullptr,
flatbuffers::IDLOptions::kTs,
"Generate TypeScript code for tables/structs", flatbuffers::JSMakeRule },
diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp
new file mode 100644
index 00000000..41343d76
--- /dev/null
+++ b/src/idl_gen_dart.cpp
@@ -0,0 +1,890 @@
+/*
+ * Copyright 2018 Dan Field
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+#include <cassert>
+#include <unordered_map>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.dart";
+}
+
+namespace dart {
+
+const std::string _kFb = "fb";
+// see https://www.dartlang.org/guides/language/language-tour#keywords
+// yeild*, async*, and sync* shouldn't be problems anyway but keeping them in
+static const char *keywords[] = {
+ "abstract", "deferred", "if", "super", "as", "do",
+ "implements", "switch", "assert", "dynamic", "import", "sync*",
+ "async", "else", "in", "this", "async*", "enum",
+ "is", "throw", "await", "export", "library", "true",
+ "break", "external", "new", "try", "case", "extends",
+ "null", "typedef", "catch", "factory", "operator", "var",
+ "class", "false", "part", "void", "const", "final",
+ "rethrow", "while", "continue", "finally", "return", "with",
+ "covariant", "for", "set", "yield", "default", "get",
+ "static", "yield*"
+};
+
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class DartGenerator : public BaseGenerator {
+ public:
+ typedef std::unordered_map<std::string, std::string> namespace_code_map;
+
+ DartGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "."){};
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ std::string code;
+ namespace_code_map namespace_code;
+ GenerateEnums(&namespace_code);
+ GenerateStructs(&namespace_code);
+
+ for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
+ code.clear();
+ code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
+ code = code +
+ "// ignore_for_file: unused_import, unused_field, "
+ "unused_local_variable\n\n";
+
+ code += "library " + kv->first + ";\n\n";
+
+ code += "import 'dart:typed_data' show Uint8List;\n";
+ code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
+ ";\n\n";
+
+ for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
+ ++kv2) {
+ if (kv2->first != kv->first) {
+ code += "import '" +
+ GeneratedFileName("./", file_name_ + "_" + kv2->first) +
+ "' as " + ImportAliasName(kv2->first) + ";\n";
+ }
+ }
+ code += "\n";
+ code += kv->second;
+
+ if (!SaveFile(
+ GeneratedFileName(path_, file_name_ + "_" + kv->first).c_str(),
+ code, false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ static std::string ImportAliasName(const std::string &ns) {
+ std::string ret;
+ ret.assign(ns);
+ size_t pos = ret.find(".");
+ while (pos != std::string::npos) {
+ ret.replace(pos, 1, "_");
+ pos = ret.find(".", pos + 1);
+ }
+
+ return ret;
+ }
+
+ static std::string BuildNamespaceName(const Namespace &ns) {
+ std::stringstream sstream;
+ std::copy(ns.components.begin(), ns.components.end() - 1,
+ std::ostream_iterator<std::string>(sstream, "."));
+
+ auto ret = sstream.str() + ns.components.back();
+ for (int i = 0; ret[i]; i++) {
+ auto lower = tolower(ret[i]);
+ if (lower != ret[i]) {
+ ret[i] = static_cast<char>(lower);
+ if (i != 0 && ret[i - 1] != '.') {
+ ret.insert(i, "_");
+ i++;
+ }
+ }
+ }
+ // std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
+ return ret;
+ }
+ static std::string EscapeKeyword(const std::string &name) {
+ for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+ if (name == keywords[i]) { return MakeCamel(name + "_", false); }
+ }
+
+ return MakeCamel(name, false);
+ }
+
+ void GenerateEnums(namespace_code_map *namespace_code) {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, namespace_code); // enum_code_ptr);
+ }
+ }
+
+ void GenerateStructs(namespace_code_map *namespace_code) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(struct_def, namespace_code);
+ }
+ }
+
+ // Generate a documentation comment, if available.
+ static void GenDocComment(const std::vector<std::string> &dc,
+ std::string *code_ptr,
+ const std::string &extra_lines,
+ const char *indent = nullptr) {
+ if (dc.empty() && extra_lines.empty()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ auto &code = *code_ptr;
+ if (indent) code += indent;
+
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ if (indent) code += indent;
+ code += "/// " + *it + "\n";
+ }
+ if (!extra_lines.empty()) {
+ if (!dc.empty()) {
+ if (indent) code += indent;
+ code += "///\n";
+ }
+ if (indent) code += indent;
+ std::string::size_type start = 0;
+ for (;;) {
+ auto end = extra_lines.find('\n', start);
+ if (end != std::string::npos) {
+ code += "/// " + extra_lines.substr(start, end - start) + "\n";
+ start = end + 1;
+ } else {
+ code += "/// " + extra_lines.substr(start) + "\n";
+ break;
+ }
+ }
+ }
+ }
+
+ static void GenDocComment(std::string *code_ptr,
+ const std::string &extra_lines) {
+ GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
+ }
+
+ // Generate an enum declaration and an enum string lookup table.
+ void GenEnum(EnumDef &enum_def, namespace_code_map *namespace_code) {
+ if (enum_def.generated) return;
+ auto ns = BuildNamespaceName(*enum_def.defined_namespace);
+ std::string code;
+ GenDocComment(enum_def.doc_comment, &code, "");
+
+ auto name = enum_def.is_union ? enum_def.name + "TypeId" : enum_def.name;
+ auto is_bit_flags = enum_def.attributes.Lookup("bit_flags");
+
+ code += "class " + name + " {\n";
+ code += " final int value;\n";
+ code += " const " + name + "._(this.value);\n\n";
+ code += " factory " + name + ".fromValue(int value) {\n";
+ code += " if (value == null) return null;\n";
+
+ code += " if (!values.containsKey(value)) {\n";
+ code +=
+ " throw new StateError('Invalid value $value for bit flag enum ";
+ code += name + "');\n";
+ code += " }\n";
+
+ code += " return values[value];\n";
+ code += " }\n\n";
+
+ // this is meaningless for bit_flags
+ // however, note that unlike "regular" dart enums this enum can still have
+ // holes.
+ if (!is_bit_flags) {
+ code += " static const int minValue = " +
+ NumToString(enum_def.vals.vec.front()->value) + ";\n";
+ code += " static const int maxValue = " +
+ NumToString(enum_def.vals.vec.back()->value) + ";\n";
+ }
+
+ code +=
+ " static bool containsValue(int value) =>"
+ " values.containsKey(value);\n\n";
+
+ for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+
+ if (!ev.doc_comment.empty()) {
+ if (it != enum_def.vals.vec.begin()) { code += '\n'; }
+ GenDocComment(ev.doc_comment, &code, "", " ");
+ }
+ code += " static const " + name + " " + ev.name + " = ";
+ code += "const " + name + "._(" + NumToString(ev.value) + ");\n";
+ }
+
+ code += " static get values => {";
+ for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ code += NumToString(ev.value) + ": " + ev.name + ",";
+ }
+ code += "};\n\n";
+
+ code += " static const " + _kFb + ".Reader<" + name +
+ "> reader = const _" + name + "Reader();\n\n";
+ code += " @override\n";
+ code += " String toString() {\n";
+ code += " return '" + name + "{value: $value}';\n";
+ code += " }\n";
+ code += "}\n\n";
+
+ GenEnumReader(enum_def, name, &code);
+ (*namespace_code)[ns] += code;
+ }
+
+ void GenEnumReader(EnumDef &enum_def, const std::string &name,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += "class _" + name + "Reader extends " + _kFb + ".Reader<" + name +
+ "> {\n";
+ code += " const _" + name + "Reader();\n\n";
+ code += " @override\n";
+ code += " int get size => 1;\n\n";
+ code += " @override\n";
+ code +=
+ " " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n";
+ code += " new " + name + ".fromValue(const " + _kFb + "." +
+ GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
+ code += "}\n\n";
+ }
+
+ static std::string GenType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "Bool";
+ case BASE_TYPE_CHAR: return "Int8";
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_UCHAR: return "Uint8";
+ case BASE_TYPE_SHORT: return "Int16";
+ case BASE_TYPE_USHORT: return "Uint16";
+ case BASE_TYPE_INT: return "Int32";
+ case BASE_TYPE_UINT: return "Uint32";
+ case BASE_TYPE_LONG: return "Int64";
+ case BASE_TYPE_ULONG: return "Uint64";
+ case BASE_TYPE_FLOAT: return "Float32";
+ case BASE_TYPE_DOUBLE: return "Float64";
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION: return type.enum_def->name + "TypeId";
+ default: return "Table";
+ }
+ }
+
+ std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def,
+ bool parent_is_vector = false) {
+ if (type.base_type == BASE_TYPE_BOOL) {
+ return "const " + _kFb + ".BoolReader()";
+ } else if (type.base_type == BASE_TYPE_VECTOR) {
+ return "const " + _kFb + ".ListReader<" +
+ GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
+ GenReaderTypeName(type.VectorType(), current_namespace, def,
+ true) +
+ ")";
+ } else if (type.base_type == BASE_TYPE_STRING) {
+ return "const " + _kFb + ".StringReader()";
+ }
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def && parent_is_vector) {
+ return GenDartTypeName(type, current_namespace, def) + ".reader";
+ }
+ return "const " + _kFb + "." + GenType(type) + "Reader()";
+ } else {
+ return GenDartTypeName(type, current_namespace, def) + ".reader";
+ }
+ }
+
+ std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def, bool addBuilder = false) {
+ if (type.enum_def) {
+ if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
+ return type.enum_def->name + "TypeId";
+ } else if (type.enum_def->is_union) {
+ return "dynamic";
+ } else if (type.base_type != BASE_TYPE_VECTOR) {
+ return type.enum_def->name;
+ }
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "bool";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR: return "int";
+ case BASE_TYPE_FLOAT:
+ case BASE_TYPE_DOUBLE: return "double";
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_STRUCT:
+ return MaybeWrapNamespace(
+ type.struct_def->name + (addBuilder ? "ObjectBuilder" : ""),
+ current_namespace, def);
+ case BASE_TYPE_VECTOR:
+ return "List<" +
+ GenDartTypeName(type.VectorType(), current_namespace, def,
+ addBuilder) +
+ ">";
+ default: assert(0); return "dynamic";
+ }
+ }
+
+ static const std::string MaybeWrapNamespace(const std::string &type_name,
+ Namespace *current_ns,
+ const FieldDef &field) {
+ auto curr_ns_str = BuildNamespaceName(*current_ns);
+ std::string field_ns_str = "";
+ if (field.value.type.struct_def) {
+ field_ns_str +=
+ BuildNamespaceName(*field.value.type.struct_def->defined_namespace);
+ } else if (field.value.type.enum_def) {
+ field_ns_str +=
+ BuildNamespaceName(*field.value.type.enum_def->defined_namespace);
+ }
+
+ if (field_ns_str != "" && field_ns_str != curr_ns_str) {
+ return ImportAliasName(field_ns_str) + "." + type_name;
+ } else {
+ return type_name;
+ }
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def,
+ namespace_code_map *namespace_code) {
+ if (struct_def.generated) return;
+
+ auto object_namespace = BuildNamespaceName(*struct_def.defined_namespace);
+ std::string code;
+
+ auto object_name = struct_def.name;
+
+ // Emit constructor
+
+ GenDocComment(struct_def.doc_comment, &code, "");
+
+ auto reader_name = "_" + struct_def.name + "Reader";
+ auto builder_name = struct_def.name + "Builder";
+ auto object_builder_name = struct_def.name + "ObjectBuilder";
+
+ std::string reader_code, builder_code;
+
+ code += "class " + struct_def.name + " {\n";
+
+ code += " " + struct_def.name + "._(this._bc, this._bcOffset);\n";
+ if (!struct_def.fixed) {
+ code += " factory " + struct_def.name + "(List<int> bytes) {\n";
+ code += " " + _kFb + ".BufferContext rootRef = new " + _kFb +
+ ".BufferContext.fromBytes(bytes);\n";
+ code += " return reader.read(rootRef, 0);\n";
+ code += " }\n";
+ }
+
+ code += "\n";
+ code += " static const " + _kFb + ".Reader<" + struct_def.name +
+ "> reader = const " + reader_name + "();\n\n";
+
+ code += " final " + _kFb + ".BufferContext _bc;\n";
+ code += " final int _bcOffset;\n\n";
+
+ GenImplementationGetters(struct_def, &code);
+
+ code += "}\n\n";
+
+ GenReader(struct_def, &reader_name, &reader_code);
+ GenBuilder(struct_def, &builder_name, &builder_code);
+ GenObjectBuilder(struct_def, &object_builder_name, &builder_code);
+
+ code += reader_code;
+ code += builder_code;
+
+ (*namespace_code)[object_namespace] += code;
+ }
+
+ std::string NamespaceAliasFromUnionType(const std::string &in) {
+ if (in.find("_") == std::string::npos) { return in; }
+
+ std::stringstream ss(in);
+ std::string item;
+ std::vector<std::string> parts;
+ std::string ns;
+
+ while (std::getline(ss, item, '_')) { parts.push_back(item); }
+
+ for (auto it = parts.begin(); it != parts.end() - 1; ++it) {
+ auto &part = *it;
+
+ for (size_t i = 0; i < part.length(); i++) {
+ if (i && !isdigit(part[i]) &&
+ part[i] == static_cast<char>(toupper(part[i]))) {
+ ns += "_";
+ ns += static_cast<char>(tolower(part[i]));
+ } else {
+ ns += static_cast<char>(tolower(part[i]));
+ }
+ }
+ if (it != parts.end() - 2) { ns += "_"; }
+ }
+
+ return ns + "." + parts.back();
+ }
+
+ void GenImplementationGetters(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ std::string field_name = MakeCamel(field.name, false);
+ std::string type_name = GenDartTypeName(
+ field.value.type, struct_def.defined_namespace, field, false);
+
+ GenDocComment(field.doc_comment, &code, "");
+
+ code += " " + type_name + " get " + field_name;
+ if (field.value.type.base_type == BASE_TYPE_UNION) {
+ code += " {\n";
+ code += " switch (" + field_name + "Type?.value) {\n";
+ for (auto en_it = field.value.type.enum_def->vals.vec.begin() + 1;
+ en_it != field.value.type.enum_def->vals.vec.end(); ++en_it) {
+ auto &ev = **en_it;
+
+ auto enum_name = NamespaceAliasFromUnionType(ev.name);
+ code += " case " + NumToString(ev.value) + ": return " +
+ enum_name + ".reader.vTableGet(_bc, _bcOffset, " +
+ NumToString(field.value.offset) + ", null);\n";
+ }
+ code += " default: return null;\n";
+ code += " }\n";
+ code += " }\n";
+ } else {
+ code += " => ";
+ if (field.value.type.enum_def &&
+ field.value.type.base_type != BASE_TYPE_VECTOR) {
+ code += "new " +
+ GenDartTypeName(field.value.type,
+ struct_def.defined_namespace, field) +
+ ".fromValue(";
+ }
+
+ code += GenReaderTypeName(field.value.type,
+ struct_def.defined_namespace, field);
+ if (struct_def.fixed) {
+ code +=
+ ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
+ } else {
+ code += ".vTableGet(_bc, _bcOffset, " +
+ NumToString(field.value.offset) + ", ";
+ if (!field.value.constant.empty() && field.value.constant != "0") {
+ code += field.value.constant;
+ } else {
+ code += "null";
+ }
+ code += ")";
+ }
+ if (field.value.type.enum_def &&
+ field.value.type.base_type != BASE_TYPE_VECTOR) {
+ code += ")";
+ }
+ code += ";\n";
+ }
+ }
+
+ code += "\n";
+
+ code += " @override\n";
+ code += " String toString() {\n";
+ code += " return '" + struct_def.name + "{";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code +=
+ MakeCamel(field.name, false) + ": $" + MakeCamel(field.name, false);
+ if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+ }
+ code += "}';\n";
+ code += " }\n";
+ }
+
+ void GenReader(const StructDef &struct_def, std::string *reader_name_ptr,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &reader_name = *reader_name_ptr;
+ auto &impl_name = struct_def.name;
+
+ code += "class " + reader_name + " extends " + _kFb;
+ if (struct_def.fixed) {
+ code += ".StructReader<";
+ } else {
+ code += ".TableReader<";
+ }
+ code += impl_name + "> {\n";
+ code += " const " + reader_name + "();\n\n";
+
+ if (struct_def.fixed) {
+ code += " @override\n";
+ code += " int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
+ }
+ code += " @override\n";
+ code += " " + impl_name +
+ " createObject(fb.BufferContext bc, int offset) => \n new " +
+ impl_name + "._(bc, offset);\n";
+ code += "}\n\n";
+ }
+
+ void GenBuilder(const StructDef &struct_def, std::string *builder_name_ptr,
+ std::string *code_ptr) {
+ if (struct_def.fields.vec.size() == 0) { return; }
+ auto &code = *code_ptr;
+ auto &builder_name = *builder_name_ptr;
+
+ code += "class " + builder_name + " {\n";
+ code += " " + builder_name + "(this.fbBuilder) {\n";
+ code += " assert(fbBuilder != null);\n";
+ code += " }\n\n";
+ code += " final " + _kFb + ".Builder fbBuilder;\n\n";
+
+ if (struct_def.fixed) {
+ StructBuilderBody(struct_def, code_ptr);
+ } else {
+ TableBuilderBody(struct_def, code_ptr);
+ }
+
+ code += "}\n\n";
+ }
+
+ void StructBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += " int finish(";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ if (IsStruct(field.value.type)) {
+ code += "fb.StructBuilder";
+ } else {
+ code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field);
+ }
+ code += " " + field.name;
+ if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+ }
+ code += ") {\n";
+
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+
+ if (field.padding) {
+ code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+ }
+
+ if (IsStruct(field.value.type)) {
+ code += " " + field.name + "();\n";
+ } else {
+ code += " fbBuilder.put" + GenType(field.value.type) + "(";
+ code += field.name;
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ }
+ }
+ code += " return fbBuilder.offset;\n";
+ code += " }\n\n";
+ }
+
+ void TableBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += " void begin() {\n";
+ code += " fbBuilder.startTable();\n";
+ code += " }\n\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+
+ if (IsScalar(field.value.type.base_type)) {
+ code += " int add" + MakeCamel(field.name) + "(";
+ code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field);
+ code += " " + MakeCamel(field.name, false) + ") {\n";
+ code += " fbBuilder.add" + GenType(field.value.type) + "(" +
+ NumToString(offset) + ", ";
+ code += MakeCamel(field.name, false);
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ } else if (IsStruct(field.value.type)) {
+ code += " int add" + MakeCamel(field.name) + "(int offset) {\n";
+ code +=
+ " fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
+ } else {
+ code += " int add" + MakeCamel(field.name) + "Offset(int offset) {\n";
+ code +=
+ " fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
+ }
+ code += " return fbBuilder.offset;\n";
+ code += " }\n";
+ }
+
+ code += "\n";
+ code += " int finish() {\n";
+ code += " return fbBuilder.endTable();\n";
+ code += " }\n";
+ }
+
+ void GenObjectBuilder(const StructDef &struct_def,
+ std::string *builder_name_ptr, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &builder_name = *builder_name_ptr;
+
+ code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += " final " +
+ GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field, true) +
+ " _" + MakeCamel(field.name, false) + ";\n";
+ }
+ code += "\n";
+ code += " " + builder_name + "(";
+ if (struct_def.fields.vec.size() != 0) {
+ code +=
+
+ "{\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += " " +
+ GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field, true) +
+ " " + MakeCamel(field.name, false) + ",\n";
+ }
+ code += " })\n";
+ code += " : ";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += "_" + MakeCamel(field.name, false) + " = " +
+ MakeCamel(field.name, false);
+ if (it == struct_def.fields.vec.end() - 1) {
+ code += ";\n\n";
+ } else {
+ code += ",\n ";
+ }
+ }
+ } else {
+ code += ");\n\n";
+ }
+
+ code += " /// Finish building, and store into the [fbBuilder].\n";
+ code += " @override\n";
+ code += " int finish(\n";
+ code += " " + _kFb + ".Builder fbBuilder) {\n";
+ code += " assert(fbBuilder != null);\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
+ continue;
+
+ code += " final int " + MakeCamel(field.name, false) + "Offset";
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code +=
+ " = _" + MakeCamel(field.name, false) + "?.isNotEmpty == true\n";
+ code += " ? fbBuilder.writeList";
+ switch (field.value.type.VectorType().base_type) {
+ case BASE_TYPE_STRING:
+ code += "(_" + MakeCamel(field.name, false) +
+ ".map((b) => fbBuilder.writeString(b)).toList())";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (field.value.type.struct_def->fixed) {
+ code += "OfStructs(_" + MakeCamel(field.name, false) + ")";
+ } else {
+ code += "(_" + MakeCamel(field.name, false) +
+ ".map((b) => b.getOrCreateOffset(fbBuilder)).toList())";
+ }
+ break;
+ default:
+ code += GenType(field.value.type.VectorType()) + "(_" +
+ MakeCamel(field.name, false);
+ if (field.value.type.enum_def) { code += ".map((f) => f.value)"; }
+ code += ")";
+ }
+ code += "\n : null;\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += " = fbBuilder.writeString(_" + field.name + ");\n";
+ } else {
+ code += " = _" + MakeCamel(field.name, false) +
+ "?.getOrCreateOffset(fbBuilder);\n";
+ }
+ }
+
+ code += "\n";
+ if (struct_def.fixed) {
+ StructObjectBuilderBody(struct_def, code_ptr);
+ } else {
+ TableObjectBuilderBody(struct_def, code_ptr);
+ }
+ code += " }\n\n";
+
+ code += " /// Convenience method to serialize to byte list.\n";
+ code += " @override\n";
+ code += " Uint8List toBytes([String fileIdentifier]) {\n";
+ code += " " + _kFb + ".Builder fbBuilder = new ";
+ code += _kFb + ".Builder();\n";
+ code += " int offset = finish(fbBuilder);\n";
+ code += " return fbBuilder.finish(offset, fileIdentifier);\n";
+ code += " }\n";
+ code += "}\n";
+ }
+
+ void StructObjectBuilderBody(const StructDef &struct_def,
+ std::string *code_ptr,
+ bool prependUnderscore = true) {
+ auto &code = *code_ptr;
+
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+
+ if (field.padding) {
+ code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+ }
+
+ if (IsStruct(field.value.type)) {
+ code += " ";
+ if (prependUnderscore) { code += "_"; }
+ code += field.name + ".finish(fbBuilder);\n";
+ } else {
+ code += " fbBuilder.put" + GenType(field.value.type) + "(";
+ if (prependUnderscore) { code += "_"; }
+ code += field.name;
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ }
+ }
+
+ code += " return fbBuilder.offset;\n";
+ }
+
+ void TableObjectBuilderBody(const StructDef &struct_def,
+ std::string *code_ptr,
+ bool prependUnderscore = true) {
+ std::string &code = *code_ptr;
+ code += " fbBuilder.startTable();\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ if (IsScalar(field.value.type.base_type)) {
+ code += " fbBuilder.add" + GenType(field.value.type) + "(" +
+ NumToString(offset) + ", ";
+ if (prependUnderscore) { code += "_"; }
+ code += MakeCamel(field.name, false);
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ } else if (IsStruct(field.value.type)) {
+ code += " if (";
+ if (prependUnderscore) { code += "_"; }
+ code += MakeCamel(field.name, false) + " != null) {\n";
+ code += " fbBuilder.addStruct(" + NumToString(offset) + ", ";
+ code += "_" + MakeCamel(field.name, false) + ".finish(fbBuilder));\n";
+ code += " }\n";
+ } else {
+ code +=
+ " if (" + MakeCamel(field.name, false) + "Offset != null) {\n";
+ code += " fbBuilder.addOffset(" + NumToString(offset) + ", " +
+ MakeCamel(field.name, false) + "Offset);\n";
+ code += " }\n";
+ }
+ }
+ code += " return fbBuilder.endTable();\n";
+ }
+};
+} // namespace dart
+
+bool GenerateDart(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ dart::DartGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string DartMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ assert(parser.opts.lang <= IDLOptions::kMAX);
+
+ auto filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ auto make_rule = GeneratedFileName(path, filebase) + ": ";
+
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/tests/DartTest.sh b/tests/DartTest.sh
new file mode 100755
index 00000000..1ec5ce4c
--- /dev/null
+++ b/tests/DartTest.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+
+command -v pub >/dev/null 2>&1 || { echo >&2 "Dart tests require `pub` but it's not installed. Aborting."; exit 1; }
+command -v dart >/dev/null 2>&1 || { echo >&2 "Dart tests require dart to be in path but it's not installed. Aborting."; exit 1; }
+# output required files to the dart folder so that pub will be able to
+# distrubte them and more people can more easily run the dart tests
+../flatc --dart -I include_test -o ../dart/test monster_test.fbs
+cp monsterdata_test.mon ../dart/test
+
+cd ../dart
+
+# update packages
+pub get
+# Execute the sample.
+dart test/flat_buffers_test.dart
+
+# cleanup
+rm ../dart/test/monsterdata_test.mon \ No newline at end of file
diff --git a/tests/TestAll.sh b/tests/TestAll.sh
index 463eb738..d2de3e90 100644
--- a/tests/TestAll.sh
+++ b/tests/TestAll.sh
@@ -36,6 +36,10 @@ echo "************************ PHP:"
php phpTest.php
sh phpUnionVectorTest.sh
+echo "************************ Dart:"
+
+sh DartTest.sh
+
echo "************************ C:"
echo "(in a different repo)"
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index 4b6db29b..c5304b69 100755
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
-../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+../flatc --cpp --java --csharp --dart --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
+../flatc --cpp --java --csharp --dart --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
../flatc --jsonschema --schema -I include_test monster_test.fbs