From 4e3a66c1410e77970184bc1f736d87406077c4bd Mon Sep 17 00:00:00 2001 From: Ivan Dlugos <6349682+vaind@users.noreply.github.com> Date: Mon, 14 Jun 2021 19:15:56 +0200 Subject: [PATCH] Dart object API (#6682) * dart test scripts - generate with `--gen-object-api` * Dart object API, pack and unpack methods (WIP) * Dart flatc - extract Builder code to separate functions to reuse it in Pack() * Dart flatc - use builder field-building implementation in pack() * Dart flatc - add pack() as an intance method of the "T" class * Dart object API - make inner fields unpacked as well * Dart object API - use pack() when collecting field offsets * Dart object API - use packOnce() for fields that are structs or vectors of structs * Dart object API - remove obsolete union support TODO * Dart object API - minor review changes, test and fixes * Dart object API - revert packOnce() - not supported by other object API implementations * Dart object API - update docs * update dart generated code in tests/ to fix CI failure on ./scripts/check-generated-code.sh * Dart flatc - fix compilation for old MSVC and c++0x --- dart/test/flat_buffers_test.dart | 66 ++ ...nster_test_my_game.example2_generated.dart | 21 + ...onster_test_my_game.example_generated.dart | 683 +++++++++++++++++- dart/test/monster_test_my_game_generated.dart | 21 + docs/source/DartUsage.md | 25 +- docs/source/Support.md | 2 +- src/idl_gen_dart.cpp | 283 ++++++-- tests/DartTest.sh | 2 +- tests/generate_code.sh | 2 +- tests/monster_extra_my_game_generated.dart | 74 ++ ...nster_test_my_game.example2_generated.dart | 21 + ...onster_test_my_game.example_generated.dart | 683 +++++++++++++++++- tests/monster_test_my_game_generated.dart | 21 + ...st1_namespace_a.namespace_b_generated.dart | 59 ++ ...namespace_test2_namespace_a_generated.dart | 83 +++ ...namespace_test2_namespace_c_generated.dart | 38 + 16 files changed, 2002 insertions(+), 82 deletions(-) diff --git a/dart/test/flat_buffers_test.dart b/dart/test/flat_buffers_test.dart index f4e084aae..0e8c7572e 100644 --- a/dart/test/flat_buffers_test.dart +++ b/dart/test/flat_buffers_test.dart @@ -12,10 +12,12 @@ import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import './monster_test_my_game.example_generated.dart' as example; +import './monster_test_my_game.example2_generated.dart' as example2; main() { defineReflectiveSuite(() { defineReflectiveTests(BuilderTest); + defineReflectiveTests(ObjectAPITest); defineReflectiveTests(CheckOtherLangaugesData); defineReflectiveTests(GeneratorTest); }); @@ -667,6 +669,70 @@ class BuilderTest { } } +@reflectiveTest +class ObjectAPITest { + void test_tableStat() { + final object1 = example.StatT(count: 3, id: "foo", val: 4); + final fbb = Builder(); + final data = fbb.finish(object1.pack(fbb)); + final object2 = example.Stat(data).unpack(); + expect(object2.count, object1.count); + expect(object2.id, object1.id); + expect(object2.val, object1.val); + expect(object2.toString(), object1.toString()); + } + + void test_tableMonster() { + final monster = example.MonsterT() + ..pos = example.Vec3T( + x: 1, + y: 2, + z: 3, + test1: 4.0, + test2: example.Color.Red, + test3: example.TestT(a: 1, b: 2)) + ..mana = 2 + ..name = 'Monstrous' + ..inventory = [24, 42] + ..color = example.Color.Green + // TODO be smarter for unions and automatically set the `type` field? + ..testType = example.AnyTypeId.MyGame_Example2_Monster + ..test = example2.MonsterT() + ..test4 = [example.TestT(a: 3, b: 4), example.TestT(a: 5, b: 6)] + ..testarrayofstring = ["foo", "bar"] + ..testarrayoftables = [example.MonsterT(name: 'Oof')] + ..enemy = example.MonsterT(name: 'Enemy') + ..testarrayofbools = [false, true, false] + ..testf = 42.24 + ..testarrayofsortedstruct = [ + example.AbilityT(id: 1, distance: 5), + example.AbilityT(id: 3, distance: 7) + ] + ..vectorOfLongs = [5, 6, 7] + ..vectorOfDoubles = [8.9, 9.0, 10.1, 11.2] + ..anyAmbiguousType = example.AnyAmbiguousAliasesTypeId.M2 + ..anyAmbiguous = null + ..vectorOfEnums = [example.Color.Blue, example.Color.Green] + ..signedEnum = example.Race.None; + + final fbBuilder = Builder(); + final offset = monster.pack(fbBuilder); + expect(offset, isNonZero); + final data = fbBuilder.finish(offset); + + // TODO currently broken because of struct builder issue, see #6688 + // final monster2 = example.Monster(data); // Monster (reader) + // expect( + // // map Monster => MonsterT, Vec3 => Vec3T, ... + // monster2.toString().replaceAllMapped( + // RegExp('([a-zA-z0-9]+){'), (match) => match.group(1) + 'T{'), + // monster.toString()); + // + // final monster3 = monster2.unpack(); // MonsterT + // expect(monster3.toString(), monster.toString()); + } +} + class StringListWrapperImpl { final BufferContext bp; final int offset; diff --git a/dart/test/monster_test_my_game.example2_generated.dart b/dart/test/monster_test_my_game.example2_generated.dart index eed14bc2c..d1c6a03ab 100644 --- a/dart/test/monster_test_my_game.example2_generated.dart +++ b/dart/test/monster_test_my_game.example2_generated.dart @@ -26,6 +26,27 @@ class Monster { String toString() { return 'Monster{}'; } + + MonsterT unpack() => MonsterT(); + + static int pack(fb.Builder fbBuilder, MonsterT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class MonsterT { + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'MonsterT{}'; + } } class _MonsterReader extends fb.TableReader { diff --git a/dart/test/monster_test_my_game.example_generated.dart b/dart/test/monster_test_my_game.example_generated.dart index 4a5f5c999..75302f9fe 100644 --- a/dart/test/monster_test_my_game.example_generated.dart +++ b/dart/test/monster_test_my_game.example_generated.dart @@ -232,6 +232,38 @@ class Test { String toString() { return 'Test{a: $a, b: $b}'; } + + TestT unpack() => TestT( + a: a, + b: b); + + static int pack(fb.Builder fbBuilder, TestT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TestT { + int a; + int b; + + TestT({ + this.a, + this.b}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.pad(1); + fbBuilder.putInt8(b); + fbBuilder.putInt16(a); + return fbBuilder.offset; + } + + @override + String toString() { + return 'TestT{a: $a, b: $b}'; + } } class _TestReader extends fb.StructReader { @@ -310,6 +342,34 @@ class TestSimpleTableWithEnum { String toString() { return 'TestSimpleTableWithEnum{color: $color}'; } + + TestSimpleTableWithEnumT unpack() => TestSimpleTableWithEnumT( + color: color); + + static int pack(fb.Builder fbBuilder, TestSimpleTableWithEnumT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TestSimpleTableWithEnumT { + Color color; + + TestSimpleTableWithEnumT({ + this.color}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + fbBuilder.addUint8(0, color?.value); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'TestSimpleTableWithEnumT{color: $color}'; + } } class _TestSimpleTableWithEnumReader extends fb.TableReader { @@ -387,6 +447,56 @@ class Vec3 { String toString() { return 'Vec3{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}'; } + + Vec3T unpack() => Vec3T( + x: x, + y: y, + z: z, + test1: test1, + test2: test2, + test3: test3?.unpack()); + + static int pack(fb.Builder fbBuilder, Vec3T object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class Vec3T { + double x; + double y; + double z; + double test1; + Color test2; + TestT test3; + + Vec3T({ + this.x, + this.y, + this.z, + this.test1, + this.test2, + this.test3}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.pad(2); + test3.pack(fbBuilder); + fbBuilder.pad(1); + fbBuilder.putUint8(test2?.value); + fbBuilder.putFloat64(test1); + fbBuilder.pad(4); + fbBuilder.putFloat32(z); + fbBuilder.putFloat32(y); + fbBuilder.putFloat32(x); + return fbBuilder.offset; + } + + @override + String toString() { + return 'Vec3T{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}'; + } } class _Vec3Reader extends fb.StructReader { @@ -486,6 +596,37 @@ class Ability { String toString() { return 'Ability{id: $id, distance: $distance}'; } + + AbilityT unpack() => AbilityT( + id: id, + distance: distance); + + static int pack(fb.Builder fbBuilder, AbilityT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class AbilityT { + int id; + int distance; + + AbilityT({ + this.id, + this.distance}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.putUint32(distance); + fbBuilder.putUint32(id); + return fbBuilder.offset; + } + + @override + String toString() { + return 'AbilityT{id: $id, distance: $distance}'; + } } class _AbilityReader extends fb.StructReader { @@ -560,6 +701,41 @@ class StructOfStructs { String toString() { return 'StructOfStructs{a: $a, b: $b, c: $c}'; } + + StructOfStructsT unpack() => StructOfStructsT( + a: a?.unpack(), + b: b?.unpack(), + c: c?.unpack()); + + static int pack(fb.Builder fbBuilder, StructOfStructsT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class StructOfStructsT { + AbilityT a; + TestT b; + AbilityT c; + + StructOfStructsT({ + this.a, + this.b, + this.c}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + c.pack(fbBuilder); + b.pack(fbBuilder); + a.pack(fbBuilder); + return fbBuilder.offset; + } + + @override + String toString() { + return 'StructOfStructsT{a: $a, b: $b, c: $c}'; + } } class _StructOfStructsReader extends fb.StructReader { @@ -643,6 +819,45 @@ class Stat { String toString() { return 'Stat{id: $id, val: $val, count: $count}'; } + + StatT unpack() => StatT( + id: id, + val: val, + count: count); + + static int pack(fb.Builder fbBuilder, StatT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class StatT { + String id; + int val; + int count; + + StatT({ + this.id, + this.val, + this.count}); + + int pack(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(); + } + + @override + String toString() { + return 'StatT{id: $id, val: $val, count: $count}'; + } } class _StatReader extends fb.TableReader { @@ -738,6 +953,34 @@ class Referrable { String toString() { return 'Referrable{id: $id}'; } + + ReferrableT unpack() => ReferrableT( + id: id); + + static int pack(fb.Builder fbBuilder, ReferrableT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class ReferrableT { + int id; + + ReferrableT({ + this.id}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + fbBuilder.addUint64(0, id); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'ReferrableT{id: $id}'; + } } class _ReferrableReader extends fb.TableReader { @@ -887,6 +1130,362 @@ class Monster { 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, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum, testrequirednestedflatbuffer: $testrequirednestedflatbuffer, scalarKeySortedTables: $scalarKeySortedTables}'; } + + MonsterT unpack() => MonsterT( + pos: pos?.unpack(), + mana: mana, + hp: hp, + name: name, + inventory: inventory, + color: color, + testType: testType, + test: test, + test4: test4?.map((e) => e.unpack())?.toList(), + testarrayofstring: testarrayofstring, + testarrayoftables: testarrayoftables?.map((e) => e.unpack())?.toList(), + enemy: enemy?.unpack(), + testnestedflatbuffer: testnestedflatbuffer, + testempty: testempty?.unpack(), + 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?.map((e) => e.unpack())?.toList(), + flex: flex, + test5: test5?.map((e) => e.unpack())?.toList(), + vectorOfLongs: vectorOfLongs, + vectorOfDoubles: vectorOfDoubles, + parentNamespaceTest: parentNamespaceTest?.unpack(), + vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack())?.toList(), + singleWeakReference: singleWeakReference, + vectorOfWeakReferences: vectorOfWeakReferences, + vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack())?.toList(), + coOwningReference: coOwningReference, + vectorOfCoOwningReferences: vectorOfCoOwningReferences, + nonOwningReference: nonOwningReference, + vectorOfNonOwningReferences: vectorOfNonOwningReferences, + anyUniqueType: anyUniqueType, + anyUnique: anyUnique, + anyAmbiguousType: anyAmbiguousType, + anyAmbiguous: anyAmbiguous, + vectorOfEnums: vectorOfEnums, + signedEnum: signedEnum, + testrequirednestedflatbuffer: testrequirednestedflatbuffer, + scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack())?.toList()); + + static int pack(fb.Builder fbBuilder, MonsterT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +/// an example documentation comment: "monster object" +class MonsterT { + Vec3T pos; + int mana; + int hp; + String name; + List inventory; + Color color; + AnyTypeId testType; + dynamic test; + List test4; + List testarrayofstring; + /// an example documentation comment: this will end up in the generated code + /// multiline too + List testarrayoftables; + MonsterT enemy; + List testnestedflatbuffer; + StatT testempty; + bool testbool; + int testhashs32Fnv1; + int testhashu32Fnv1; + int testhashs64Fnv1; + int testhashu64Fnv1; + int testhashs32Fnv1a; + int testhashu32Fnv1a; + int testhashs64Fnv1a; + int testhashu64Fnv1a; + List testarrayofbools; + double testf; + double testf2; + double testf3; + List testarrayofstring2; + List testarrayofsortedstruct; + List flex; + List test5; + List vectorOfLongs; + List vectorOfDoubles; + my_game.InParentNamespaceT parentNamespaceTest; + List vectorOfReferrables; + int singleWeakReference; + List vectorOfWeakReferences; + List vectorOfStrongReferrables; + int coOwningReference; + List vectorOfCoOwningReferences; + int nonOwningReference; + List vectorOfNonOwningReferences; + AnyUniqueAliasesTypeId anyUniqueType; + dynamic anyUnique; + AnyAmbiguousAliasesTypeId anyAmbiguousType; + dynamic anyAmbiguous; + List vectorOfEnums; + Race signedEnum; + List testrequirednestedflatbuffer; + List scalarKeySortedTables; + + MonsterT({ + this.pos, + this.mana, + this.hp, + this.name, + this.inventory, + this.color, + this.testType, + this.test, + this.test4, + this.testarrayofstring, + this.testarrayoftables, + this.enemy, + this.testnestedflatbuffer, + this.testempty, + this.testbool, + this.testhashs32Fnv1, + this.testhashu32Fnv1, + this.testhashs64Fnv1, + this.testhashu64Fnv1, + this.testhashs32Fnv1a, + this.testhashu32Fnv1a, + this.testhashs64Fnv1a, + this.testhashu64Fnv1a, + this.testarrayofbools, + this.testf, + this.testf2, + this.testf3, + this.testarrayofstring2, + this.testarrayofsortedstruct, + this.flex, + this.test5, + this.vectorOfLongs, + this.vectorOfDoubles, + this.parentNamespaceTest, + this.vectorOfReferrables, + this.singleWeakReference, + this.vectorOfWeakReferences, + this.vectorOfStrongReferrables, + this.coOwningReference, + this.vectorOfCoOwningReferences, + this.nonOwningReference, + this.vectorOfNonOwningReferences, + this.anyUniqueType, + this.anyUnique, + this.anyAmbiguousType, + this.anyAmbiguous, + this.vectorOfEnums, + this.signedEnum, + this.testrequirednestedflatbuffer, + this.scalarKeySortedTables}); + + int pack(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?.pack(fbBuilder); + int test4Offset = null; + if (test4?.isNotEmpty == true) { + test4.forEach((e) => e.pack(fbBuilder)); + test4Offset = fbBuilder.endStructVector(test4.length); + } + 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.pack(fbBuilder)).toList()) + : null; + final int enemyOffset = enemy?.pack(fbBuilder); + final int testnestedflatbufferOffset = testnestedflatbuffer?.isNotEmpty == true + ? fbBuilder.writeListUint8(testnestedflatbuffer) + : null; + final int testemptyOffset = testempty?.pack(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; + int testarrayofsortedstructOffset = null; + if (testarrayofsortedstruct?.isNotEmpty == true) { + testarrayofsortedstruct.forEach((e) => e.pack(fbBuilder)); + testarrayofsortedstructOffset = fbBuilder.endStructVector(testarrayofsortedstruct.length); + } + final int flexOffset = flex?.isNotEmpty == true + ? fbBuilder.writeListUint8(flex) + : null; + int test5Offset = null; + if (test5?.isNotEmpty == true) { + test5.forEach((e) => e.pack(fbBuilder)); + test5Offset = fbBuilder.endStructVector(test5.length); + } + final int vectorOfLongsOffset = vectorOfLongs?.isNotEmpty == true + ? fbBuilder.writeListInt64(vectorOfLongs) + : null; + final int vectorOfDoublesOffset = vectorOfDoubles?.isNotEmpty == true + ? fbBuilder.writeListFloat64(vectorOfDoubles) + : null; + final int parentNamespaceTestOffset = parentNamespaceTest?.pack(fbBuilder); + final int vectorOfReferrablesOffset = vectorOfReferrables?.isNotEmpty == true + ? fbBuilder.writeList(vectorOfReferrables.map((b) => b.pack(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.pack(fbBuilder)).toList()) + : null; + final int vectorOfCoOwningReferencesOffset = vectorOfCoOwningReferences?.isNotEmpty == true + ? fbBuilder.writeListUint64(vectorOfCoOwningReferences) + : null; + final int vectorOfNonOwningReferencesOffset = vectorOfNonOwningReferences?.isNotEmpty == true + ? fbBuilder.writeListUint64(vectorOfNonOwningReferences) + : null; + final int anyUniqueOffset = anyUnique?.pack(fbBuilder); + final int anyAmbiguousOffset = anyAmbiguous?.pack(fbBuilder); + final int vectorOfEnumsOffset = vectorOfEnums?.isNotEmpty == true + ? fbBuilder.writeListUint8(vectorOfEnums.map((f) => f.value).toList()) + : null; + final int testrequirednestedflatbufferOffset = testrequirednestedflatbuffer?.isNotEmpty == true + ? fbBuilder.writeListUint8(testrequirednestedflatbuffer) + : null; + final int scalarKeySortedTablesOffset = scalarKeySortedTables?.isNotEmpty == true + ? fbBuilder.writeList(scalarKeySortedTables.map((b) => b.pack(fbBuilder)).toList()) + : null; + + fbBuilder.startTable(); + if (pos != null) { + fbBuilder.addStruct(0, pos.pack(fbBuilder)); + } + fbBuilder.addInt16(1, mana); + fbBuilder.addInt16(2, hp); + if (nameOffset != null) { + fbBuilder.addOffset(3, nameOffset); + } + if (inventoryOffset != null) { + fbBuilder.addOffset(5, inventoryOffset); + } + fbBuilder.addUint8(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); + } + fbBuilder.addUint8(43, anyUniqueType?.value); + if (anyUniqueOffset != null) { + fbBuilder.addOffset(44, anyUniqueOffset); + } + fbBuilder.addUint8(45, anyAmbiguousType?.value); + if (anyAmbiguousOffset != null) { + fbBuilder.addOffset(46, anyAmbiguousOffset); + } + if (vectorOfEnumsOffset != null) { + fbBuilder.addOffset(47, vectorOfEnumsOffset); + } + fbBuilder.addInt8(48, signedEnum?.value); + if (testrequirednestedflatbufferOffset != null) { + fbBuilder.addOffset(49, testrequirednestedflatbufferOffset); + } + if (scalarKeySortedTablesOffset != null) { + fbBuilder.addOffset(50, scalarKeySortedTablesOffset); + } + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'MonsterT{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, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum, testrequirednestedflatbuffer: $testrequirednestedflatbuffer, scalarKeySortedTables: $scalarKeySortedTables}'; + } } class _MonsterReader extends fb.TableReader { @@ -1333,7 +1932,7 @@ class MonsterObjectBuilder extends fb.ObjectBuilder { final int anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder); final int anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder); final int vectorOfEnumsOffset = _vectorOfEnums?.isNotEmpty == true - ? fbBuilder.writeListUint8(_vectorOfEnums.map((f) => f.value)) + ? fbBuilder.writeListUint8(_vectorOfEnums.map((f) => f.value).toList()) : null; final int testrequirednestedflatbufferOffset = _testrequirednestedflatbuffer?.isNotEmpty == true ? fbBuilder.writeListUint8(_testrequirednestedflatbuffer) @@ -1489,6 +2088,88 @@ class TypeAliases { 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}'; } + + TypeAliasesT unpack() => TypeAliasesT( + i8: i8, + u8: u8, + i16: i16, + u16: u16, + i32: i32, + u32: u32, + i64: i64, + u64: u64, + f32: f32, + f64: f64, + v8: v8, + vf64: vf64); + + static int pack(fb.Builder fbBuilder, TypeAliasesT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TypeAliasesT { + int i8; + int u8; + int i16; + int u16; + int i32; + int u32; + int i64; + int u64; + double f32; + double f64; + List v8; + List vf64; + + TypeAliasesT({ + this.i8, + this.u8, + this.i16, + this.u16, + this.i32, + this.u32, + this.i64, + this.u64, + this.f32, + this.f64, + this.v8, + this.vf64}); + + int pack(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(); + } + + @override + String toString() { + return 'TypeAliasesT{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 { diff --git a/dart/test/monster_test_my_game_generated.dart b/dart/test/monster_test_my_game_generated.dart index abd538c49..d53550d13 100644 --- a/dart/test/monster_test_my_game_generated.dart +++ b/dart/test/monster_test_my_game_generated.dart @@ -26,6 +26,27 @@ class InParentNamespace { String toString() { return 'InParentNamespace{}'; } + + InParentNamespaceT unpack() => InParentNamespaceT(); + + static int pack(fb.Builder fbBuilder, InParentNamespaceT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class InParentNamespaceT { + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'InParentNamespaceT{}'; + } } class _InParentNamespaceReader extends fb.TableReader { diff --git a/docs/source/DartUsage.md b/docs/source/DartUsage.md index 6670cc59d..515a64411 100644 --- a/docs/source/DartUsage.md +++ b/docs/source/DartUsage.md @@ -105,4 +105,27 @@ 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). -
+## Object based API + +FlatBuffers is all about memory efficiency, which is why its base API is written +around using as little as possible of it. This does make the API clumsier +(requiring pre-order construction of all data, and making mutation harder). + +For times when efficiency is less important a more convenient object based API +can be used (through `--gen-object-api`) that is able to unpack & pack a FlatBuffer +into objects and lists, allowing for convenient construction, access and mutation. + +To use: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart} + // Deserialize from buffer into object. + MonsterT monster = Monster(flatbuffer).unpack(); + + // Update object directly like a Dart class instance. + print(monster.Name); + monster.Name = "Bob"; // Change the name. + + // Serialize into new flatbuffer. + final fbb = Builder(); + fbb.Finish(monster.pack(fbb)); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/Support.md b/docs/source/Support.md index 4cac209b1..3436a6fbd 100644 --- a/docs/source/Support.md +++ b/docs/source/Support.md @@ -25,7 +25,7 @@ JSON parsing | Yes | No | No | No | No | No Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No | Yes Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No | No Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No | No -Native Object API | Yes | No | Yes | Yes | Yes | Yes | Yes | No | No | No | No | No | No +Native Object API | Yes | No | Yes | Yes | Yes | Yes | Yes | No | No | Yes | No | No | No Optional Scalars | Yes | Yes | Yes | No | No | Yes | Yes | Yes | No | No | Yes | Yes | Yes Flexbuffers | Yes | Yes | ? | ? | ? | ? | ? | ? | ? | ? | ? | Yes | ? Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes | Yes diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp index 56c4a8255..92a8bd51b 100644 --- a/src/idl_gen_dart.cpp +++ b/src/idl_gen_dart.cpp @@ -350,7 +350,8 @@ class DartGenerator : public BaseGenerator { } std::string GenDartTypeName(const Type &type, Namespace *current_namespace, - const FieldDef &def, bool addBuilder = false) { + const FieldDef &def, + std::string struct_type_suffix = "") { if (type.enum_def) { if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) { return type.enum_def->name + "TypeId"; @@ -375,13 +376,12 @@ class DartGenerator : public BaseGenerator { 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); + return MaybeWrapNamespace(type.struct_def->name + struct_type_suffix, + current_namespace, def); case BASE_TYPE_VECTOR: return "List<" + GenDartTypeName(type.VectorType(), current_namespace, def, - addBuilder) + + struct_type_suffix) + ">"; default: assert(0); return "dynamic"; } @@ -430,6 +430,8 @@ class DartGenerator : public BaseGenerator { code += "class " + object_name + " {\n"; code += " " + object_name + "._(this._bc, this._bcOffset);\n"; + // TODO why not generate the (reader) factory constructor for "structs"? + // Currently only genreated for "tables" but should work for both... if (!struct_def.fixed) { code += " factory " + object_name + "(List bytes) {\n"; code += " " + _kFb + ".BufferContext rootRef = new " + _kFb + @@ -456,8 +458,23 @@ class DartGenerator : public BaseGenerator { GenImplementationGetters(struct_def, non_deprecated_fields, &code); + if (parser_.opts.generate_object_based_api) { + code += + "\n" + GenStructObjectAPIUnpack(struct_def, non_deprecated_fields); + + code += "\n static int pack(fb.Builder fbBuilder, " + struct_def.name + + "T object) {\n"; + code += " if (object == null) return 0;\n"; + code += " return object.pack(fbBuilder);\n"; + code += " }\n"; + } + code += "}\n\n"; + if (parser_.opts.generate_object_based_api) { + code += GenStructObjectAPI(struct_def, non_deprecated_fields); + } + GenReader(struct_def, &reader_name, &reader_code); GenBuilder(struct_def, non_deprecated_fields, &builder_name, &builder_code); GenObjectBuilder(struct_def, non_deprecated_fields, &object_builder_name, @@ -469,6 +486,87 @@ class DartGenerator : public BaseGenerator { (*namespace_code)[object_namespace] += code; } + // Generate an accessor struct with constructor for a flatbuffers struct. + std::string GenStructObjectAPI( + const StructDef &struct_def, + const std::vector> &non_deprecated_fields) { + std::string code; + GenDocComment(struct_def.doc_comment, &code, ""); + + std::string class_name = struct_def.name + "T"; + code += "class " + class_name + " {\n"; + + std::string constructor_args; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + const FieldDef &field = *it->second; + + std::string field_name = MakeCamel(field.name, false); + std::string type_name = GenDartTypeName( + field.value.type, struct_def.defined_namespace, field, "T"); + + GenDocComment(field.doc_comment, &code, "", " "); + code += " " + type_name + " " + field_name + ";\n"; + + if (!constructor_args.empty()) constructor_args += ",\n"; + // TODO for null safety: add `required` if struct_def.fixed + constructor_args += " this." + field_name; + } + + if (!constructor_args.empty()) { + code += "\n " + class_name + "({\n" + constructor_args + "});\n\n"; + } + + code += GenStructObjectAPIPack(struct_def, non_deprecated_fields); + code += "\n"; + code += GenToString(class_name, non_deprecated_fields); + + code += "}\n\n"; + return code; + } + + // Generate function `StructNameT unpack()` + std::string GenStructObjectAPIUnpack( + const StructDef &struct_def, + const std::vector> &non_deprecated_fields) { + std::string constructor_args; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + const FieldDef &field = *it->second; + + std::string field_name = MakeCamel(field.name, false); + if (!constructor_args.empty()) constructor_args += ",\n"; + constructor_args += " " + field_name + ": " + field_name; + + const Type &type = field.value.type; + if (type.base_type == BASE_TYPE_STRUCT) { + constructor_args += "?.unpack()"; + } else if (type.base_type == BASE_TYPE_VECTOR && + type.VectorType().base_type == BASE_TYPE_STRUCT) { + constructor_args += "?.map((e) => e.unpack())?.toList()"; + } + } + + std::string class_name = struct_def.name + "T"; + std::string code = " " + class_name + " unpack() => " + class_name + "("; + if (!constructor_args.empty()) code += "\n" + constructor_args; + code += ");\n"; + return code; + } + + // Generate function `StructNameT pack()` + std::string GenStructObjectAPIPack( + const StructDef &struct_def, + const std::vector> &non_deprecated_fields) { + std::string code; + + code += " int pack(fb.Builder fbBuilder) {\n"; + code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields, + false, true); + code += " }\n"; + return code; + } + std::string NamespaceAliasFromUnionType(Namespace *root_namespace, const Type &type) { const std::vector qualified_name_parts = @@ -512,7 +610,7 @@ class DartGenerator : public BaseGenerator { std::string field_name = MakeCamel(field.name, false); std::string type_name = GenDartTypeName( - field.value.type, struct_def.defined_namespace, field, false); + field.value.type, struct_def.defined_namespace, field); GenDocComment(field.doc_comment, &code, "", " "); @@ -587,10 +685,16 @@ class DartGenerator : public BaseGenerator { } code += "\n"; + code += GenToString(struct_def.name, non_deprecated_fields); + } + std::string GenToString( + const std::string &object_name, + const std::vector> &non_deprecated_fields) { + std::string code; code += " @override\n"; code += " String toString() {\n"; - code += " return '" + struct_def.name + "{"; + code += " return '" + object_name + "{"; for (auto it = non_deprecated_fields.begin(); it != non_deprecated_fields.end(); ++it) { auto pair = *it; @@ -601,6 +705,7 @@ class DartGenerator : public BaseGenerator { } code += "}';\n"; code += " }\n"; + return code; } void GenReader(const StructDef &struct_def, std::string *reader_name_ptr, @@ -756,7 +861,7 @@ class DartGenerator : public BaseGenerator { code += " final " + GenDartTypeName(field.value.type, struct_def.defined_namespace, - field, true) + + field, "ObjectBuilder") + " _" + MakeCamel(field.name, false) + ";\n"; } code += "\n"; @@ -771,7 +876,7 @@ class DartGenerator : public BaseGenerator { code += " " + GenDartTypeName(field.value.type, struct_def.defined_namespace, - field, true) + + field, "ObjectBuilder") + " " + MakeCamel(field.name, false) + ",\n"; } code += " })\n"; @@ -797,56 +902,7 @@ class DartGenerator : public BaseGenerator { code += " @override\n"; code += " int finish(\n"; code += " " + _kFb + ".Builder fbBuilder) {\n"; - code += " assert(fbBuilder != null);\n"; - - for (auto it = non_deprecated_fields.begin(); - it != non_deprecated_fields.end(); ++it) { - auto pair = *it; - auto &field = *pair.second; - - if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) - continue; - - code += " final int " + MakeCamel(field.name, false) + "Offset"; - if (IsVector(field.value.type)) { - 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 (IsString(field.value.type)) { - code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) + - ");\n"; - } else { - code += " = _" + MakeCamel(field.name, false) + - "?.getOrCreateOffset(fbBuilder);\n"; - } - } - - code += "\n"; - if (struct_def.fixed) { - StructObjectBuilderBody(non_deprecated_fields, code_ptr); - } else { - TableObjectBuilderBody(non_deprecated_fields, code_ptr); - } + code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields); code += " }\n\n"; code += " /// Convenience method to serialize to byte list.\n"; @@ -860,10 +916,84 @@ class DartGenerator : public BaseGenerator { code += "}\n"; } - void StructObjectBuilderBody( - std::vector> non_deprecated_fields, - std::string *code_ptr, bool prependUnderscore = true) { - auto &code = *code_ptr; + std::string GenObjectBuilderImplementation( + const StructDef &struct_def, + const std::vector> &non_deprecated_fields, + bool prependUnderscore = true, bool pack = false) { + std::string code = " assert(fbBuilder != null);\n"; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + const FieldDef &field = *it->second; + + if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) + continue; + + std::string offset_name = MakeCamel(field.name, false) + "Offset"; + std::string field_name = + (prependUnderscore ? "_" : "") + MakeCamel(field.name, false); + + // custom handling for fixed-sized struct in pack() + if (pack && IsVector(field.value.type) && + field.value.type.VectorType().base_type == BASE_TYPE_STRUCT && + field.value.type.struct_def->fixed) { + code += " int " + offset_name + " = null;\n"; + code += " if (" + field_name + "?.isNotEmpty == true) {\n"; + code += " " + field_name + ".forEach((e) => e.pack(fbBuilder));\n"; + code += " " + MakeCamel(field.name, false) + + "Offset = fbBuilder.endStructVector(" + field_name + + ".length);\n"; + code += " }\n"; + continue; + } + + code += " final int " + offset_name; + if (IsVector(field.value.type)) { + code += " = " + field_name + "?.isNotEmpty == true\n"; + code += " ? fbBuilder.writeList"; + switch (field.value.type.VectorType().base_type) { + case BASE_TYPE_STRING: + code += "(" + field_name + + ".map((b) => fbBuilder.writeString(b)).toList())"; + break; + case BASE_TYPE_STRUCT: + if (field.value.type.struct_def->fixed) { + code += "OfStructs(" + field_name + ")"; + } else { + code += "(" + field_name + ".map((b) => b." + + (pack ? "pack" : "getOrCreateOffset") + + "(fbBuilder)).toList())"; + } + break; + default: + code += GenType(field.value.type.VectorType()) + "(" + field_name; + if (field.value.type.enum_def) { + code += ".map((f) => f.value).toList()"; + } + code += ")"; + } + code += "\n : null;\n"; + } else if (IsString(field.value.type)) { + code += " = fbBuilder.writeString(" + field_name + ");\n"; + } else { + code += " = " + field_name + "?." + + (pack ? "pack" : "getOrCreateOffset") + "(fbBuilder);\n"; + } + } + code += "\n"; + if (struct_def.fixed) { + code += StructObjectBuilderBody(non_deprecated_fields, prependUnderscore, + pack); + } else { + code += TableObjectBuilderBody(non_deprecated_fields, prependUnderscore, + pack); + } + return code; + } + + std::string StructObjectBuilderBody( + const std::vector> &non_deprecated_fields, + bool prependUnderscore = true, bool pack = false) { + std::string code; for (auto it = non_deprecated_fields.rbegin(); it != non_deprecated_fields.rend(); ++it) { @@ -877,7 +1007,7 @@ class DartGenerator : public BaseGenerator { if (IsStruct(field.value.type)) { code += " "; if (prependUnderscore) { code += "_"; } - code += field.name + ".finish(fbBuilder);\n"; + code += field.name + (pack ? ".pack" : ".finish") + "(fbBuilder);\n"; } else { code += " fbBuilder.put" + GenType(field.value.type) + "("; if (prependUnderscore) { code += "_"; } @@ -888,12 +1018,13 @@ class DartGenerator : public BaseGenerator { } code += " return fbBuilder.offset;\n"; + return code; } - void TableObjectBuilderBody( - std::vector> non_deprecated_fields, - std::string *code_ptr, bool prependUnderscore = true) { - std::string &code = *code_ptr; + std::string TableObjectBuilderBody( + const std::vector> &non_deprecated_fields, + bool prependUnderscore = true, bool pack = false) { + std::string code; code += " fbBuilder.startTable();\n"; for (auto it = non_deprecated_fields.begin(); @@ -902,19 +1033,18 @@ class DartGenerator : public BaseGenerator { auto &field = *pair.second; auto offset = pair.first; + std::string field_name = + (prependUnderscore ? "_" : "") + MakeCamel(field.name, false); + if (IsScalar(field.value.type.base_type)) { code += " fbBuilder.add" + GenType(field.value.type) + "(" + - NumToString(offset) + ", "; - if (prependUnderscore) { code += "_"; } - code += MakeCamel(field.name, false); + NumToString(offset) + ", " + field_name; 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 += " if (" + field_name + " != null) {\n"; + code += " fbBuilder.addStruct(" + NumToString(offset) + ", " + + field_name + (pack ? ".pack" : ".finish") + "(fbBuilder));\n"; code += " }\n"; } else { code += @@ -925,6 +1055,7 @@ class DartGenerator : public BaseGenerator { } } code += " return fbBuilder.endTable();\n"; + return code; } }; } // namespace dart diff --git a/tests/DartTest.sh b/tests/DartTest.sh index 0aedb637e..e33fd4406 100755 --- a/tests/DartTest.sh +++ b/tests/DartTest.sh @@ -19,7 +19,7 @@ pushd "$(dirname $0)" >/dev/null 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 # distribute them and more people can more easily run the dart tests -../flatc --dart -I include_test -o ../dart/test monster_test.fbs +../flatc --dart --gen-object-api -I include_test -o ../dart/test monster_test.fbs cp monsterdata_test.mon ../dart/test cd ../dart diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 12add89d1..cefe428f3 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -57,7 +57,7 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_TS_FLAGS -o namespace_te ../flatc --cpp --java --kotlin --csharp --python $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS monster_extra.fbs monsterdata_extra.json ../flatc --cpp --java --csharp --jsonschema --rust $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS --scoped-enums arrays_test.fbs ../flatc --python $TEST_BASE_FLAGS arrays_test.fbs -../flatc --dart monster_extra.fbs +../flatc --dart --gen-object-api monster_extra.fbs # Generate optional scalar code for tests. ../flatc --java --kotlin --lobster --ts optional_scalars.fbs diff --git a/tests/monster_extra_my_game_generated.dart b/tests/monster_extra_my_game_generated.dart index 676641de6..11bf3af8a 100644 --- a/tests/monster_extra_my_game_generated.dart +++ b/tests/monster_extra_my_game_generated.dart @@ -34,6 +34,80 @@ class MonsterExtra { String toString() { return 'MonsterExtra{d0: $d0, d1: $d1, d2: $d2, d3: $d3, f0: $f0, f1: $f1, f2: $f2, f3: $f3, dvec: $dvec, fvec: $fvec}'; } + + MonsterExtraT unpack() => MonsterExtraT( + d0: d0, + d1: d1, + d2: d2, + d3: d3, + f0: f0, + f1: f1, + f2: f2, + f3: f3, + dvec: dvec, + fvec: fvec); + + static int pack(fb.Builder fbBuilder, MonsterExtraT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class MonsterExtraT { + double d0; + double d1; + double d2; + double d3; + double f0; + double f1; + double f2; + double f3; + List dvec; + List fvec; + + MonsterExtraT({ + this.d0, + this.d1, + this.d2, + this.d3, + this.f0, + this.f1, + this.f2, + this.f3, + this.dvec, + this.fvec}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + final int dvecOffset = dvec?.isNotEmpty == true + ? fbBuilder.writeListFloat64(dvec) + : null; + final int fvecOffset = fvec?.isNotEmpty == true + ? fbBuilder.writeListFloat32(fvec) + : null; + + fbBuilder.startTable(); + fbBuilder.addFloat64(0, d0); + fbBuilder.addFloat64(1, d1); + fbBuilder.addFloat64(2, d2); + fbBuilder.addFloat64(3, d3); + fbBuilder.addFloat32(4, f0); + fbBuilder.addFloat32(5, f1); + fbBuilder.addFloat32(6, f2); + fbBuilder.addFloat32(7, f3); + if (dvecOffset != null) { + fbBuilder.addOffset(8, dvecOffset); + } + if (fvecOffset != null) { + fbBuilder.addOffset(9, fvecOffset); + } + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'MonsterExtraT{d0: $d0, d1: $d1, d2: $d2, d3: $d3, f0: $f0, f1: $f1, f2: $f2, f3: $f3, dvec: $dvec, fvec: $fvec}'; + } } class _MonsterExtraReader extends fb.TableReader { diff --git a/tests/monster_test_my_game.example2_generated.dart b/tests/monster_test_my_game.example2_generated.dart index eed14bc2c..d1c6a03ab 100644 --- a/tests/monster_test_my_game.example2_generated.dart +++ b/tests/monster_test_my_game.example2_generated.dart @@ -26,6 +26,27 @@ class Monster { String toString() { return 'Monster{}'; } + + MonsterT unpack() => MonsterT(); + + static int pack(fb.Builder fbBuilder, MonsterT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class MonsterT { + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'MonsterT{}'; + } } class _MonsterReader extends fb.TableReader { diff --git a/tests/monster_test_my_game.example_generated.dart b/tests/monster_test_my_game.example_generated.dart index 4a5f5c999..75302f9fe 100644 --- a/tests/monster_test_my_game.example_generated.dart +++ b/tests/monster_test_my_game.example_generated.dart @@ -232,6 +232,38 @@ class Test { String toString() { return 'Test{a: $a, b: $b}'; } + + TestT unpack() => TestT( + a: a, + b: b); + + static int pack(fb.Builder fbBuilder, TestT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TestT { + int a; + int b; + + TestT({ + this.a, + this.b}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.pad(1); + fbBuilder.putInt8(b); + fbBuilder.putInt16(a); + return fbBuilder.offset; + } + + @override + String toString() { + return 'TestT{a: $a, b: $b}'; + } } class _TestReader extends fb.StructReader { @@ -310,6 +342,34 @@ class TestSimpleTableWithEnum { String toString() { return 'TestSimpleTableWithEnum{color: $color}'; } + + TestSimpleTableWithEnumT unpack() => TestSimpleTableWithEnumT( + color: color); + + static int pack(fb.Builder fbBuilder, TestSimpleTableWithEnumT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TestSimpleTableWithEnumT { + Color color; + + TestSimpleTableWithEnumT({ + this.color}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + fbBuilder.addUint8(0, color?.value); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'TestSimpleTableWithEnumT{color: $color}'; + } } class _TestSimpleTableWithEnumReader extends fb.TableReader { @@ -387,6 +447,56 @@ class Vec3 { String toString() { return 'Vec3{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}'; } + + Vec3T unpack() => Vec3T( + x: x, + y: y, + z: z, + test1: test1, + test2: test2, + test3: test3?.unpack()); + + static int pack(fb.Builder fbBuilder, Vec3T object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class Vec3T { + double x; + double y; + double z; + double test1; + Color test2; + TestT test3; + + Vec3T({ + this.x, + this.y, + this.z, + this.test1, + this.test2, + this.test3}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.pad(2); + test3.pack(fbBuilder); + fbBuilder.pad(1); + fbBuilder.putUint8(test2?.value); + fbBuilder.putFloat64(test1); + fbBuilder.pad(4); + fbBuilder.putFloat32(z); + fbBuilder.putFloat32(y); + fbBuilder.putFloat32(x); + return fbBuilder.offset; + } + + @override + String toString() { + return 'Vec3T{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}'; + } } class _Vec3Reader extends fb.StructReader { @@ -486,6 +596,37 @@ class Ability { String toString() { return 'Ability{id: $id, distance: $distance}'; } + + AbilityT unpack() => AbilityT( + id: id, + distance: distance); + + static int pack(fb.Builder fbBuilder, AbilityT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class AbilityT { + int id; + int distance; + + AbilityT({ + this.id, + this.distance}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.putUint32(distance); + fbBuilder.putUint32(id); + return fbBuilder.offset; + } + + @override + String toString() { + return 'AbilityT{id: $id, distance: $distance}'; + } } class _AbilityReader extends fb.StructReader { @@ -560,6 +701,41 @@ class StructOfStructs { String toString() { return 'StructOfStructs{a: $a, b: $b, c: $c}'; } + + StructOfStructsT unpack() => StructOfStructsT( + a: a?.unpack(), + b: b?.unpack(), + c: c?.unpack()); + + static int pack(fb.Builder fbBuilder, StructOfStructsT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class StructOfStructsT { + AbilityT a; + TestT b; + AbilityT c; + + StructOfStructsT({ + this.a, + this.b, + this.c}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + c.pack(fbBuilder); + b.pack(fbBuilder); + a.pack(fbBuilder); + return fbBuilder.offset; + } + + @override + String toString() { + return 'StructOfStructsT{a: $a, b: $b, c: $c}'; + } } class _StructOfStructsReader extends fb.StructReader { @@ -643,6 +819,45 @@ class Stat { String toString() { return 'Stat{id: $id, val: $val, count: $count}'; } + + StatT unpack() => StatT( + id: id, + val: val, + count: count); + + static int pack(fb.Builder fbBuilder, StatT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class StatT { + String id; + int val; + int count; + + StatT({ + this.id, + this.val, + this.count}); + + int pack(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(); + } + + @override + String toString() { + return 'StatT{id: $id, val: $val, count: $count}'; + } } class _StatReader extends fb.TableReader { @@ -738,6 +953,34 @@ class Referrable { String toString() { return 'Referrable{id: $id}'; } + + ReferrableT unpack() => ReferrableT( + id: id); + + static int pack(fb.Builder fbBuilder, ReferrableT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class ReferrableT { + int id; + + ReferrableT({ + this.id}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + fbBuilder.addUint64(0, id); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'ReferrableT{id: $id}'; + } } class _ReferrableReader extends fb.TableReader { @@ -887,6 +1130,362 @@ class Monster { 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, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum, testrequirednestedflatbuffer: $testrequirednestedflatbuffer, scalarKeySortedTables: $scalarKeySortedTables}'; } + + MonsterT unpack() => MonsterT( + pos: pos?.unpack(), + mana: mana, + hp: hp, + name: name, + inventory: inventory, + color: color, + testType: testType, + test: test, + test4: test4?.map((e) => e.unpack())?.toList(), + testarrayofstring: testarrayofstring, + testarrayoftables: testarrayoftables?.map((e) => e.unpack())?.toList(), + enemy: enemy?.unpack(), + testnestedflatbuffer: testnestedflatbuffer, + testempty: testempty?.unpack(), + 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?.map((e) => e.unpack())?.toList(), + flex: flex, + test5: test5?.map((e) => e.unpack())?.toList(), + vectorOfLongs: vectorOfLongs, + vectorOfDoubles: vectorOfDoubles, + parentNamespaceTest: parentNamespaceTest?.unpack(), + vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack())?.toList(), + singleWeakReference: singleWeakReference, + vectorOfWeakReferences: vectorOfWeakReferences, + vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack())?.toList(), + coOwningReference: coOwningReference, + vectorOfCoOwningReferences: vectorOfCoOwningReferences, + nonOwningReference: nonOwningReference, + vectorOfNonOwningReferences: vectorOfNonOwningReferences, + anyUniqueType: anyUniqueType, + anyUnique: anyUnique, + anyAmbiguousType: anyAmbiguousType, + anyAmbiguous: anyAmbiguous, + vectorOfEnums: vectorOfEnums, + signedEnum: signedEnum, + testrequirednestedflatbuffer: testrequirednestedflatbuffer, + scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack())?.toList()); + + static int pack(fb.Builder fbBuilder, MonsterT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +/// an example documentation comment: "monster object" +class MonsterT { + Vec3T pos; + int mana; + int hp; + String name; + List inventory; + Color color; + AnyTypeId testType; + dynamic test; + List test4; + List testarrayofstring; + /// an example documentation comment: this will end up in the generated code + /// multiline too + List testarrayoftables; + MonsterT enemy; + List testnestedflatbuffer; + StatT testempty; + bool testbool; + int testhashs32Fnv1; + int testhashu32Fnv1; + int testhashs64Fnv1; + int testhashu64Fnv1; + int testhashs32Fnv1a; + int testhashu32Fnv1a; + int testhashs64Fnv1a; + int testhashu64Fnv1a; + List testarrayofbools; + double testf; + double testf2; + double testf3; + List testarrayofstring2; + List testarrayofsortedstruct; + List flex; + List test5; + List vectorOfLongs; + List vectorOfDoubles; + my_game.InParentNamespaceT parentNamespaceTest; + List vectorOfReferrables; + int singleWeakReference; + List vectorOfWeakReferences; + List vectorOfStrongReferrables; + int coOwningReference; + List vectorOfCoOwningReferences; + int nonOwningReference; + List vectorOfNonOwningReferences; + AnyUniqueAliasesTypeId anyUniqueType; + dynamic anyUnique; + AnyAmbiguousAliasesTypeId anyAmbiguousType; + dynamic anyAmbiguous; + List vectorOfEnums; + Race signedEnum; + List testrequirednestedflatbuffer; + List scalarKeySortedTables; + + MonsterT({ + this.pos, + this.mana, + this.hp, + this.name, + this.inventory, + this.color, + this.testType, + this.test, + this.test4, + this.testarrayofstring, + this.testarrayoftables, + this.enemy, + this.testnestedflatbuffer, + this.testempty, + this.testbool, + this.testhashs32Fnv1, + this.testhashu32Fnv1, + this.testhashs64Fnv1, + this.testhashu64Fnv1, + this.testhashs32Fnv1a, + this.testhashu32Fnv1a, + this.testhashs64Fnv1a, + this.testhashu64Fnv1a, + this.testarrayofbools, + this.testf, + this.testf2, + this.testf3, + this.testarrayofstring2, + this.testarrayofsortedstruct, + this.flex, + this.test5, + this.vectorOfLongs, + this.vectorOfDoubles, + this.parentNamespaceTest, + this.vectorOfReferrables, + this.singleWeakReference, + this.vectorOfWeakReferences, + this.vectorOfStrongReferrables, + this.coOwningReference, + this.vectorOfCoOwningReferences, + this.nonOwningReference, + this.vectorOfNonOwningReferences, + this.anyUniqueType, + this.anyUnique, + this.anyAmbiguousType, + this.anyAmbiguous, + this.vectorOfEnums, + this.signedEnum, + this.testrequirednestedflatbuffer, + this.scalarKeySortedTables}); + + int pack(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?.pack(fbBuilder); + int test4Offset = null; + if (test4?.isNotEmpty == true) { + test4.forEach((e) => e.pack(fbBuilder)); + test4Offset = fbBuilder.endStructVector(test4.length); + } + 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.pack(fbBuilder)).toList()) + : null; + final int enemyOffset = enemy?.pack(fbBuilder); + final int testnestedflatbufferOffset = testnestedflatbuffer?.isNotEmpty == true + ? fbBuilder.writeListUint8(testnestedflatbuffer) + : null; + final int testemptyOffset = testempty?.pack(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; + int testarrayofsortedstructOffset = null; + if (testarrayofsortedstruct?.isNotEmpty == true) { + testarrayofsortedstruct.forEach((e) => e.pack(fbBuilder)); + testarrayofsortedstructOffset = fbBuilder.endStructVector(testarrayofsortedstruct.length); + } + final int flexOffset = flex?.isNotEmpty == true + ? fbBuilder.writeListUint8(flex) + : null; + int test5Offset = null; + if (test5?.isNotEmpty == true) { + test5.forEach((e) => e.pack(fbBuilder)); + test5Offset = fbBuilder.endStructVector(test5.length); + } + final int vectorOfLongsOffset = vectorOfLongs?.isNotEmpty == true + ? fbBuilder.writeListInt64(vectorOfLongs) + : null; + final int vectorOfDoublesOffset = vectorOfDoubles?.isNotEmpty == true + ? fbBuilder.writeListFloat64(vectorOfDoubles) + : null; + final int parentNamespaceTestOffset = parentNamespaceTest?.pack(fbBuilder); + final int vectorOfReferrablesOffset = vectorOfReferrables?.isNotEmpty == true + ? fbBuilder.writeList(vectorOfReferrables.map((b) => b.pack(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.pack(fbBuilder)).toList()) + : null; + final int vectorOfCoOwningReferencesOffset = vectorOfCoOwningReferences?.isNotEmpty == true + ? fbBuilder.writeListUint64(vectorOfCoOwningReferences) + : null; + final int vectorOfNonOwningReferencesOffset = vectorOfNonOwningReferences?.isNotEmpty == true + ? fbBuilder.writeListUint64(vectorOfNonOwningReferences) + : null; + final int anyUniqueOffset = anyUnique?.pack(fbBuilder); + final int anyAmbiguousOffset = anyAmbiguous?.pack(fbBuilder); + final int vectorOfEnumsOffset = vectorOfEnums?.isNotEmpty == true + ? fbBuilder.writeListUint8(vectorOfEnums.map((f) => f.value).toList()) + : null; + final int testrequirednestedflatbufferOffset = testrequirednestedflatbuffer?.isNotEmpty == true + ? fbBuilder.writeListUint8(testrequirednestedflatbuffer) + : null; + final int scalarKeySortedTablesOffset = scalarKeySortedTables?.isNotEmpty == true + ? fbBuilder.writeList(scalarKeySortedTables.map((b) => b.pack(fbBuilder)).toList()) + : null; + + fbBuilder.startTable(); + if (pos != null) { + fbBuilder.addStruct(0, pos.pack(fbBuilder)); + } + fbBuilder.addInt16(1, mana); + fbBuilder.addInt16(2, hp); + if (nameOffset != null) { + fbBuilder.addOffset(3, nameOffset); + } + if (inventoryOffset != null) { + fbBuilder.addOffset(5, inventoryOffset); + } + fbBuilder.addUint8(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); + } + fbBuilder.addUint8(43, anyUniqueType?.value); + if (anyUniqueOffset != null) { + fbBuilder.addOffset(44, anyUniqueOffset); + } + fbBuilder.addUint8(45, anyAmbiguousType?.value); + if (anyAmbiguousOffset != null) { + fbBuilder.addOffset(46, anyAmbiguousOffset); + } + if (vectorOfEnumsOffset != null) { + fbBuilder.addOffset(47, vectorOfEnumsOffset); + } + fbBuilder.addInt8(48, signedEnum?.value); + if (testrequirednestedflatbufferOffset != null) { + fbBuilder.addOffset(49, testrequirednestedflatbufferOffset); + } + if (scalarKeySortedTablesOffset != null) { + fbBuilder.addOffset(50, scalarKeySortedTablesOffset); + } + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'MonsterT{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, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums, signedEnum: $signedEnum, testrequirednestedflatbuffer: $testrequirednestedflatbuffer, scalarKeySortedTables: $scalarKeySortedTables}'; + } } class _MonsterReader extends fb.TableReader { @@ -1333,7 +1932,7 @@ class MonsterObjectBuilder extends fb.ObjectBuilder { final int anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder); final int anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder); final int vectorOfEnumsOffset = _vectorOfEnums?.isNotEmpty == true - ? fbBuilder.writeListUint8(_vectorOfEnums.map((f) => f.value)) + ? fbBuilder.writeListUint8(_vectorOfEnums.map((f) => f.value).toList()) : null; final int testrequirednestedflatbufferOffset = _testrequirednestedflatbuffer?.isNotEmpty == true ? fbBuilder.writeListUint8(_testrequirednestedflatbuffer) @@ -1489,6 +2088,88 @@ class TypeAliases { 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}'; } + + TypeAliasesT unpack() => TypeAliasesT( + i8: i8, + u8: u8, + i16: i16, + u16: u16, + i32: i32, + u32: u32, + i64: i64, + u64: u64, + f32: f32, + f64: f64, + v8: v8, + vf64: vf64); + + static int pack(fb.Builder fbBuilder, TypeAliasesT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TypeAliasesT { + int i8; + int u8; + int i16; + int u16; + int i32; + int u32; + int i64; + int u64; + double f32; + double f64; + List v8; + List vf64; + + TypeAliasesT({ + this.i8, + this.u8, + this.i16, + this.u16, + this.i32, + this.u32, + this.i64, + this.u64, + this.f32, + this.f64, + this.v8, + this.vf64}); + + int pack(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(); + } + + @override + String toString() { + return 'TypeAliasesT{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 { diff --git a/tests/monster_test_my_game_generated.dart b/tests/monster_test_my_game_generated.dart index abd538c49..d53550d13 100644 --- a/tests/monster_test_my_game_generated.dart +++ b/tests/monster_test_my_game_generated.dart @@ -26,6 +26,27 @@ class InParentNamespace { String toString() { return 'InParentNamespace{}'; } + + InParentNamespaceT unpack() => InParentNamespaceT(); + + static int pack(fb.Builder fbBuilder, InParentNamespaceT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class InParentNamespaceT { + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'InParentNamespaceT{}'; + } } class _InParentNamespaceReader extends fb.TableReader { diff --git a/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart b/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart index 4941a3c26..c36d1e000 100644 --- a/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart +++ b/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart @@ -104,6 +104,34 @@ class TableInNestedNS { String toString() { return 'TableInNestedNS{foo: $foo}'; } + + TableInNestedNST unpack() => TableInNestedNST( + foo: foo); + + static int pack(fb.Builder fbBuilder, TableInNestedNST object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TableInNestedNST { + int foo; + + TableInNestedNST({ + this.foo}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.startTable(); + fbBuilder.addInt32(0, foo); + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'TableInNestedNST{foo: $foo}'; + } } class _TableInNestedNSReader extends fb.TableReader { @@ -177,6 +205,37 @@ class StructInNestedNS { String toString() { return 'StructInNestedNS{a: $a, b: $b}'; } + + StructInNestedNST unpack() => StructInNestedNST( + a: a, + b: b); + + static int pack(fb.Builder fbBuilder, StructInNestedNST object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class StructInNestedNST { + int a; + int b; + + StructInNestedNST({ + this.a, + this.b}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + + fbBuilder.putInt32(b); + fbBuilder.putInt32(a); + return fbBuilder.offset; + } + + @override + String toString() { + return 'StructInNestedNST{a: $a, b: $b}'; + } } class _StructInNestedNSReader extends fb.StructReader { diff --git a/tests/namespace_test/namespace_test2_namespace_a_generated.dart b/tests/namespace_test/namespace_test2_namespace_a_generated.dart index 8c08420cf..79a82a2c7 100644 --- a/tests/namespace_test/namespace_test2_namespace_a_generated.dart +++ b/tests/namespace_test/namespace_test2_namespace_a_generated.dart @@ -35,6 +35,58 @@ class TableInFirstNS { String toString() { return 'TableInFirstNS{fooTable: $fooTable, fooEnum: $fooEnum, fooUnionType: $fooUnionType, fooUnion: $fooUnion, fooStruct: $fooStruct}'; } + + TableInFirstNST unpack() => TableInFirstNST( + fooTable: fooTable?.unpack(), + fooEnum: fooEnum, + fooUnionType: fooUnionType, + fooUnion: fooUnion, + fooStruct: fooStruct?.unpack()); + + static int pack(fb.Builder fbBuilder, TableInFirstNST object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TableInFirstNST { + namespace_a_namespace_b.TableInNestedNST fooTable; + EnumInNestedNS fooEnum; + UnionInNestedNSTypeId fooUnionType; + dynamic fooUnion; + namespace_a_namespace_b.StructInNestedNST fooStruct; + + TableInFirstNST({ + this.fooTable, + this.fooEnum, + this.fooUnionType, + this.fooUnion, + this.fooStruct}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + final int fooTableOffset = fooTable?.pack(fbBuilder); + final int fooUnionOffset = fooUnion?.pack(fbBuilder); + + fbBuilder.startTable(); + if (fooTableOffset != null) { + fbBuilder.addOffset(0, fooTableOffset); + } + fbBuilder.addInt8(1, fooEnum?.value); + fbBuilder.addUint8(2, fooUnionType?.value); + if (fooUnionOffset != null) { + fbBuilder.addOffset(3, fooUnionOffset); + } + if (fooStruct != null) { + fbBuilder.addStruct(4, fooStruct.pack(fbBuilder)); + } + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'TableInFirstNST{fooTable: $fooTable, fooEnum: $fooEnum, fooUnionType: $fooUnionType, fooUnion: $fooUnion, fooStruct: $fooStruct}'; + } } class _TableInFirstNSReader extends fb.TableReader { @@ -151,6 +203,37 @@ class SecondTableInA { String toString() { return 'SecondTableInA{referToC: $referToC}'; } + + SecondTableInAT unpack() => SecondTableInAT( + referToC: referToC?.unpack()); + + static int pack(fb.Builder fbBuilder, SecondTableInAT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class SecondTableInAT { + namespace_c.TableInCT referToC; + + SecondTableInAT({ + this.referToC}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + final int referToCOffset = referToC?.pack(fbBuilder); + + fbBuilder.startTable(); + if (referToCOffset != null) { + fbBuilder.addOffset(0, referToCOffset); + } + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'SecondTableInAT{referToC: $referToC}'; + } } class _SecondTableInAReader extends fb.TableReader { diff --git a/tests/namespace_test/namespace_test2_namespace_c_generated.dart b/tests/namespace_test/namespace_test2_namespace_c_generated.dart index edb6ffcbc..41f474c38 100644 --- a/tests/namespace_test/namespace_test2_namespace_c_generated.dart +++ b/tests/namespace_test/namespace_test2_namespace_c_generated.dart @@ -27,6 +27,44 @@ class TableInC { String toString() { return 'TableInC{referToA1: $referToA1, referToA2: $referToA2}'; } + + TableInCT unpack() => TableInCT( + referToA1: referToA1?.unpack(), + referToA2: referToA2?.unpack()); + + static int pack(fb.Builder fbBuilder, TableInCT object) { + if (object == null) return 0; + return object.pack(fbBuilder); + } +} + +class TableInCT { + namespace_a.TableInFirstNST referToA1; + namespace_a.SecondTableInAT referToA2; + + TableInCT({ + this.referToA1, + this.referToA2}); + + int pack(fb.Builder fbBuilder) { + assert(fbBuilder != null); + final int referToA1Offset = referToA1?.pack(fbBuilder); + final int referToA2Offset = referToA2?.pack(fbBuilder); + + fbBuilder.startTable(); + if (referToA1Offset != null) { + fbBuilder.addOffset(0, referToA1Offset); + } + if (referToA2Offset != null) { + fbBuilder.addOffset(1, referToA2Offset); + } + return fbBuilder.endTable(); + } + + @override + String toString() { + return 'TableInCT{referToA1: $referToA1, referToA2: $referToA2}'; + } } class _TableInCReader extends fb.TableReader {