From de9aa0cdee04fb2e73fc956657f89a0e6100a10a Mon Sep 17 00:00:00 2001 From: Paulo Pinheiro Date: Mon, 22 Jul 2019 20:05:15 -0300 Subject: [PATCH] Add basic Kotlin support (#5409) * [Kotlin] Add kotlin generate code for tests and add kotlin test to TestAll.sh * [Kotlin] Add Kotlin generator This change adds support for generating Kotlin classes. The approach of this generator is to keep it as close as possible to the java generator for now, in order to keep the change simple. It uses the already implemented java runtime, so we don't support cross-platform nor js Kotlin yet. Kotlin tests are just a copy of the java tests. * Add optional ident support for CodeWriter Identation is important for some languages and different projects have different ways of ident code, e.g. tabs vs spaces, so we are adding optional support on CodeWriter for identation. * [Kotlin] Add Documentation for Kotlin * [Kotlin] Modify generated code to use experimental Unsigned types. --- BUILD | 1 + CMakeLists.txt | 1 + docs/source/Compiler.md | 2 + docs/source/FlatBuffers.md | 8 +- docs/source/KotlinUsage.md | 84 + docs/source/Tutorial.md | 191 ++- include/flatbuffers/code_generators.h | 18 +- include/flatbuffers/idl.h | 47 +- samples/SampleBinary.kt | 108 ++ samples/kotlin_sample.sh | 60 + src/code_generators.cpp | 11 + src/flatc_main.cpp | 3 + src/idl_gen_cpp.cpp | 2 +- src/idl_gen_general.cpp | 4 +- src/idl_gen_go.cpp | 2 +- src/idl_gen_kotlin.cpp | 1527 +++++++++++++++++ src/idl_gen_lobster.cpp | 2 +- src/idl_gen_lua.cpp | 2 +- src/idl_gen_php.cpp | 2 +- src/idl_gen_python.cpp | 2 +- src/idl_gen_rust.cpp | 4 +- src/idl_gen_text.cpp | 8 +- src/idl_parser.cpp | 21 +- tests/KotlinTest.kt | 460 +++++ tests/KotlinTest.sh | 46 + tests/MyGame/Example/Ability.kt | 32 + tests/MyGame/Example/Any.kt | 16 + tests/MyGame/Example/AnyAmbiguousAliases.kt | 16 + tests/MyGame/Example/AnyUniqueAliases.kt | 16 + tests/MyGame/Example/Color.kt | 25 + tests/MyGame/Example/Monster.kt | 974 +++++++++++ tests/MyGame/Example/Referrable.kt | 80 + tests/MyGame/Example/Stat.kt | 78 + tests/MyGame/Example/Test.kt | 33 + tests/MyGame/Example/TestEnum.kt | 14 + .../MyGame/Example/TestSimpleTableWithEnum.kt | 53 + tests/MyGame/Example/TypeAliases.kt | 263 +++ tests/MyGame/Example/Vec3.kt | 50 + tests/MyGame/Example2/Monster.kt | 33 + tests/MyGame/InParentNamespace.kt | 33 + tests/MyGame/MonsterExtra.kt | 202 +++ tests/TestAll.sh | 4 + tests/generate_code.sh | 10 +- .../NamespaceA/NamespaceB/EnumInNestedNS.kt | 15 + .../NamespaceA/NamespaceB/StructInNestedNS.kt | 32 + .../NamespaceA/NamespaceB/TableInNestedNS.kt | 53 + .../NamespaceA/SecondTableInA.kt | 48 + .../NamespaceA/TableInFirstNS.kt | 68 + tests/namespace_test/NamespaceC/TableInC.kt | 59 + tests/union_vector/Attacker.kt | 51 + tests/union_vector/BookReader.kt | 27 + tests/union_vector/Character.kt | 17 + tests/union_vector/Movie.kt | 114 ++ tests/union_vector/Rapunzel.kt | 27 + 54 files changed, 4995 insertions(+), 64 deletions(-) create mode 100644 docs/source/KotlinUsage.md create mode 100644 samples/SampleBinary.kt create mode 100755 samples/kotlin_sample.sh create mode 100644 src/idl_gen_kotlin.cpp create mode 100644 tests/KotlinTest.kt create mode 100755 tests/KotlinTest.sh create mode 100644 tests/MyGame/Example/Ability.kt create mode 100644 tests/MyGame/Example/Any.kt create mode 100644 tests/MyGame/Example/AnyAmbiguousAliases.kt create mode 100644 tests/MyGame/Example/AnyUniqueAliases.kt create mode 100644 tests/MyGame/Example/Color.kt create mode 100644 tests/MyGame/Example/Monster.kt create mode 100644 tests/MyGame/Example/Referrable.kt create mode 100644 tests/MyGame/Example/Stat.kt create mode 100644 tests/MyGame/Example/Test.kt create mode 100644 tests/MyGame/Example/TestEnum.kt create mode 100644 tests/MyGame/Example/TestSimpleTableWithEnum.kt create mode 100644 tests/MyGame/Example/TypeAliases.kt create mode 100644 tests/MyGame/Example/Vec3.kt create mode 100644 tests/MyGame/Example2/Monster.kt create mode 100644 tests/MyGame/InParentNamespace.kt create mode 100644 tests/MyGame/MonsterExtra.kt create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt create mode 100644 tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt create mode 100644 tests/namespace_test/NamespaceA/SecondTableInA.kt create mode 100644 tests/namespace_test/NamespaceA/TableInFirstNS.kt create mode 100644 tests/namespace_test/NamespaceC/TableInC.kt create mode 100644 tests/union_vector/Attacker.kt create mode 100644 tests/union_vector/BookReader.kt create mode 100644 tests/union_vector/Character.kt create mode 100644 tests/union_vector/Movie.kt create mode 100644 tests/union_vector/Rapunzel.kt diff --git a/BUILD b/BUILD index e66618196..6c69195fb 100644 --- a/BUILD +++ b/BUILD @@ -86,6 +86,7 @@ cc_binary( "src/idl_gen_cpp.cpp", "src/idl_gen_dart.cpp", "src/idl_gen_general.cpp", + "src/idl_gen_kotlin.cpp", "src/idl_gen_go.cpp", "src/idl_gen_grpc.cpp", "src/idl_gen_js_ts.cpp", diff --git a/CMakeLists.txt b/CMakeLists.txt index c7da97f5a..029ccb5d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ set(FlatBuffers_Compiler_SRCS src/idl_gen_cpp.cpp src/idl_gen_dart.cpp src/idl_gen_general.cpp + src/idl_gen_kotlin.cpp src/idl_gen_go.cpp src/idl_gen_js_ts.cpp src/idl_gen_php.cpp diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 49a3d8f6e..7889abdc2 100644 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -23,6 +23,8 @@ For any schema input files, one or more generators can be specified: - `--java`, `-j` : Generate Java code. +- `--kotlin`, `-k` : Generate Kotlin code. + - `--csharp`, `-n` : Generate C# code. - `--go`, `-g` : Generate Go code. diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md index 7cc93b92c..dc77500de 100644 --- a/docs/source/FlatBuffers.md +++ b/docs/source/FlatBuffers.md @@ -4,7 +4,7 @@ FlatBuffers {#flatbuffers_index} # Overview {#flatbuffers_overview} [FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform -serialization library for C++, C#, C, Go, Java, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust. +serialization library for C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust. It was originally created at Google for game development and other performance-critical applications. @@ -51,7 +51,7 @@ under the Apache license, v2 (see LICENSE.txt). needed (faster and more memory efficient than other JSON parsers). - Java and Go code supports object-reuse. C# has efficient struct based + Java, Kotlin and Go code supports object-reuse. C# has efficient struct based accessors. - **Cross platform code with no dependencies** - C++ code will work @@ -108,7 +108,7 @@ sections provide a more in-depth usage guide. present for every object instance. - Use `flatc` (the FlatBuffer compiler) to generate a C++ header (or - Java/C#/Go/Python.. classes) with helper classes to access and construct + Java/Kotlin/C#/Go/Python.. classes) with helper classes to access and construct serialized data. This header (say `mydata_generated.h`) only depends on `flatbuffers.h`, which defines the core functionality. @@ -132,6 +132,8 @@ sections provide a more in-depth usage guide. own programs. - How to [use the generated Java/C# code](@ref flatbuffers_guide_use_java_c-sharp) in your own programs. +- How to [use the generated Kotlin code](@ref flatbuffers_guide_use_kotlin) + in your own programs. - How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your own programs. - How to [use the generated Lua code](@ref flatbuffers_guide_use_lua) in your diff --git a/docs/source/KotlinUsage.md b/docs/source/KotlinUsage.md new file mode 100644 index 000000000..092fcd7f5 --- /dev/null +++ b/docs/source/KotlinUsage.md @@ -0,0 +1,84 @@ +Use in Kotlin {#flatbuffers_guide_use_kotlin} +============== + +## Before you get started + +Before diving into the FlatBuffers usage in Kotlin, 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 K). + +This page is designed to cover the nuances of FlatBuffers usage, specific to Kotlin. + +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). + +## Kotlin and FlatBuffers Java code location + +Code generated for Kotlin currently uses the flatbuffers java runtime library. That means that Kotlin generated code can only have Java virtual machine as target architecture (which includes Android). Kotlin Native and Kotlin.js are currently not supported. + +The code for the FlatBuffers Java library can be found at +`flatbuffers/java/com/google/flatbuffers`. You can browse the library on the +[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/ +java/com/google/flatbuffers). + +## Testing FlatBuffers Kotlin + +The test code for Java is located in [KotlinTest.java](https://github.com/google +/flatbuffers/blob/master/tests/KotlinTest.kt). + +To run the tests, use [KotlinTest.sh](https://github.com/google/ +flatbuffers/blob/master/tests/KotlinTest.sh) shell script. + +*Note: These scripts require that [Kotlin](https://kotlinlang.org/) is installed.* + +## Using the FlatBuffers Kotlin library + +*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth +example of how to use FlatBuffers in Kotlin.* + +FlatBuffers supports reading and writing binary FlatBuffers in Kotlin. + +To use FlatBuffers in your own code, first generate Java classes from your +schema with the `--kotlin` 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 Kotlin: +First, import the library and generated code. Then, you read a FlatBuffer binary +file into a `ByteArray`. You then turn the `ByteArray` into a `ByteBuffer`, which you +pass to the `getRootAsMyRootType` function: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.kt} + import MyGame.Example.* + import com.google.flatbuffers.FlatBufferBuilder + + // This snippet ignores exceptions for brevity. + val data = RandomAccessFile(File("monsterdata_test.mon"), "r").use { + val temp = ByteArray(it.length().toInt()) + it.readFully(temp) + temp + } + + val bb = ByteBuffer.wrap(data) + val monster = Monster.getRootAsMonster(bb) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now you can access the data from the `Monster monster`: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.kt} + val hp = monster.hp + val pos = monster.pos!!; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + +## Differences between Kotlin and Java code + +Kotlin generated code was designed to be as close as possible to the java counterpart, as for now, we only support kotlin on java virtual machine. So the differences in implementation and usage are basically the ones introduced by the Kotlin language itself. You can find more in-depth information [here](https://kotlinlang.org/docs/reference/comparison-to-java.html). + +The most obvious ones are: + +* Fields as accessed as Kotlin [properties](https://kotlinlang.org/docs/reference/properties.html) +* Static methods are accessed in [companion object](https://kotlinlang.org/docs/reference/classes.html#companion-objects) \ No newline at end of file diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index 62abe7ffb..18818a0af 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -23,6 +23,7 @@ Please select your desired language for our quest:
C++ Java + Kotlin C# Go Python @@ -115,6 +116,9 @@ For your chosen language, please cross-reference with:
[SampleBinary.java](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.java)
+
+[SampleBinary.kt](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.kt) +
[SampleBinary.cs](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.cs)
@@ -284,6 +288,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools. ./../flatc --java monster.fbs ~~~ +
+~~~{.sh} + cd flatbuffers/samples + ./../flatc --kotlin monster.fbs +~~~ +
~~~{.sh} cd flatbuffers/samples @@ -382,6 +392,13 @@ The first step is to import/include the library, generated files, etc. import com.google.flatbuffers.FlatBufferBuilder; ~~~
+
+~~~{.kotlin} + import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.) + + import com.google.flatbuffers.FlatBufferBuilder +~~~ +
~~~{.cs} using FlatBuffers; @@ -525,6 +542,13 @@ which will grow automatically if needed: FlatBufferBuilder builder = new FlatBufferBuilder(1024); ~~~
+
+~~~{.kt} + // Create a `FlatBufferBuilder`, which will be used to create our + // monsters' FlatBuffers. + val builder = FlatBufferBuilder(1024) +~~~ +
~~~{.cs} // Create a `FlatBufferBuilder`, which will be used to create our @@ -633,6 +657,19 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. int axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage); ~~~
+
+~~~{.kt} + val weaponOneName = builder.createString("Sword") + val weaponOneDamage: Short = 3; + + val weaponTwoName = builder.createString("Axe") + val weaponTwoDamage: Short = 5; + + // Use the `createWeapon()` helper function to create the weapons, since we set every field. + val sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage) + val axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage) +~~~ +
~~~{.cs} var weaponOneName = builder.CreateString("Sword"); @@ -875,6 +912,17 @@ traversal. This is generally easy to do on any tree structures. int inv = Monster.createInventoryVector(builder, treasure); ~~~
+
+~~~{.kt} + // Serialize a name for our monster, called "Orc". + val name = builder.createString("Orc") + + // Create a `vector` representing the inventory of the Orc. Each number + // could correspond to an item that can be claimed after he is slain. + val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + val inv = Monster.createInventoryVector(builder, treasure) +~~~ +
~~~{.cs} // Serialize a name for our monster, called "Orc". @@ -1060,6 +1108,16 @@ offsets. int weapons = Monster.createWeaponsVector(builder, weaps); ~~~
+
+~~~{.kt} + // Place the two weapons into an array, and pass it to the `createWeaponsVector()` method to + // create a FlatBuffer vector. + val weaps = intArrayOf(sword, axe) + + // Pass the `weaps` array into the `createWeaponsVector()` method to create a FlatBuffer vector. + val weapons = Monster.createWeaponsVector(builder, weaps) +~~~ +
~~~{.cs} var weaps = new Offset[2]; @@ -1180,6 +1238,14 @@ for the `path` field above: int path = fbb.endVector(); ~~~
+
+~~~{.kt} + Monster.startPathVector(fbb, 2) + Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f) + Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f) + val path = fbb.endVector() +~~~ +
~~~{.cs} Monster.StartPathVector(fbb, 2); @@ -1318,6 +1384,22 @@ can serialize the monster itself: int orc = Monster.endMonster(builder); ~~~
+
+~~~{.kt} + // Create our monster using `startMonster()` and `endMonster()`. + Monster.startMonster(builder) + Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)) + Monster.addName(builder, name) + Monster.addColor(builder, Color.Red) + Monster.addHp(builder, 300.toShort()) + Monster.addInventory(builder, inv) + Monster.addWeapons(builder, weapons) + Monster.addEquippedType(builder, Equipment.Weapon) + Monster.addEquipped(builder, axe) + Monster.addPath(builder, path) + val orc = Monster.endMonster(builder) +~~~ +
~~~{.cs} // Create our monster using `StartMonster()` and `EndMonster()`. @@ -1627,6 +1709,12 @@ Here is a repetition these lines, to help highlight them more clearly: Monster.addEquipped(axe); // Union data ~~~
+
+ ~~~{.kt} + Monster.addEquippedType(builder, Equipment.Weapon) // Union type + Monster.addEquipped(axe) // Union data + ~~~ +
~~~{.cs} Monster.AddEquippedType(builder, Equipment.Weapon); // Union type @@ -1722,6 +1810,12 @@ appropriate `finish` method. builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`. ~~~
+
+~~~{.kt} + // Call `finish()` to instruct the builder that this monster is complete. + builder.finish(orc) // You could also call `Monster.finishMonsterBuffer(builder, orc);`. +~~~ +
~~~{.cs} // Call `Finish()` to instruct the builder that this monster is complete. @@ -1814,6 +1908,17 @@ like so: byte[] buf = builder.sizedByteArray(); ~~~
+
+~~~{.kt} + // This must be called after `finish()`. + val buf = builder.dataBuffer() + // The data in this ByteBuffer does NOT start at 0, but at buf.position(). + // The number of bytes is buf.remaining(). + + // Alternatively this copies the above data out of the ByteBuffer for you: + val buf = builder.sizedByteArray() +~~~ +
~~~{.cs} // This must be called after `Finish()`. @@ -1936,6 +2041,13 @@ before: import com.google.flatbuffers.FlatBufferBuilder; ~~~
+
+~~~{.kt} + import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.) + + import com.google.flatbuffers.FlatBufferBuilder +~~~ +
~~~{.cs} using FlatBuffers; @@ -2084,6 +2196,15 @@ won't work** Monster monster = Monster.getRootAsMonster(buf); ~~~
+
+~~~{.kt} + val bytes = /* the data you just read */ + val buf = java.nio.ByteBuffer.wrap(bytes) + + // Get an accessor to the root object inside the buffer. + Monster monster = Monster.getRootAsMonster(buf) +~~~ +
~~~{.cs} byte[] bytes = /* the data you just read */ @@ -2208,6 +2329,13 @@ accessors for all non-`deprecated` fields. For example: String name = monster.name(); ~~~
+
+~~~{.kt} + val hp = monster.hp + val mana = monster.mana + val name = monster.name +~~~ +
~~~{.cs} // For C#, unlike most other languages support by FlatBuffers, most values (except for @@ -2313,6 +2441,14 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`: float z = pos.z(); ~~~
+
+~~~{.kt} + val pos = monster.pos!! + val x = pos.x + val y = pos.y + val z = pos.z +~~~ +
~~~{.cs} var pos = monster.Pos.Value; @@ -2429,6 +2565,12 @@ FlatBuffers `vector`. byte thirdItem = monster.inventory(2); ~~~
+
+~~~{.kotlin} + val invLength = monster.inventoryLength + val thirdItem = monster.inventory(2)!! +~~~ +
~~~{.cs} int invLength = monster.InventoryLength; @@ -2520,6 +2662,13 @@ except your need to handle the result as a FlatBuffer `table`: short secondWeaponDamage = monster.weapons(1).damage(); ~~~
+
+~~~{.kt} + val weaponsLength = monster.weaponsLength + val secondWeaponName = monster.weapons(1)!!.name + val secondWeaponDamage = monster.weapons(1)!!.damage +~~~ +
~~~{.cs} int weaponsLength = monster.WeaponsLength; @@ -2640,6 +2789,19 @@ We can access the type to dynamically cast the data as needed (since the } ~~~
+
+~~~{.kt} + val unionType = monster.EquippedType + + if (unionType == Equipment.Weapon) { + val weapon = monster.equipped(Weapon()) as Weapon // Requires explicit cast + // to `Weapon`. + + val weaponName = weapon.name // "Axe" + val weaponDamage = weapon.damage // 5 + } +~~~ +
~~~{.cs} var unionType = monster.EquippedType; @@ -2816,6 +2978,14 @@ mutators like so: monster.mutateInventory(0, 1); // Set vector element. ~~~
+
+~~~{.kt} + val monster = Monster.getRootAsMonster(buf) + monster.mutateHp(10) // Set table field. + monster.pos!!.mutateZ(4) // Set struct field. + monster.mutateInventory(0, 1) // Set vector element. +~~~ +
~~~{.cs} var monster = Monster.GetRootAsMonster(buf); @@ -2903,9 +3073,9 @@ See the individual language documents for support. If you are working with C, C++, or Lobster, you can parse JSON at runtime. If your language does not support JSON at the moment, `flatc` may provide an -alternative. Using `flatc` is often the preferred method, as it doesn't require you to -add any new code to your program. It is also efficient, since you can ship with -the binary data. The drawback is that it requires an extra step for your +alternative. Using `flatc` is often the preferred method, as it doesn't require you to +add any new code to your program. It is also efficient, since you can ship with +the binary data. The drawback is that it requires an extra step for your users/developers to perform (although it may be able to be automated as part of your compilation). @@ -2979,13 +3149,13 @@ Converting from a FlatBuffer binary representation to JSON is supported as well: ./../flatc --json --raw-binary monster.fbs -- monsterdata.bin ~~~ This will convert `monsterdata.bin` back to its original JSON representation. -You need to pass the corresponding FlatBuffers schema so that flatc knows how to -interpret the binary buffer. Since `monster.fbs` does not specify an explicit -`file_identifier` for binary buffers, `flatc` needs to be forced into reading +You need to pass the corresponding FlatBuffers schema so that flatc knows how to +interpret the binary buffer. Since `monster.fbs` does not specify an explicit +`file_identifier` for binary buffers, `flatc` needs to be forced into reading the `.bin` file using the `--raw-binary` option. -The FlatBuffer binary representation does not explicitly encode default values, -therefore they are not present in the resulting JSON unless you specify +The FlatBuffer binary representation does not explicitly encode default values, +therefore they are not present in the resulting JSON unless you specify `--defaults-json`. If you intend to process the JSON with other tools, you may consider switching @@ -2993,7 +3163,7 @@ on `--strict-json` so that identifiers are quoted properly. *Note: The resulting JSON file is not necessarily identical with the original JSON. If the binary representation contains floating point numbers, floats and doubles -are rounded to 6 and 12 digits, respectively, in order to represent them as +are rounded to 6 and 12 digits, respectively, in order to represent them as decimals in the JSON document. * ## Advanced Features for Each Language @@ -3009,6 +3179,9 @@ For your chosen language, see:
[Use in Java/C#](@ref flatbuffers_guide_use_java_c-sharp)
+
+[Use in Kotlin](@ref flatbuffers_guide_use_kotlin) +
[Use in Java/C#](@ref flatbuffers_guide_use_java_c-sharp)
diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index ae3229d0f..0bcec9102 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -26,7 +26,7 @@ namespace flatbuffers { // Utility class to assist in generating code through use of text templates. // // Example code: -// CodeWriter code; +// CodeWriter code("\t"); // code.SetValue("NAME", "Foo"); // code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }"; // code.SetValue("NAME", "Bar"); @@ -38,7 +38,8 @@ namespace flatbuffers { // void Bar() { printf("%s", "Bar"); } class CodeWriter { public: - CodeWriter() {} + CodeWriter(std::string pad = std::string()) + : pad_(pad), cur_ident_lvl_(0), ignore_ident_(false) {} // Clears the current "written" code. void Clear() { @@ -67,9 +68,22 @@ class CodeWriter { // Returns the current contents of the CodeWriter as a std::string. std::string ToString() const { return stream_.str(); } + // Increase ident level for writing code + void IncrementIdentLevel() { cur_ident_lvl_++; } + // Decrease ident level for writing code + void DecrementIdentLevel() { + if (cur_ident_lvl_) cur_ident_lvl_--; + } + private: std::map value_map_; std::stringstream stream_; + std::string pad_; + int cur_ident_lvl_; + bool ignore_ident_; + + // Add ident padding (tab or space) based on ident level + void AppendIdent(std::stringstream &stream); }; class BaseGenerator { diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 2ec539192..44e35665d 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -47,26 +47,26 @@ namespace flatbuffers { // of type tokens. // clang-format off #define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ - TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8) \ - TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8) /* begin scalar/int */ \ - TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool) \ - TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8) \ - TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8) \ - TD(SHORT, "short", int16_t, short, int16, short, int16, i16) \ - TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16) \ - TD(INT, "int", int32_t, int, int32, int, int32, i32) \ - TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32) \ - TD(LONG, "long", int64_t, long, int64, long, int64, i64) \ - TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64) /* end int */ \ - TD(FLOAT, "float", float, float, float32, float, float32, f32) /* begin float */ \ - TD(DOUBLE, "double", double, double, float64, double, float64, f64) /* end float/scalar */ + TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8, UByte) \ + TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8, UByte) /* begin scalar/int */ \ + TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool, Boolean) \ + TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8, Byte) \ + TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8, UByte) \ + TD(SHORT, "short", int16_t, short, int16, short, int16, i16, Short) \ + TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16, UShort) \ + TD(INT, "int", int32_t, int, int32, int, int32, i32, Int) \ + TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32, UInt) \ + TD(LONG, "long", int64_t, long, int64, long, int64, i64, Long) \ + TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64, ULong) /* end int */ \ + TD(FLOAT, "float", float, float, float32, float, float32, f32, Float) /* begin float */ \ + TD(DOUBLE, "double", double, double, float64, double, float64, f64, Double) /* end float/scalar */ #define FLATBUFFERS_GEN_TYPES_POINTER(TD) \ - TD(STRING, "string", Offset, int, int, StringOffset, int, unused) \ - TD(VECTOR, "", Offset, int, int, VectorOffset, int, unused) \ - TD(STRUCT, "", Offset, int, int, int, int, unused) \ - TD(UNION, "", Offset, int, int, int, int, unused) + TD(STRING, "string", Offset, int, int, StringOffset, int, unused, Int) \ + TD(VECTOR, "", Offset, int, int, VectorOffset, int, unused, Int) \ + TD(STRUCT, "", Offset, int, int, int, int, unused, Int) \ + TD(UNION, "", Offset, int, int, int, int, unused, Int) #define FLATBUFFERS_GEN_TYPE_ARRAY(TD) \ - TD(ARRAY, "", int, int, int, int, int, unused) + TD(ARRAY, "", int, int, int, int, int, unused, Int) // The fields are: // - enum // - FlatBuffers schema type. @@ -76,13 +76,14 @@ namespace flatbuffers { // - C# / .Net type. // - Python type. // - Rust type. +// - Kotlin type. // using these macros, we can now write code dealing with types just once, e.g. /* switch (type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ + RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ // do something specific to CTYPE here FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) @@ -101,14 +102,14 @@ __extension__ // Stop GCC complaining about trailing comma with -Wpendantic. #endif enum BaseType { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ + RTYPE, KTYPE) \ BASE_TYPE_ ## ENUM, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD }; #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ + RTYPE, KTYPE) \ static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \ "define largest_scalar_t as " #CTYPE); FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) @@ -546,6 +547,7 @@ struct IDLOptions { kLua = 1 << 12, kLobster = 1 << 13, kRust = 1 << 14, + kKotlin = 1 << 15, kMAX }; @@ -1009,6 +1011,9 @@ extern bool GenerateJsonSchema(const Parser &parser, const std::string &path, const std::string &file_name); +extern bool GenerateKotlin(const Parser &parser, const std::string &path, + const std::string &file_name); + // Generate Java/C#/.. files from the definitions in the Parser object. // See idl_gen_general.cpp. extern bool GenerateGeneral(const Parser &parser, diff --git a/samples/SampleBinary.kt b/samples/SampleBinary.kt new file mode 100644 index 000000000..2974f36a9 --- /dev/null +++ b/samples/SampleBinary.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2015 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. + */ + +// Run this file with the `java_sample.sh` script. + +import MyGame.Sample.Color +import MyGame.Sample.Equipment +import MyGame.Sample.Monster +import MyGame.Sample.Vec3 +import MyGame.Sample.Weapon + +import com.google.flatbuffers.FlatBufferBuilder + +class SampleBinary { + + companion object { + // Example how to use FlatBuffers to create and read binary buffers. + @JvmStatic + fun main(args: Array) { + val builder = FlatBufferBuilder(0) + + // Create some weapons for our Monster ('Sword' and 'Axe'). + val weaponOneName = builder.createString("Sword") + val weaponOneDamage: Short = 3 + val weaponTwoName = builder.createString("Axe") + val weaponTwoDamage: Short = 5 + + // Use the `createWeapon()` helper function to create the weapons, since we set every field. + val weaps = IntArray(2) + weaps[0] = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage) + weaps[1] = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage) + + // Serialize the FlatBuffer data. + val name = builder.createString("Orc") + val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + val inv = Monster.createInventoryVector(builder, treasure) + val weapons = Monster.createWeaponsVector(builder, weaps) + val pos = Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f) + + Monster.startMonster(builder) + Monster.addPos(builder, pos) + Monster.addName(builder, name) + Monster.addColor(builder, Color.Red) + Monster.addHp(builder, 300.toShort()) + Monster.addInventory(builder, inv) + Monster.addWeapons(builder, weapons) + Monster.addEquippedType(builder, Equipment.Weapon) + Monster.addEquipped(builder, weaps[1]) + val orc = Monster.endMonster(builder) + + builder.finish(orc) // You could also call `Monster.finishMonsterBuffer(builder, orc);`. + + // We now have a FlatBuffer that can be stored on disk or sent over a network. + + // ...Code to store to disk or send over a network goes here... + + // Instead, we are going to access it right away, as if we just received it. + + val buf = builder.dataBuffer() + + // Get access to the root: + val monster = Monster.getRootAsMonster(buf) + + // Note: We did not set the `mana` field explicitly, so we get back the default value. + assert(monster.mana == 150.toShort()) + assert(monster.hp == 300.toShort()) + assert(monster.name.equals("Orc")) + assert(monster.color == Color.Red) + assert(monster.pos!!.x == 1.0f) + assert(monster.pos!!.y == 2.0f) + assert(monster.pos!!.z == 3.0f) + + // Get and test the `inventory` FlatBuffer `vector`. + for (i in 0 until monster.inventoryLength) { + assert(monster.inventory(i) == i.toByte().toInt()) + } + + // Get and test the `weapons` FlatBuffer `vector` of `table`s. + val expectedWeaponNames = arrayOf("Sword", "Axe") + val expectedWeaponDamages = intArrayOf(3, 5) + for (i in 0 until monster.weaponsLength) { + assert(monster.weapons(i)!!.name.equals(expectedWeaponNames[i])) + assert(monster.weapons(i)!!.damage.toInt() == expectedWeaponDamages[i]) + } + + // Get and test the `equipped` FlatBuffer `union`. + assert(monster.equippedType == Equipment.Weapon) + val equipped = monster.equipped(Weapon()) as Weapon? + assert(equipped!!.name.equals("Axe")) + assert(equipped.damage == 5.toShort()) + + println("The FlatBuffer was successfully created and verified!") + } + } +} diff --git a/samples/kotlin_sample.sh b/samples/kotlin_sample.sh new file mode 100755 index 000000000..30ca00a04 --- /dev/null +++ b/samples/kotlin_sample.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright 2015 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: This script runs on Mac and Linux. It requires `kotlin` 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 + +# Run `flatc`. Note: This requires you to compile using `cmake` from the +# root `/flatbuffers` directory. +if [ -e ../flatc ]; then + echo "compiling now" + ../flatc --kotlin --gen-mutable monster.fbs +elif [ -e ../Debug/flatc ]; then + ../Debug/flatc --kotlin --gen-mutable monster.fbs +else + echo 'flatc' could not be found. Make sure to build FlatBuffers from the \ + $rootdir directory. + exit 1 +fi + +echo Compiling and running the Kotlin sample + +all_kt_files=`find $sampledir -name "*.kt" -print` +# Run test +mkdir -v "${sampledir}/kotlin" +echo Compiling Java Runtime +javac ${rootdir}/java/com/google/flatbuffers/*.java -d ${sampledir}/kotlin +echo Compiling Kotlin source +kotlinc -classpath ${sampledir}/../java:${sampledir}/kotlin $all_kt_files SampleBinary.kt -include-runtime -d ${sampledir}/kotlin +# Make jar +echo Making jar +jar cvf ${sampledir}/kotlin/kotlin_sample.jar -C ${sampledir}/kotlin . > /dev/null +echo Running test +kotlin -cp ${sampledir}/kotlin/kotlin_sample.jar SampleBinary + +# Cleanup temporary files. +# rm -rf MyGame/ +# rm -rf ${sampledir}/kotlin diff --git a/src/code_generators.cpp b/src/code_generators.cpp index a3078e025..52ca3056c 100644 --- a/src/code_generators.cpp +++ b/src/code_generators.cpp @@ -29,6 +29,8 @@ namespace flatbuffers { void CodeWriter::operator+=(std::string text) { + if (!ignore_ident_ && !text.empty()) AppendIdent(stream_); + while (true) { auto begin = text.find("{{"); if (begin == std::string::npos) { break; } @@ -58,12 +60,21 @@ void CodeWriter::operator+=(std::string text) { } if (!text.empty() && string_back(text) == '\\') { text.pop_back(); + ignore_ident_ = true; stream_ << text; } else { + ignore_ident_ = false; stream_ << text << std::endl; } } +void CodeWriter::AppendIdent(std::stringstream &stream) { + int lvl = cur_ident_lvl_; + while (lvl--) { + stream.write(pad_.c_str(), static_cast(pad_.size())); + } +} + const char *BaseGenerator::FlatBuffersGeneratedWarning() { return "automatically generated by the FlatBuffers compiler," " do not modify"; diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp index 9dfe81ce2..72bb4a2f0 100644 --- a/src/flatc_main.cpp +++ b/src/flatc_main.cpp @@ -90,6 +90,9 @@ int main(int argc, const char *argv[]) { { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr, flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs", flatbuffers::GeneralMakeRule }, + { flatbuffers::GenerateKotlin, nullptr, "--kotlin", "Kotlin", true, nullptr, + flatbuffers::IDLOptions::kKotlin, "Generate Kotlin classes for tables/structs", + flatbuffers::GeneralMakeRule }, { flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema", true, nullptr, flatbuffers::IDLOptions::kJsonSchema, "Generate Json schema", flatbuffers::GeneralMakeRule }, diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 322b7f5ff..2294de9ff 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -538,7 +538,7 @@ class CppGenerator : public BaseGenerator { // clang-format off static const char *const ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ + RTYPE, KTYPE) \ #CTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 5f41e5aa1..8dca79299 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -258,7 +258,7 @@ class GeneralGenerator : public BaseGenerator { // clang-format off static const char * const java_typename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #JTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -266,7 +266,7 @@ class GeneralGenerator : public BaseGenerator { static const char * const csharp_typename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #NTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 80ce1925a..5e62b6170 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -827,7 +827,7 @@ class GoGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #GTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp new file mode 100644 index 000000000..3ced7b374 --- /dev/null +++ b/src/idl_gen_kotlin.cpp @@ -0,0 +1,1527 @@ +/* + * Copyright 2014 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. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include +#include +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" +#if defined(FLATBUFFERS_CPP98_STL) +#include +#endif // defined(FLATBUFFERS_CPP98_STL) + +namespace flatbuffers { + +namespace kotlin { + +typedef std::map > FbbParamMap; +static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN", + "POSITIVE_INFINITY", + "NEGATIVE_INFINITY"); + +static const CommentConfig comment_config = {"/**", " *", " */"}; +static const std::string ident_pad = " "; +static const char *keywords[] = { + "package", "as", "typealias", "class", "this", "super", + "val", "var", "fun", "for", "null", "true", + "false", "is", "in", "throw", "return", "break", + "continue", "object", "if", "try", "else", "while", + "do", "when", "interface", "typeof", "Any", "Character"}; + +// Escape Keywords +static std::string Esc(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); +} + +class KotlinGenerator : public BaseGenerator { + public: + KotlinGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "."), + cur_name_space_(nullptr) {} + + KotlinGenerator &operator=(const KotlinGenerator &); + bool generate() FLATBUFFERS_OVERRIDE { + std::string one_file_code; + + cur_name_space_ = parser_.current_namespace_; + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + CodeWriter enumWriter(ident_pad); + auto &enum_def = **it; + if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace; + GenEnum(enum_def, enumWriter); + if (parser_.opts.one_file) { + one_file_code += enumWriter.ToString(); + } else { + if (!SaveType(enum_def.name, *enum_def.defined_namespace, + enumWriter.ToString(), false)) + return false; + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + CodeWriter structWriter(ident_pad); + auto &struct_def = **it; + if (!parser_.opts.one_file) + cur_name_space_ = struct_def.defined_namespace; + GenStruct(struct_def, structWriter); + if (parser_.opts.one_file) { + one_file_code += structWriter.ToString(); + } else { + if (!SaveType(struct_def.name, *struct_def.defined_namespace, + structWriter.ToString(), true)) + return false; + } + } + + if (parser_.opts.one_file) { + return SaveType(file_name_, *parser_.current_namespace_, one_file_code, + true); + } + return true; + } + + // Save out the generated code for a single class while adding + // declaration boilerplate. + bool SaveType(const std::string &defname, const Namespace &ns, + const std::string &classcode, bool needs_includes) const { + if (!classcode.length()) return true; + + std::string code = + "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + std::string namespace_name = FullNamespace(".", ns); + if (!namespace_name.empty()) { + code += "package " + namespace_name; + code += "\n\n"; + } + if (needs_includes) { + code += "import java.nio.*\n"; + code += "import kotlin.math.sign\n"; + code += "import com.google.flatbuffers.*\n\n"; + } + code += classcode; + auto filename = NamespaceDir(ns) + defname + ".kt"; + return SaveFile(filename.c_str(), code, false); + } + + const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE { + return cur_name_space_; + } + + static bool IsEnum(const Type &type) { + return type.enum_def != nullptr && IsInteger(type.base_type); + } + + static std::string GenTypeBasic(const BaseType &type) { + // clang-format off + static const char * const kotlin_typename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ + #KTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + return kotlin_typename[type]; + + } + + std::string GenTypePointer(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: + return "String"; + case BASE_TYPE_VECTOR: + return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: + return WrapInNameSpace(*type.struct_def); + default: + return "Table"; + } + } + + std::string GenTypeGet(const Type &type) const { + return IsScalar(type.base_type) ? GenTypeBasic(type.base_type) + : GenTypePointer(type); + } + + std::string GenEnumDefaultValue(const FieldDef &field) const { + auto &value = field.value; + FLATBUFFERS_ASSERT(value.type.enum_def); + auto &enum_def = *value.type.enum_def; + auto enum_val = enum_def.FindByValue(value.constant); + return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name) + : value.constant; + } + + + // Generate default values to compare against a default value when + // `force_defaults` is `false`. + // Main differences are: + // - Floats are upcasted to doubles + // - Unsigned are casted to signed + std::string GenFBBDefaultValue(const FieldDef &field) const { + auto out = GenDefaultValue(field, true); + // All FlatBufferBuilder default floating point values are doubles + if (field.value.type.base_type == BASE_TYPE_FLOAT) { + if (out.find("Float") != std::string::npos) { + out.replace(0, 5, "Double"); + } + } + //Guarantee all values are doubles + if (out.back() == 'f') + out.pop_back(); + return out; + } + + + // FlatBufferBuilder only store signed types, so this function + // returns a cast for unsigned values + std::string GenFBBValueCast(const FieldDef &field) const { + if (IsUnsigned(field.value.type.base_type)) { + return CastToSigned(field.value.type); + } + return ""; + } + + std::string GenDefaultValue(const FieldDef &field, + bool force_signed = false) const { + auto &value = field.value; + auto base_type = field.value.type.base_type; + if (IsFloat(base_type)) { + auto val = KotlinFloatGen.GenFloatConstant(field); + if (base_type == BASE_TYPE_DOUBLE && + val.back() == 'f') { + val.pop_back(); + } + return val; + } + + if (base_type == BASE_TYPE_BOOL) { + return value.constant == "0" ? "false" : "true"; + } + + std::string suffix = ""; + + if (base_type == BASE_TYPE_LONG || !force_signed) { + suffix = LiteralSuffix(base_type); + } + return value.constant + suffix; + } + + void GenEnum(EnumDef &enum_def, CodeWriter &writer) const { + if (enum_def.generated) return; + + GenerateComment(enum_def.doc_comment, writer, &comment_config); + + writer += "@Suppress(\"unused\")"; + writer += "@ExperimentalUnsignedTypes"; + writer += "class " + Esc(enum_def.name) + " private constructor() {"; + writer.IncrementIdentLevel(); + + GenerateCompanionObject(writer, [&](){ + // Write all properties + auto vals = enum_def.Vals(); + for (auto it = vals.begin(); it != vals.end(); ++it) { + auto &ev = **it; + auto field_type = GenTypeBasic(enum_def.underlying_type.base_type); + auto val = enum_def.ToString(ev); + auto suffix = LiteralSuffix(enum_def.underlying_type.base_type); + writer.SetValue("name", Esc(ev.name)); + writer.SetValue("type", field_type); + writer.SetValue("val", val + suffix); + GenerateComment(ev.doc_comment, writer, &comment_config); + writer += "const val {{name}}: {{type}} = {{val}}"; + } + + // Generate a generate string table for enum values. + // Problem is, if values are very sparse that could generate really + // big tables. Ideally in that case we generate a map lookup + // instead, but for the moment we simply don't output a table at all. + auto range = enum_def.Distance(); + // Average distance between values above which we consider a table + // "too sparse". Change at will. + static const uint64_t kMaxSparseness = 5; + if (range / static_cast(enum_def.size()) < kMaxSparseness) { + GeneratePropertyOneLine(writer, "names", "Array", + [&](){ + writer += "arrayOf(\\"; + auto val = enum_def.Vals().front(); + for (auto it = vals.begin(); it != vals.end(); ++it) { + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) + writer += "\"\", \\"; + val = ev; + writer += "\"" + (*it)->name + "\"\\"; + if (it+1 != vals.end()) { + writer += ", \\"; + } + } + writer += ")"; + }); + GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){ + writer += "names[e\\"; + if (enum_def.MinValue()->IsNonZero()) + writer += " - " + enum_def.MinValue()->name + ".toInt()\\"; + writer += "]"; + }); + } + }); + writer.DecrementIdentLevel(); + writer += "}"; + } + + // Returns the function name that is able to read a value of the given type. + std::string ByteBufferGetter(const Type &type, std::string bb_var_name) const { + switch (type.base_type) { + case BASE_TYPE_STRING: + return "__string"; + case BASE_TYPE_STRUCT: + return "__struct"; + case BASE_TYPE_UNION: + return "__union"; + case BASE_TYPE_VECTOR: + return ByteBufferGetter(type.VectorType(), bb_var_name); + case BASE_TYPE_INT: + case BASE_TYPE_UINT: + return bb_var_name + ".getInt"; + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: + return bb_var_name + ".getShort"; + case BASE_TYPE_ULONG: + case BASE_TYPE_LONG: + return bb_var_name + ".getLong"; + case BASE_TYPE_FLOAT: + return bb_var_name + ".getFloat"; + case BASE_TYPE_DOUBLE: + return bb_var_name + ".getDouble"; + case BASE_TYPE_CHAR: + case BASE_TYPE_UCHAR: + case BASE_TYPE_NONE: + case BASE_TYPE_UTYPE: + return bb_var_name + ".get"; + case BASE_TYPE_BOOL: + return "0.toByte() != " + bb_var_name + ".get"; + default: + return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type)); + } + } + + std::string ByteBufferSetter(const Type &type) const { + if (IsScalar(type.base_type)) { + switch (type.base_type) { + case BASE_TYPE_INT: + case BASE_TYPE_UINT: + return "bb.putInt"; + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: + return "bb.putShort"; + case BASE_TYPE_ULONG: + case BASE_TYPE_LONG: + return "bb.putLong"; + case BASE_TYPE_FLOAT: + return "bb.putFloat"; + case BASE_TYPE_DOUBLE: + return "bb.putDouble"; + case BASE_TYPE_CHAR: + case BASE_TYPE_UCHAR: + case BASE_TYPE_BOOL: + case BASE_TYPE_NONE: + case BASE_TYPE_UTYPE: + return "bb.put"; + default: + return "bb.put" + MakeCamel(GenTypeBasic(type.base_type)); + } + } + return ""; + } + + // Returns the function name that is able to read a value of the given type. + std::string GenLookupByKey(flatbuffers::FieldDef *key_field, + const std::string &bb_var_name, + const char *num = nullptr) const { + auto type = key_field->value.type; + return ByteBufferGetter(type, bb_var_name) + "(" + GenOffsetGetter(key_field, num) + ")"; + + } + + // Returns the method name for use with add/put calls. + static std::string GenMethod(const Type &type) { + return IsScalar(type.base_type) ? ToSignedType(type) + : (IsStruct(type) ? "Struct" : "Offset"); + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer, + const char *nameprefix) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure + // names don't clash, and to make it obvious these arguments are + // constructing a nested struct, prefix the name with the field + // name. + GenStructArgs(*field.value.type.struct_def, writer, + (nameprefix + (field.name + "_")).c_str()); + } else { + writer += std::string(", ") + nameprefix + "\\"; + writer += MakeCamel(field.name) + ": \\"; + writer += GenTypeBasic(field.value.type.base_type) + "\\"; + } + } + } + + // Recusively generate struct construction statements of the form: + // builder.putType(name); + // and insert manual padding. + static void GenStructBody(const StructDef &struct_def, CodeWriter &writer, + const char *nameprefix) { + writer.SetValue("align", NumToString(struct_def.minalign)); + writer.SetValue("size", NumToString(struct_def.bytesize)); + writer += "builder.prep({{align}}, {{size}})"; + auto fields_vec = struct_def.fields.vec; + for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) { + auto &field = **it; + + if (field.padding) { + writer.SetValue("pad", NumToString(field.padding)); + writer += "builder.pad({{pad}})"; + } + if (IsStruct(field.value.type)) { + GenStructBody(*field.value.type.struct_def, writer, + (nameprefix + (field.name + "_")).c_str()); + } else { + writer.SetValue("type", GenMethod(field.value.type)); + writer.SetValue("argname", nameprefix + + MakeCamel(field.name, false)); + writer.SetValue("cast", CastToSigned(field.value.type)); + writer += "builder.put{{type}}({{argname}}{{cast}})"; + } + } + } + + std::string GenByteBufferLength(const char *bb_name) const { + std::string bb_len = bb_name; + bb_len += ".capacity()"; + return bb_len; + } + + std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, + const char *num = nullptr) const { + std::string key_offset = "__offset(" + + NumToString(key_field->value.offset) + ", "; + if (num) { + key_offset += num; + key_offset += ", _bb)"; + } else { + key_offset += GenByteBufferLength("bb"); + key_offset += " - tableOffset, bb)"; + } + return key_offset; + } + + void GenStruct(StructDef &struct_def, CodeWriter &writer) const { + if (struct_def.generated) return; + + GenerateComment(struct_def.doc_comment, writer, &comment_config); + auto fixed = struct_def.fixed; + + writer.SetValue("struct_name", Esc(struct_def.name)); + writer.SetValue("superclass", fixed ? "Struct" : "Table"); + + writer += "@Suppress(\"unused\")"; + writer += "@ExperimentalUnsignedTypes"; + writer += "class {{struct_name}} : {{superclass}}() {\n"; + + writer.IncrementIdentLevel(); + + { + // Generate the __init() method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", [&]() { + writer += "__reset(_i, _bb)"; + }); + + // Generate assign method + GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer", + Esc(struct_def.name), [&]() { + writer += "__init(_i, _bb)"; + writer += "return this"; + }); + + // Generate all getters + GenerateStructGetters(struct_def, writer); + + // Generate Static Fields + GenerateCompanionObject(writer, [&](){ + + if (!struct_def.fixed) { + FieldDef *key_field = nullptr; + + // Generate verson check method. + // Force compile time error if not using the same version + // runtime. + GenerateFunOneLine(writer, "validateVersion", "", "", [&](){ + writer += "Constants.FLATBUFFERS_1_11_1()"; + }); + + GenerateGetRootAsAccessors(Esc(struct_def.name), writer); + GenerateBufferHasIdentifier(struct_def, writer); + GenerateTableCreator(struct_def, writer); + + GenerateStartStructMethod(struct_def, writer); + + // Static Add for fields + auto fields = struct_def.fields.vec; + int field_pos = -1; + for (auto it = fields.begin(); it != fields.end(); ++it) { + auto &field = **it; + field_pos++; + if (field.deprecated) continue; + if (field.key) key_field = &field; + GenerateAddField(NumToString(field_pos), field, writer); + + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + auto vector_type = field.value.type.VectorType(); + if (!IsStruct(vector_type)) { + GenerateCreateVectorField(field, writer); + } + GenerateStartVectorField(field, writer); + } + } + + GenerateEndStructMethod(struct_def, writer); + auto file_identifier = parser_.file_identifier_; + if (parser_.root_struct_def_ == &struct_def) { + GenerateFinishStructBuffer(struct_def, + file_identifier, + writer); + GenerateFinishSizePrefixed(struct_def, + file_identifier, + writer); + } + + if (struct_def.has_key) { + GenerateLookupByKey(key_field, struct_def, writer); + } + } else { + GenerateStaticConstructor(struct_def, writer); + } + }); + } + + // class closing + writer.DecrementIdentLevel(); + writer += "}"; + } + + // TODO: move key_field to reference instead of pointer + void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def, + CodeWriter &writer) const { + std::stringstream params; + params << "obj: " << Esc(struct_def.name) << "?" << ", "; + params << "vectorLocation: Int, "; + params << "key: " << GenTypeGet(key_field->value.type) << ", "; + params << "bb: ByteBuffer"; + + auto statements = [&]() { + auto base_type = key_field->value.type.base_type; + writer.SetValue("struct_name", Esc(struct_def.name)); + if (base_type == BASE_TYPE_STRING) { + writer += "val byteKey = key." + "toByteArray(Table.UTF8_CHARSET.get()!!)"; + } + writer += "var span = bb.getInt(vectorLocation - 4)"; + writer += "var start = 0"; + writer += "while (span != 0) {"; + writer.IncrementIdentLevel(); + writer += "var middle = span / 2"; + writer += "val tableOffset = __indirect(vector" + "Location + 4 * (start + middle), bb)"; + if (key_field->value.type.base_type == BASE_TYPE_STRING) { + writer += "val comp = compareStrings(\\"; + writer += GenOffsetGetter(key_field) + "\\"; + writer += ", byteKey, bb)"; + } else { + auto cast = CastToUsigned(key_field->value.type); + auto get_val = GenLookupByKey(key_field, "bb"); + writer += "val value = " + get_val + cast; + writer += "val comp = value.compareTo(key)"; + } + writer += "when {"; + writer.IncrementIdentLevel(); + writer += "comp > 0 -> span = middle"; + writer += "comp < 0 -> {"; + writer.IncrementIdentLevel(); + writer += "middle++"; + writer += "start += middle"; + writer += "span -= middle"; + writer.DecrementIdentLevel(); + writer += "}"; // end comp < 0 + writer += "else -> {"; + writer.IncrementIdentLevel(); + writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)"; + writer.DecrementIdentLevel(); + writer += "}"; // end else + writer.DecrementIdentLevel(); + writer += "}"; // end when + writer.DecrementIdentLevel(); + writer += "}"; // end while + writer += "return null"; + }; + GenerateFun(writer, "__lookup_by_key", + params.str(), + Esc(struct_def.name) + "?", + statements); + } + + void GenerateFinishSizePrefixed(StructDef &struct_def, + const std::string &identifier, + CodeWriter &writer) const { + auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : ""; + auto params = "builder: FlatBufferBuilder, offset: Int"; + auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer"; + GenerateFunOneLine(writer, method_name, params, "", [&]() { + writer += "builder.finishSizePrefixed(offset" + id + ")"; + }); + } + void GenerateFinishStructBuffer(StructDef &struct_def, + const std::string &identifier, + CodeWriter &writer) const { + auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : ""; + auto params = "builder: FlatBufferBuilder, offset: Int"; + auto method_name = "finish" + Esc(struct_def.name) + "Buffer"; + GenerateFunOneLine(writer, method_name, params, "", [&]() { + writer += "builder.finish(offset" + id + ")"; + }); + } + + void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer) const { + // Generate end{{TableName}}(builder: FlatBufferBuilder) method + auto name = "end" + Esc(struct_def.name); + auto params = "builder: FlatBufferBuilder"; + auto returns = "Int"; + auto field_vec = struct_def.fields.vec; + + GenerateFun(writer, name, params, returns, [&](){ + writer += "val o = builder.endTable()"; + writer.IncrementIdentLevel(); + for (auto it = field_vec.begin(); it != field_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated || !field.required) { + continue; + } + writer.SetValue("offset", NumToString(field.value.offset)); + writer += "builder.required(o, {{offset}})"; + } + writer.DecrementIdentLevel(); + writer += "return o"; + }); + } + + // Generate a method to create a vector from a Kotlin array. + void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer) const { + auto vector_type = field.value.type.VectorType(); + auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector"; + auto params = "builder: FlatBufferBuilder, data: " + + GenTypeBasic(vector_type.base_type) + "Array"; + writer.SetValue("size", NumToString(InlineSize(vector_type))); + writer.SetValue("align", NumToString(InlineAlignment(vector_type))); + writer.SetValue("root", GenMethod(vector_type)); + writer.SetValue("cast", CastToSigned(vector_type)); + + GenerateFun(writer, method_name, params, "Int", [&](){ + writer += "builder.startVector({{size}}, data.size, {{align}})"; + writer += "for (i in data.size - 1 downTo 0) {"; + writer.IncrementIdentLevel(); + writer += "builder.add{{root}}(data[i]{{cast}})"; + writer.DecrementIdentLevel(); + writer += "}"; + writer += "return builder.endVector()"; + }); + } + + void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const { + // Generate a method to start a vector, data to be added manually + // after. + auto vector_type = field.value.type.VectorType(); + auto params = "builder: FlatBufferBuilder, numElems: Int"; + writer.SetValue("size", NumToString(InlineSize(vector_type))); + writer.SetValue("align", NumToString(InlineAlignment(vector_type))); + + GenerateFunOneLine(writer, + "start" + MakeCamel(Esc(field.name) + "Vector", true), + params, + "", + [&]() { + writer += "builder.startVector({{size}}, numElems, {{align}})"; + }); + } + + void GenerateAddField(std::string field_pos, FieldDef &field, + CodeWriter &writer) const { + auto field_type = GenTypeBasic(field.value.type.base_type); + auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type; + GenerateFunOneLine(writer, "add" + MakeCamel(Esc(field.name), true), + "builder: FlatBufferBuilder, " + secondArg, "", [&](){ + auto method = GenMethod(field.value.type); + writer.SetValue("field_name", MakeCamel(Esc(field.name), false)); + writer.SetValue("method_name", method); + writer.SetValue("pos", field_pos); + writer.SetValue("default", GenFBBDefaultValue(field)); + writer.SetValue("cast", GenFBBValueCast(field)); + + writer += "builder.add{{method_name}}({{pos}}, \\"; + writer += "{{field_name}}{{cast}}, {{default}})"; + }); + } + + static std::string ToSignedType(const Type & type) { + switch(type.base_type) { + case BASE_TYPE_UINT: + return GenTypeBasic(BASE_TYPE_INT); + case BASE_TYPE_ULONG: + return GenTypeBasic(BASE_TYPE_LONG); + case BASE_TYPE_UCHAR: + case BASE_TYPE_NONE: + case BASE_TYPE_UTYPE: + return GenTypeBasic(BASE_TYPE_CHAR); + case BASE_TYPE_USHORT: + return GenTypeBasic(BASE_TYPE_SHORT); + case BASE_TYPE_VECTOR: + return ToSignedType(type.VectorType()); + default: + return GenTypeBasic(type.base_type); + } + } + + static std::string FlexBufferBuilderCast(const std::string &method, + FieldDef &field, + bool isFirst) { + auto field_type = GenTypeBasic(field.value.type.base_type); + std::string to_type; + if (method == "Boolean") + to_type = "Boolean"; + else if (method == "Long") + to_type = "Long"; + else if (method == "Int" || method == "Offset" || method == "Struct") + to_type = "Int"; + else if (method == "Byte" || method.empty()) + to_type = isFirst ? "Byte" : "Int"; + else if (method == "Short") + to_type = isFirst ? "Short" : "Int"; + else if (method == "Double") + to_type = "Double"; + else if (method == "Float") + to_type = isFirst ? "Float" : "Double"; + else if (method == "UByte") + + if (field_type != to_type) + return ".to" + to_type + "()"; + return ""; + } + + // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11) + void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code) const { + GenerateFunOneLine(code, "start" + Esc(struct_def.name), + "builder: FlatBufferBuilder", "", [&] () { + code += "builder.startTable("+ NumToString(struct_def.fields.vec.size()) + ")"; + }); + } + + void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer) const { + // Generate a method that creates a table in one go. This is only possible + // when the table has no struct fields, since those have to be created + // inline, and there's no way to do so in Java. + bool has_no_struct_fields = true; + int num_fields = 0; + auto fields_vec = struct_def.fields.vec; + + for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (IsStruct(field.value.type)) { + has_no_struct_fields = false; + } else { + num_fields++; + } + } + // JVM specifications restrict default constructor params to be < 255. + // Longs and doubles take up 2 units, so we set the limit to be < 127. + if (has_no_struct_fields && num_fields && num_fields < 127) { + // Generate a table constructor of the form: + // public static int createName(FlatBufferBuilder builder, args...) + + auto name = "create" + Esc(struct_def.name); + std::stringstream params; + params << "builder: FlatBufferBuilder"; + for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + params << ", " << MakeCamel(Esc(field.name), false); + if (!IsScalar(field.value.type.base_type)){ + params << "Offset: "; + } else { + params << ": "; + } + params << GenTypeBasic(field.value.type.base_type); + } + + GenerateFun(writer, name, params.str(), "Int", [&]() { + writer.SetValue("vec_size", NumToString(fields_vec.size())); + + writer += "builder.startTable({{vec_size}})"; + + auto sortbysize = struct_def.sortbysize; + auto largest = sortbysize ? sizeof(largest_scalar_t) : 1; + for (size_t size = largest; size; size /= 2) { + for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); + ++it) { + auto &field = **it; + auto base_type_size = SizeOf(field.value.type.base_type); + if (!field.deprecated && + (!sortbysize || size == base_type_size)) { + writer.SetValue("camel_field_name", + MakeCamel(Esc(field.name), true)); + writer.SetValue("field_name", + MakeCamel(Esc(field.name), false)); + + writer += "add{{camel_field_name}}(builder, {{field_name}}\\"; + if (!IsScalar(field.value.type.base_type)){ + writer += "Offset\\"; + } + writer += ")"; + } + } + } + writer += "return end{{struct_name}}(builder)"; + }); + } + + } + void GenerateBufferHasIdentifier(StructDef &struct_def, + CodeWriter &writer) const { + auto file_identifier = parser_.file_identifier_; + // Check if a buffer has the identifier. + if (parser_.root_struct_def_ != &struct_def || !file_identifier.length()) + return; + auto name = MakeCamel(Esc(struct_def.name), false); + GenerateFunOneLine(writer, name + "BufferHasIdentifier", + "_bb: ByteBuffer", + "Boolean", + [&]() { + writer += "__has_identifier(_bb, \"" + file_identifier + "\")"; + }); + } + + void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const { + auto fields_vec = struct_def.fields.vec; + FieldDef *key_field = nullptr; + for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.key) key_field = &field; + + GenerateComment(field.doc_comment, writer, &comment_config); + + auto field_name = MakeCamel(Esc(field.name), false); + auto field_type = GenTypeGet(field.value.type); + auto field_default_value = GenDefaultValue(field); + auto return_type = GenTypeGet(field.value.type); + auto bbgetter = ByteBufferGetter(field.value.type, "bb"); + auto ucast = CastToUsigned(field); + auto offset_val = NumToString(field.value.offset); + auto offset_prefix = "val o = __offset(" + offset_val + + "); return o != 0 ? "; + auto value_base_type = field.value.type.base_type; + // Most field accessors need to retrieve and test the field offset + // first, this is the offset value for that: + writer.SetValue("offset", NumToString(field.value.offset)); + writer.SetValue("return_type", return_type); + writer.SetValue("field_type", field_type); + writer.SetValue("field_name", field_name); + writer.SetValue("field_default", field_default_value); + writer.SetValue("bbgetter", bbgetter); + writer.SetValue("ucast", ucast); + + auto opt_ret_type = return_type + "?"; + // Generate the accessors that don't do object reuse. + if (value_base_type == BASE_TYPE_STRUCT) { + // Calls the accessor that takes an accessor object with a + // new object. + // val pos + // get() = pos(Vec3()) + GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){ + writer += "{{field_name}}({{field_type}}())"; + }); + } else if (value_base_type == BASE_TYPE_VECTOR && + field.value.type.element == BASE_TYPE_STRUCT) { + // Accessors for vectors of structs also take accessor objects, + // this generates a variant without that argument. + // ex: fun weapons(j: Int) = weapons(Weapon(), j) + GenerateFunOneLine(writer, field_name, "j: Int", opt_ret_type, [&](){ + writer += "{{field_name}}({{return_type}}(), j)"; + }); + } + + if (IsScalar(value_base_type)) { + if (struct_def.fixed) { + GenerateGetterOneLine(writer, field_name, return_type, [&](){ + writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}"; + }); + } else { + GenerateGetter(writer, field_name, return_type, [&](){ + writer += "val o = __offset({{offset}})"; + writer += "return if(o != 0) {{bbgetter}}" + "(o + bb_pos){{ucast}} else " + "{{field_default}}"; + }); + } + } else { + switch (value_base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + // create getter with object reuse + // ex: + // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb) + // ? adds nullability annotation + GenerateFunOneLine(writer, + field_name, "obj: " + field_type , + return_type + "?", [&](){ + writer += "obj.__assign(bb_pos + {{offset}}, bb)"; + }); + } else { + // create getter with object reuse + // ex: + // fun pos(obj: Vec3) : Vec3? { + // val o = __offset(4) + // return if(o != 0) { + // obj.__assign(o + bb_pos, bb) + // else { + // null + // } + // } + // ? adds nullability annotation + GenerateFun(writer, field_name, "obj: " + field_type, + return_type + "?", [&](){ + auto fixed = field.value.type.struct_def->fixed; + + writer.SetValue("seek", Indirect("o + bb_pos", fixed)); + OffsetWrapper(writer, + offset_val, + [&]() { writer += "obj.__assign({{seek}}, bb)"; }, + [&]() { writer += "null"; }); + }); + } + break; + case BASE_TYPE_STRING: + // create string getter + // e.g. + // val Name : String? + // get() = { + // val o = __offset(10) + // return if (o != 0) __string(o + bb_pos) else null + // } + // ? adds nullability annotation + GenerateGetter(writer, field_name, return_type + "?", [&](){ + + writer += "val o = __offset({{offset}})"; + writer += "return if (o != 0) __string(o + bb_pos) else null"; + }); + break; + case BASE_TYPE_VECTOR: { + // e.g. + // fun inventory(j: Int) : UByte { + // val o = __offset(14) + // return if (o != 0) { + // bb.get(__vector(o) + j * 1).toUByte() + // } else { + // 0 + // } + // } + + auto vectortype = field.value.type.VectorType(); + std::string params = "j: Int"; + std::string nullable = IsScalar(vectortype.base_type) ? "" + : "?"; + + if (vectortype.base_type == BASE_TYPE_STRUCT || + vectortype.base_type == BASE_TYPE_UNION) { + params = "obj: " + field_type + ", j: Int"; + } + + + writer.SetValue("toType", "YYYYY"); + + auto ret_type = return_type + nullable; + GenerateFun(writer, field_name, params, ret_type, [&](){ + auto inline_size = NumToString(InlineSize(vectortype)); + auto index = "__vector(o) + j * " + inline_size; + auto not_found = NotFoundReturn(field.value.type.element); + auto found = ""; + writer.SetValue("index", index); + switch(vectortype.base_type) { + case BASE_TYPE_STRUCT: { + bool fixed = vectortype.struct_def->fixed; + writer.SetValue("index", Indirect(index, fixed)); + found = "obj.__assign({{index}}, bb)"; + break; + } + case BASE_TYPE_UNION: + found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}"; + break; + default: + found = "{{bbgetter}}({{index}}){{ucast}}"; + } + OffsetWrapper(writer, offset_val, + [&]() { writer += found; } , + [&]() { writer += not_found; }); + }); + break; + } + case BASE_TYPE_UNION: + GenerateFun(writer, field_name, "obj: " + field_type, + return_type + "?", [&](){ + writer += OffsetWrapperOneLine(offset_val, + bbgetter + "(obj, o)", + "null"); + }); + break; + default: + FLATBUFFERS_ASSERT(0); + } + } + + if (value_base_type == BASE_TYPE_VECTOR) { + // Generate Lenght functions for vectors + GenerateGetter(writer, field_name + "Length", "Int", [&](){ + writer += OffsetWrapperOneLine(offset_val, + "__vector_len(o)", "0"); + }); + + // See if we should generate a by-key accessor. + if (field.value.type.element == BASE_TYPE_STRUCT && + !field.value.type.struct_def->fixed) { + auto &sd = *field.value.type.struct_def; + auto &fields = sd.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &kfield = **kit; + if (kfield.key) { + auto qualified_name = WrapInNameSpace(sd); + auto name = MakeCamel(Esc(field.name), false) + "ByKey"; + auto params = "key: " + GenTypeGet(kfield.value.type); + auto rtype = qualified_name + "?"; + GenerateFun(writer, name, params, rtype, [&] () { + OffsetWrapper(writer, offset_val, + [&] () { + writer += qualified_name + + ".__lookup_by_key(null, __vector(o), key, bb)"; + }, + [&] () { + writer += "null"; + }); + }); + + auto param2 = "obj: " + qualified_name + + ", key: " + + GenTypeGet(kfield.value.type); + GenerateFun(writer, name, param2, rtype, [&](){ + OffsetWrapper(writer, offset_val, + [&] () { + writer += qualified_name + + ".__lookup_by_key(obj, __vector(o), key, bb)"; + }, + [&]() { writer += "null"; }); + }); + + break; + } + } + } + } + + if ((value_base_type == BASE_TYPE_VECTOR && + IsScalar(field.value.type.VectorType().base_type)) || + value_base_type == BASE_TYPE_STRING) { + + auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING + ? 1 + : InlineSize(field.value.type.VectorType())); + // Generate a ByteBuffer accessor for strings & vectors of scalars. + // e.g. + // val inventoryByteBuffer: ByteBuffer + // get = __vector_as_bytebuffer(14, 1) + + GenerateGetterOneLine(writer, field_name + "AsByteBuffer", + "ByteBuffer", [&](){ + writer.SetValue("end", end_idx); + writer += "__vector_as_bytebuffer({{offset}}, {{end}})"; + }); + + // Generate a ByteBuffer accessor for strings & vectors of scalars. + // e.g. + // fun inventoryInByteBuffer(_bb: Bytebuffer): + // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1) + GenerateFunOneLine(writer, field_name + "InByteBuffer", + "_bb: ByteBuffer", "ByteBuffer", [&](){ + writer.SetValue("end", end_idx); + writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})"; + }); + } + + // generate object accessors if is nested_flatbuffer + //fun testnestedflatbufferAsMonster() : Monster? + //{ return testnestedflatbufferAsMonster(new Monster()); } + + if (field.nested_flatbuffer) { + auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer); + auto nested_method_name = + field_name + "As" + + field.nested_flatbuffer->name; + + GenerateGetterOneLine(writer, + nested_method_name, + nested_type_name + "?", [&](){ + writer += nested_method_name + "(" + nested_type_name + "())"; + }); + + GenerateFun(writer, + nested_method_name, + "obj: " + nested_type_name, + nested_type_name + "?", [&](){ + OffsetWrapper(writer, offset_val, + [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; }, + [&]() { writer += "null";}); + }); + } + + // Generate mutators for scalar fields or vectors of scalars. + if (parser_.opts.mutable_buffer) { + auto value_type = field.value.type; + auto underlying_type = value_base_type == BASE_TYPE_VECTOR + ? value_type.VectorType() + : value_type; + auto name = "mutate" + MakeCamel(Esc(field.name), true); + auto size = NumToString(InlineSize(underlying_type)); + auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type); + // A vector mutator also needs the index of the vector element it should + // mutate. + if (value_base_type == BASE_TYPE_VECTOR) + params.insert(0, "j: Int, "); + + // Boolean parameters have to be explicitly converted to byte + // representation. + auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL + ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()" + : Esc(field.name); + + auto setter_index = value_base_type == BASE_TYPE_VECTOR + ? "__vector(o) + j * " + size + : (struct_def.fixed + ? "bb_pos + " + offset_val + : "o + bb_pos"); + if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR && + IsScalar(value_type.VectorType().base_type))) { + + auto statements = [&] () { + writer.SetValue("bbsetter", ByteBufferSetter(underlying_type)); + writer.SetValue("index", setter_index); + writer.SetValue("params", setter_parameter); + writer.SetValue("cast", CastToSigned(field)); + if (struct_def.fixed) { + writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})"; + } else { + OffsetWrapper(writer, offset_val, [&](){ + writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})"; + writer += "true"; + }, [&](){ writer += "false";}); + } + }; + + if (struct_def.fixed) { + GenerateFunOneLine(writer, name, params, "ByteBuffer", + statements); + } else { + GenerateFun(writer, name, params, "Boolean", + statements); + } + } + } + } + if (struct_def.has_key && !struct_def.fixed) { + // Key Comparison method + GenerateOverrideFun( + writer, + "keysCompare", + "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() { + if (key_field->value.type.base_type == BASE_TYPE_STRING) { + writer.SetValue("offset", NumToString(key_field->value.offset)); + writer += " return compareStrings(__offset({{offset}}, o1, " + "_bb), __offset({{offset}}, o2, _bb), _bb)"; + + } else { + auto getter1 = GenLookupByKey(key_field, "_bb", "o1"); + auto getter2 = GenLookupByKey(key_field, "_bb", "o2"); + writer += "val val_1 = " + getter1; + writer += "val val_2 = " + getter2; + writer += "return (val_1 - val_2).sign"; + } + }); + } + } + + static std::string CastToUsigned(const FieldDef &field) { + return CastToUsigned(field.value.type); + } + + static std::string CastToUsigned(const Type type) { + switch (type.base_type) { + case BASE_TYPE_UINT: + return ".toUInt()"; + case BASE_TYPE_UCHAR: + case BASE_TYPE_UTYPE: + return ".toUByte()"; + case BASE_TYPE_USHORT: + return ".toUShort()"; + case BASE_TYPE_ULONG: + return ".toULong()"; + case BASE_TYPE_VECTOR: + return CastToUsigned(type.VectorType()); + default: + return ""; + } + } + + static std::string CastToSigned(const FieldDef &field) { + return CastToSigned(field.value.type); + } + + static std::string CastToSigned(const Type type) { + switch (type.base_type) { + case BASE_TYPE_UINT: + return ".toInt()"; + case BASE_TYPE_UCHAR: + case BASE_TYPE_UTYPE: + return ".toByte()"; + case BASE_TYPE_USHORT: + return ".toShort()"; + case BASE_TYPE_ULONG: + return ".toLong()"; + case BASE_TYPE_VECTOR: + return CastToSigned(type.VectorType()); + default: + return ""; + } + } + + static std::string LiteralSuffix(const BaseType type) { + switch (type) { + case BASE_TYPE_UINT: + case BASE_TYPE_UCHAR: + case BASE_TYPE_UTYPE: + case BASE_TYPE_USHORT: + return "u"; + case BASE_TYPE_ULONG: + return "UL"; + case BASE_TYPE_LONG: + return "L"; + default: + return ""; + } + } + + void GenerateCompanionObject(CodeWriter &code, + const std::function &callback) const { + code += "companion object {"; + code.IncrementIdentLevel(); + callback(); + code.DecrementIdentLevel(); + code += "}"; + } + + // Generate a documentation comment, if available. + void GenerateComment(const std::vector &dc, CodeWriter &writer, + const CommentConfig *config) const { + if (dc.begin() == dc.end()) { + // Don't output empty comment blocks with 0 lines of comment content. + return; + } + + if (config != nullptr && config->first_line != nullptr) { + writer += std::string(config->first_line); + } + std::string line_prefix = + ((config != nullptr && config->content_line_prefix != nullptr) + ? config->content_line_prefix + : "///"); + for (auto it = dc.begin(); it != dc.end(); ++it) { + writer += line_prefix + *it; + } + if (config != nullptr && config->last_line != nullptr) { + writer += std::string(config->last_line); + } + } + + static void GenerateGetRootAsAccessors(const std::string &struct_name, + CodeWriter &writer) { + // Generate a special accessor for the table that when used as the root + // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...} + writer.SetValue("gr_name", struct_name); + writer.SetValue("gr_method", "getRootAs" + struct_name); + + // create convenience method that doesn't require an existing object + writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\"; + writer += "{{gr_method}}(_bb, {{gr_name}}())"; + + // create method that allows object reuse + // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...} + writer += "fun {{gr_method}}" + "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {"; + writer.IncrementIdentLevel(); + writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)"; + writer += "return (obj.__assign(_bb.getInt(_bb.position())" + " + _bb.position(), _bb))"; + writer.DecrementIdentLevel(); + writer += "}"; + } + + static void GenerateStaticConstructor(const StructDef &struct_def, + CodeWriter &code) { + // create a struct constructor function + auto params = StructConstructorParams(struct_def); + GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){ + GenStructBody(struct_def, code, ""); + code += "return builder.offset()"; + }); + } + + static std::string StructConstructorParams(const StructDef &struct_def, + const std::string &prefix = "") { + //builder: FlatBufferBuilder + std::stringstream out; + auto field_vec = struct_def.fields.vec; + if (prefix.empty()) { + out << "builder: FlatBufferBuilder"; + } + for (auto it = field_vec.begin(); it != field_vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure + // names don't clash, and to make it obvious these arguments are + // constructing a nested struct, prefix the name with the field + // name. + out << StructConstructorParams(*field.value.type.struct_def, + prefix + (Esc(field.name) + "_")); + } else { + out << ", " << prefix << MakeCamel(Esc(field.name), false) + << ": " + << GenTypeBasic(field.value.type.base_type); + } + } + return out.str(); + } + + static void GeneratePropertyOneLine(CodeWriter &writer, + const std::string &name, + const std::string &type, + const std::function &body) { + // Generates Kotlin getter for properties + // e.g.: + // val prop: Mytype = x + writer.SetValue("_name", name); + writer.SetValue("_type", type); + writer += "val {{_name}} : {{_type}} = \\"; + body(); + } + static void GenerateGetterOneLine(CodeWriter &writer, + const std::string &name, + const std::string &type, + const std::function &body) { + // Generates Kotlin getter for properties + // e.g.: + // val prop: Mytype get() = x + writer.SetValue("_name", name); + writer.SetValue("_type", type); + writer += "val {{_name}} : {{_type}} get() = \\"; + body(); + } + + static void GenerateGetter(CodeWriter &writer, + const std::string &name, + const std::string &type, + const std::function &body) { + // Generates Kotlin getter for properties + // e.g.: + // val prop: Mytype + // get() = { + // return x + // } + writer.SetValue("name", name); + writer.SetValue("type", type); + writer += "val {{name}} : {{type}}"; + writer.IncrementIdentLevel(); + writer += "get() {"; + writer.IncrementIdentLevel(); + body(); + writer.DecrementIdentLevel(); + writer += "}"; + writer.DecrementIdentLevel(); + } + + static void GenerateFun(CodeWriter &writer, + const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::function &body) { + // Generates Kotlin function + // e.g.: + // fun path(j: Int): Vec3 { + // return path(Vec3(), j) + // } + auto noreturn = returnType.empty(); + writer.SetValue("name", name); + writer.SetValue("params", params); + writer.SetValue("return_type", noreturn ? "" : ": " + returnType); + writer += "fun {{name}}({{params}}) {{return_type}} {"; + writer.IncrementIdentLevel(); + body(); + writer.DecrementIdentLevel(); + writer += "}"; + } + + static void GenerateFunOneLine(CodeWriter &writer, + const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::function &body) { + // Generates Kotlin function + // e.g.: + // fun path(j: Int): Vec3 = return path(Vec3(), j) + writer.SetValue("name", name); + writer.SetValue("params", params); + writer.SetValue("return_type_p", returnType.empty() ? "" : + " : " + returnType); + writer += "fun {{name}}({{params}}){{return_type_p}} = \\"; + body(); + } + + static void GenerateOverrideFun(CodeWriter &writer, + const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::function &body) { + // Generates Kotlin function + // e.g.: + // override fun path(j: Int): Vec3 = return path(Vec3(), j) + writer += "override \\"; + GenerateFun(writer, name, params, returnType, body); + } + + static void GenerateOverrideFunOneLine(CodeWriter &writer, + const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::string &statement) { + // Generates Kotlin function + // e.g.: + // override fun path(j: Int): Vec3 = return path(Vec3(), j) + writer.SetValue("name", name); + writer.SetValue("params", params); + writer.SetValue("return_type", returnType.empty() ? "" : + " : " + returnType); + writer += "override fun {{name}}({{params}}){{return_type}} = \\"; + writer += statement; + } + + static std::string OffsetWrapperOneLine(const std::string &offset, + const std::string &found, + const std::string ¬_found) { + return "val o = __offset(" + offset + "); return if (o != 0) " + found + + " else " + not_found; + } + + static void OffsetWrapper(CodeWriter &code, + const std::string &offset, + const std::function &found, + const std::function ¬_found) { + code += "val o = __offset(" + offset + ")"; + code +="return if (o != 0) {"; + code.IncrementIdentLevel(); + found(); + code.DecrementIdentLevel(); + code += "} else {"; + code.IncrementIdentLevel(); + not_found(); + code.DecrementIdentLevel(); + code += "}"; + } + + static std::string Indirect(const std::string &index, bool fixed) { + // We apply __indirect() and struct is not fixed. + if (!fixed) + return "__indirect(" + index + ")"; + return index; + } + + static std::string NotFoundReturn(BaseType el) { + switch (el) { + case BASE_TYPE_FLOAT: + return "0.0f"; + case BASE_TYPE_DOUBLE: + return "0.0"; + case BASE_TYPE_BOOL: + return "false"; + case BASE_TYPE_LONG: + case BASE_TYPE_INT: + case BASE_TYPE_CHAR: + case BASE_TYPE_SHORT: + return "0"; + case BASE_TYPE_UINT: + case BASE_TYPE_UCHAR: + case BASE_TYPE_USHORT: + case BASE_TYPE_UTYPE: + return "0u"; + case BASE_TYPE_ULONG: + return "0uL"; + default: + return "null"; + } + } + + // This tracks the current namespace used to determine if a type need to be + // prefixed by its namespace + const Namespace *cur_name_space_; +}; +} // namespace kotlin + +bool GenerateKotlin(const Parser &parser, const std::string &path, + const std::string &file_name) { + kotlin::KotlinGenerator generator(parser, path, file_name); + return generator.generate(); +} +} // namespace flatbuffers diff --git a/src/idl_gen_lobster.cpp b/src/idl_gen_lobster.cpp index 9a8214c6f..ef9e474c5 100644 --- a/src/idl_gen_lobster.cpp +++ b/src/idl_gen_lobster.cpp @@ -83,7 +83,7 @@ class LobsterGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #PTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp index d25e7795f..10df23117 100644 --- a/src/idl_gen_lua.cpp +++ b/src/idl_gen_lua.cpp @@ -606,7 +606,7 @@ namespace lua { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #PTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp index 30512ee1c..9d8141595 100644 --- a/src/idl_gen_php.cpp +++ b/src/idl_gen_php.cpp @@ -862,7 +862,7 @@ class PhpGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #NTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index 643ab198d..fde8a6588 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -680,7 +680,7 @@ class PythonGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ #PTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 409f7a11f..936ac8369 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -516,7 +516,7 @@ class RustGenerator : public BaseGenerator { // clang-format off static const char * const ctypename[] = { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ + RTYPE, KTYPE) \ #RTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -538,7 +538,7 @@ class RustGenerator : public BaseGenerator { static const char *ctypename[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ - RTYPE) \ + RTYPE, KTYPE) \ #RTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index c417bbf09..ef2dce7db 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -146,7 +146,7 @@ bool Print(const void *val, Type type, int indent, // clang-format off switch (vec_type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ if (!PrintVector( \ *reinterpret_cast *>(val), \ @@ -166,7 +166,7 @@ bool Print(const void *val, Type type, int indent, // clang-format off switch (vec_type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ if (!PrintArray( \ *reinterpret_cast *>(val), \ @@ -266,7 +266,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, switch (fd.value.type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ if (!GenField(fd, table, struct_def.fixed, \ opts, indent + Indent(opts), _text)) { \ @@ -277,7 +277,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table, #undef FLATBUFFERS_TD // Generate drop-thru case statements for all pointer types: #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD) diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index adc80ccd6..14d3acd81 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -29,7 +29,7 @@ namespace flatbuffers { // Reflects the version at the compiling time of binary(lib/dll/so). const char *FLATBUFFERS_VERSION() { // clang-format off - return + return FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); @@ -41,7 +41,7 @@ const double kPi = 3.14159265358979323846; const char *const kTypeNames[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ IDLTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -52,7 +52,7 @@ const char *const kTypeNames[] = { const char kTypeSizes[] = { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ sizeof(CTYPE), FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -212,7 +212,7 @@ static std::string TokenToString(int t) { FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) #undef FLATBUFFERS_TOKEN #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ IDLTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -1169,7 +1169,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, switch (field_value.type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ builder_.Pad(field->padding); \ if (struct_def.fixed) { \ @@ -1186,7 +1186,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD); #undef FLATBUFFERS_TD #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ builder_.Pad(field->padding); \ if (IsStruct(field->value.type)) { \ @@ -1267,7 +1267,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue, switch (val.type.base_type) { // clang-format off #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ else { \ @@ -1313,7 +1313,7 @@ CheckedError Parser::ParseArray(Value &array) { // clang-format off switch (val.type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: \ if (IsStruct(val.type)) { \ SerializeStruct(builder, *val.type.struct_def, val); \ @@ -1661,7 +1661,7 @@ CheckedError Parser::ParseSingleValue(const std::string *name, Value &e, // clang-format off switch (match_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ - CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_ ## ENUM: {\ CTYPE val; \ ECHECK(atot(e.constant.c_str(), *this, &val)); \ @@ -1897,7 +1897,7 @@ struct EnumValBuilder { // clang-format off switch (enum_def.underlying_type.base_type) { #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ - PTYPE, RTYPE) \ + PTYPE, RTYPE, KTYPE) \ case BASE_TYPE_##ENUM: { \ if (!IsInteger(BASE_TYPE_##ENUM)) break; \ return ValidateImpl(ev, next ? 1 : 0); \ @@ -2091,6 +2091,7 @@ bool Parser::SupportsAdvancedUnionFeatures() const { (opts.lang_to_generate & ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs | IDLOptions::kPhp | IDLOptions::kJava | IDLOptions::kCSharp | + IDLOptions::kKotlin | IDLOptions::kBinary)) == 0; } diff --git a/tests/KotlinTest.kt b/tests/KotlinTest.kt new file mode 100644 index 000000000..07f0465a4 --- /dev/null +++ b/tests/KotlinTest.kt @@ -0,0 +1,460 @@ +/* + * Copyright 2014 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. + */ + +import MyGame.Example.* +import com.google.flatbuffers.ByteBufferUtil +import com.google.flatbuffers.FlatBufferBuilder +import NamespaceA.* +import NamespaceA.NamespaceB.* +import NamespaceA.NamespaceB.TableInNestedNS +import java.io.File +import java.io.FileOutputStream +import java.io.InputStream +import java.io.RandomAccessFile +import java.nio.ByteBuffer +import java.nio.ByteOrder +import java.nio.channels.FileChannel + +import com.google.flatbuffers.Constants.SIZE_PREFIX_LENGTH + +@kotlin.ExperimentalUnsignedTypes +class KotlinTest { + + companion object { + @JvmStatic + fun main(args: Array) { + + // First, let's test reading a FlatBuffer generated by C++ code: + // This file was generated from monsterdata_test.json + + val data = RandomAccessFile(File("monsterdata_test.mon"), "r").use { + val temp = ByteArray(it.length().toInt()) + it.readFully(temp) + temp + } + + // Now test it: + + val bb = ByteBuffer.wrap(data) + TestBuffer(bb) + + // Second, let's create a FlatBuffer from scratch in Java, and test it also. + // We use an initial size of 1 to exercise the reallocation algorithm, + // normally a size larger than the typical FlatBuffer you generate would be + // better for performance. + val fbb = FlatBufferBuilder(1) + + TestBuilderBasics(fbb, true) + TestBuilderBasics(fbb, false) + + TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer()) + + TestNamespaceNesting() + + TestNestedFlatBuffer() + + TestCreateByteVector() + + TestCreateUninitializedVector() + + TestByteBufferFactory() + + TestSizedInputStream() + + TestVectorOfUnions() + + println("FlatBuffers test: completed successfully") + } + + fun TestEnums() { + assert(Color.name(Color.Red.toInt()) == "Red") + assert(Color.name(Color.Blue.toInt()) == "Blue") + assert(Any_.name(Any_.NONE.toInt()) == "NONE") + assert(Any_.name(Any_.Monster.toInt()) == "Monster") + } + + fun TestBuffer(bb: ByteBuffer) { + assert(Monster.MonsterBufferHasIdentifier(bb) == true) + + val monster = Monster.getRootAsMonster(bb) + + assert(monster.hp == 80.toShort()) + assert(monster.mana == 150.toShort()) // default + + assert(monster.name == "MyMonster") + // monster.friendly() // can't access, deprecated + + val pos = monster.pos!! + assert(pos.x == 1.0f) + assert(pos.y == 2.0f) + assert(pos.z == 3.0f) + assert(pos.test1 == 3.0) + // issue: int != byte + assert(pos.test2 == Color.Green) + val t = pos.test3!! + assert(t.a == 5.toShort()) + assert(t.b == 6.toByte()) + + assert(monster.testType == Any_.Monster) + val monster2 = Monster() + assert(monster.test(monster2) != null == true) + assert(monster2.name == "Fred") + + assert(monster.inventoryLength == 5) + var invsum = 0u + for (i in 0 until monster.inventoryLength) + invsum += monster.inventory(i) + assert(invsum == 10u) + + // Alternative way of accessing a vector: + val ibb = monster.inventoryAsByteBuffer + invsum = 0u + while (ibb.position() < ibb.limit()) + invsum += ibb.get().toUInt() + assert(invsum == 10u) + + + val test_0 = monster.test4(0)!! + val test_1 = monster.test4(1)!! + assert(monster.test4Length == 2) + assert(test_0.a + test_0.b + test_1.a + test_1.b == 100) + + assert(monster.testarrayofstringLength == 2) + assert(monster.testarrayofstring(0) == "test1") + assert(monster.testarrayofstring(1) == "test2") + + assert(monster.testbool == true) + } + + // this method checks additional fields not present in the binary buffer read from file + // these new tests are performed on top of the regular tests + fun TestExtendedBuffer(bb: ByteBuffer) { + TestBuffer(bb) + + val monster = Monster.getRootAsMonster(bb) + + assert(monster.testhashu32Fnv1 == (1u + Integer.MAX_VALUE.toUInt())) + } + + fun TestNamespaceNesting() { + // reference / manipulate these to verify compilation + val fbb = FlatBufferBuilder(1) + + TableInNestedNS.startTableInNestedNS(fbb) + TableInNestedNS.addFoo(fbb, 1234) + val nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb) + + TableInFirstNS.startTableInFirstNS(fbb) + TableInFirstNS.addFooTable(fbb, nestedTableOff) + } + + fun TestNestedFlatBuffer() { + val nestedMonsterName = "NestedMonsterName" + val nestedMonsterHp: Short = 600 + val nestedMonsterMana: Short = 1024 + + var fbb1: FlatBufferBuilder? = FlatBufferBuilder(16) + val str1 = fbb1!!.createString(nestedMonsterName) + Monster.startMonster(fbb1) + Monster.addName(fbb1, str1) + Monster.addHp(fbb1, nestedMonsterHp) + Monster.addMana(fbb1, nestedMonsterMana) + val monster1 = Monster.endMonster(fbb1) + Monster.finishMonsterBuffer(fbb1, monster1) + val fbb1Bytes = fbb1.sizedByteArray() + + val fbb2 = FlatBufferBuilder(16) + val str2 = fbb2.createString("My Monster") + val nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes.asUByteArray()) + Monster.startMonster(fbb2) + Monster.addName(fbb2, str2) + Monster.addHp(fbb2, 50.toShort()) + Monster.addMana(fbb2, 32.toShort()) + Monster.addTestnestedflatbuffer(fbb2, nestedBuffer) + val monster = Monster.endMonster(fbb2) + Monster.finishMonsterBuffer(fbb2, monster) + + // Now test the data extracted from the nested buffer + val mons = Monster.getRootAsMonster(fbb2.dataBuffer()) + val nestedMonster = mons.testnestedflatbufferAsMonster!! + + assert(nestedMonsterMana == nestedMonster.mana) + assert(nestedMonsterHp == nestedMonster.hp) + assert(nestedMonsterName == nestedMonster.name) + } + + fun TestCreateByteVector() { + val fbb = FlatBufferBuilder(16) + val str = fbb.createString("MyMonster") + val inventory = byteArrayOf(0, 1, 2, 3, 4) + val vec = fbb.createByteVector(inventory) + Monster.startMonster(fbb) + Monster.addInventory(fbb, vec) + Monster.addName(fbb, str) + val monster1 = Monster.endMonster(fbb) + Monster.finishMonsterBuffer(fbb, monster1) + val monsterObject = Monster.getRootAsMonster(fbb.dataBuffer()) + + assert(monsterObject.inventory(1) == inventory[1].toUByte()) + assert(monsterObject.inventoryLength == inventory.size) + assert(ByteBuffer.wrap(inventory) == monsterObject.inventoryAsByteBuffer) + } + + fun TestCreateUninitializedVector() { + val fbb = FlatBufferBuilder(16) + val str = fbb.createString("MyMonster") + val inventory = byteArrayOf(0, 1, 2, 3, 4) + val bb = fbb.createUnintializedVector(1, inventory.size, 1) + for (i in inventory) { + bb.put(i) + } + val vec = fbb.endVector() + Monster.startMonster(fbb) + Monster.addInventory(fbb, vec) + Monster.addName(fbb, str) + val monster1 = Monster.endMonster(fbb) + Monster.finishMonsterBuffer(fbb, monster1) + val monsterObject = Monster.getRootAsMonster(fbb.dataBuffer()) + + assert(monsterObject.inventory(1) == inventory[1].toUByte()) + assert(monsterObject.inventoryLength == inventory.size) + assert(ByteBuffer.wrap(inventory) == monsterObject.inventoryAsByteBuffer) + } + + fun TestByteBufferFactory() { + class MappedByteBufferFactory : FlatBufferBuilder.ByteBufferFactory() { + override fun newByteBuffer(capacity: Int): ByteBuffer? { + var bb: ByteBuffer? + try { + bb = RandomAccessFile("javatest.bin", "rw").channel.map( + FileChannel.MapMode.READ_WRITE, + 0, + capacity.toLong() + ).order(ByteOrder.LITTLE_ENDIAN) + } catch (e: Throwable) { + println("FlatBuffers test: couldn't map ByteBuffer to a file") + bb = null + } + + return bb + } + } + + val fbb = FlatBufferBuilder(1, MappedByteBufferFactory()) + + TestBuilderBasics(fbb, false) + } + + fun TestSizedInputStream() { + // Test on default FlatBufferBuilder that uses HeapByteBuffer + val fbb = FlatBufferBuilder(1) + + TestBuilderBasics(fbb, false) + + val `in` = fbb.sizedInputStream() + val array = fbb.sizedByteArray() + var count = 0 + var currentVal = 0 + + while (currentVal != -1 && count < array.size) { + try { + currentVal = `in`.read() + } catch (e: java.io.IOException) { + println("FlatBuffers test: couldn't read from InputStream") + return + } + + assert(currentVal.toByte() == array[count]) + count++ + } + assert(count == array.size) + } + + fun TestBuilderBasics(fbb: FlatBufferBuilder, sizePrefix: Boolean) { + val names = intArrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")) + val off = IntArray(3) + Monster.startMonster(fbb) + Monster.addName(fbb, names[0]) + off[0] = Monster.endMonster(fbb) + Monster.startMonster(fbb) + Monster.addName(fbb, names[1]) + off[1] = Monster.endMonster(fbb) + Monster.startMonster(fbb) + Monster.addName(fbb, names[2]) + off[2] = Monster.endMonster(fbb) + val sortMons = fbb.createSortedVectorOfTables(Monster(), off) + + // We set up the same values as monsterdata.json: + + val str = fbb.createString("MyMonster") + + val inv = Monster.createInventoryVector(fbb, byteArrayOf(0, 1, 2, 3, 4).asUByteArray()) + + val fred = fbb.createString("Fred") + Monster.startMonster(fbb) + Monster.addName(fbb, fred) + val mon2 = Monster.endMonster(fbb) + + Monster.startTest4Vector(fbb, 2) + Test.createTest(fbb, 10.toShort(), 20.toByte()) + Test.createTest(fbb, 30.toShort(), 40.toByte()) + val test4 = fbb.endVector() + + val testArrayOfString = + Monster.createTestarrayofstringVector(fbb, intArrayOf(fbb.createString("test1"), fbb.createString("test2"))) + + Monster.startMonster(fbb) + Monster.addPos( + fbb, Vec3.createVec3( + fbb, 1.0f, 2.0f, 3.0f, 3.0, + Color.Green, 5.toShort(), 6.toByte() + ) + ) + Monster.addHp(fbb, 80.toShort()) + Monster.addName(fbb, str) + Monster.addInventory(fbb, inv) + Monster.addTestType(fbb, Any_.Monster) + Monster.addTest(fbb, mon2) + Monster.addTest4(fbb, test4) + Monster.addTestarrayofstring(fbb, testArrayOfString) + Monster.addTestbool(fbb, true) + Monster.addTesthashu32Fnv1(fbb, UInt.MAX_VALUE + 1u) + Monster.addTestarrayoftables(fbb, sortMons) + val mon = Monster.endMonster(fbb) + + if (sizePrefix) { + Monster.finishSizePrefixedMonsterBuffer(fbb, mon) + } else { + Monster.finishMonsterBuffer(fbb, mon) + } + + // Write the result to a file for debugging purposes: + // Note that the binaries are not necessarily identical, since the JSON + // parser may serialize in a slightly different order than the above + // Java code. They are functionally equivalent though. + + try { + val filename = "monsterdata_java_wire" + (if (sizePrefix) "_sp" else "") + ".mon" + val fc = FileOutputStream(filename).channel + fc.write(fbb.dataBuffer().duplicate()) + fc.close() + } catch (e: java.io.IOException) { + println("FlatBuffers test: couldn't write file") + return + } + + // Test it: + var dataBuffer = fbb.dataBuffer() + if (sizePrefix) { + assert( + ByteBufferUtil.getSizePrefix(dataBuffer) + SIZE_PREFIX_LENGTH == + dataBuffer.remaining() + ) + dataBuffer = ByteBufferUtil.removeSizePrefix(dataBuffer) + } + TestExtendedBuffer(dataBuffer) + + // Make sure it also works with read only ByteBuffers. This is slower, + // since creating strings incurs an additional copy + // (see Table.__string). + TestExtendedBuffer(dataBuffer.asReadOnlyBuffer()) + + TestEnums() + + //Attempt to mutate Monster fields and check whether the buffer has been mutated properly + // revert to original values after testing + val monster = Monster.getRootAsMonster(dataBuffer) + + // mana is optional and does not exist in the buffer so the mutation should fail + // the mana field should retain its default value + assert(monster.mutateMana(10.toShort()) == false) + assert(monster.mana == 150.toShort()) + + // Accessing a vector of sorted by the key tables + assert(monster.testarrayoftables(0)!!.name == "Barney") + assert(monster.testarrayoftables(1)!!.name == "Frodo") + assert(monster.testarrayoftables(2)!!.name == "Wilma") + + // Example of searching for a table by the key + assert(monster.testarrayoftablesByKey("Frodo")!!.name == "Frodo") + assert(monster.testarrayoftablesByKey("Barney")!!.name == "Barney") + assert(monster.testarrayoftablesByKey("Wilma")!!.name == "Wilma") + + // testType is an existing field and mutating it should succeed + assert(monster.testType == Any_.Monster) + assert(monster.mutateTestType(Any_.NONE) == true) + assert(monster.testType == Any_.NONE) + assert(monster.mutateTestType(Any_.Monster) == true) + assert(monster.testType == Any_.Monster) + + //mutate the inventory vector + assert(monster.mutateInventory(0, 1u) == true) + assert(monster.mutateInventory(1, 2u) == true) + assert(monster.mutateInventory(2, 3u) == true) + assert(monster.mutateInventory(3, 4u) == true) + assert(monster.mutateInventory(4, 5u) == true) + + for (i in 0 until monster.inventoryLength) { + assert(monster.inventory(i) == (i.toUByte() + 1u).toUByte()) + } + + //reverse mutation + assert(monster.mutateInventory(0, 0u) == true) + assert(monster.mutateInventory(1, 1u) == true) + assert(monster.mutateInventory(2, 2u) == true) + assert(monster.mutateInventory(3, 3u) == true) + assert(monster.mutateInventory(4, 4u) == true) + + // get a struct field and edit one of its fields + val pos = monster.pos!! + assert(pos.x == 1.0f) + pos.mutateX(55.0f) + assert(pos.x == 55.0f) + pos.mutateX(1.0f) + assert(pos.x == 1.0f) + } + + fun TestVectorOfUnions() { + val fbb = FlatBufferBuilder() + + val swordAttackDamage = 1 + + val characterVector = intArrayOf(Attacker.createAttacker(fbb, swordAttackDamage)) + + val characterTypeVector = ubyteArrayOf(Character_.MuLan) + + Movie.finishMovieBuffer( + fbb, + Movie.createMovie( + fbb, + 0u, + 0, + Movie.createCharactersTypeVector(fbb, characterTypeVector), + Movie.createCharactersVector(fbb, characterVector) + ) + ) + + val movie = Movie.getRootAsMovie(fbb.dataBuffer()) + + assert(movie.charactersTypeLength == characterTypeVector.size) + assert(movie.charactersLength == characterVector.size) + + assert(movie.charactersType(0) == characterTypeVector[0]) + + assert((movie.characters(Attacker(), 0) as Attacker).swordAttackDamage == swordAttackDamage) + } +} + } diff --git a/tests/KotlinTest.sh b/tests/KotlinTest.sh new file mode 100755 index 000000000..709e68c65 --- /dev/null +++ b/tests/KotlinTest.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# Copyright 2014 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. + +echo Compile then run the Kotlin test. + +testdir=$(dirname $0) +targetdir="${testdir}/kotlin" + +if [[ -e "${targetdir}" ]]; then + echo "cleaning target" + rm -rf "${targetdir}" +fi + +mkdir -v "${targetdir}" + +if ! find "${testdir}/../java" -type f -name "*.class" -delete; then + echo "failed to clean .class files from java directory" >&2 + exit 1 +fi + +all_kt_files=`find . -name "*.kt" -print` + +# Compile java FlatBuffer library +javac ${testdir}/../java/com/google/flatbuffers/*.java -d $targetdir +# Compile Kotlin files +kotlinc $all_kt_files -classpath $targetdir -include-runtime -d $targetdir +# Make jar +jar cvf ${testdir}/kotlin_test.jar -C $targetdir . > /dev/null +# Run test +kotlin -cp ${testdir}/kotlin_test.jar KotlinTest +# clean up +rm -rf $targetdir +rm ${testdir}/kotlin_test.jar diff --git a/tests/MyGame/Example/Ability.kt b/tests/MyGame/Example/Ability.kt new file mode 100644 index 000000000..1b644d6ea --- /dev/null +++ b/tests/MyGame/Example/Ability.kt @@ -0,0 +1,32 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Ability : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Ability { + __init(_i, _bb) + return this + } + val id : UInt get() = bb.getInt(bb_pos + 0).toUInt() + fun mutateId(id: UInt) : ByteBuffer = bb.putInt(bb_pos + 0, id.toInt()) + val distance : UInt get() = bb.getInt(bb_pos + 4).toUInt() + fun mutateDistance(distance: UInt) : ByteBuffer = bb.putInt(bb_pos + 4, distance.toInt()) + companion object { + fun createAbility(builder: FlatBufferBuilder, id: UInt, distance: UInt) : Int { + builder.prep(4, 8) + builder.putInt(distance.toInt()) + builder.putInt(id.toInt()) + return builder.offset() + } + } +} diff --git a/tests/MyGame/Example/Any.kt b/tests/MyGame/Example/Any.kt new file mode 100644 index 000000000..f1a4dfed1 --- /dev/null +++ b/tests/MyGame/Example/Any.kt @@ -0,0 +1,16 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Any_ private constructor() { + companion object { + const val NONE: UByte = 0u + const val Monster: UByte = 1u + const val TestSimpleTableWithEnum: UByte = 2u + const val MyGameExample2Monster: UByte = 3u + val names : Array = arrayOf("NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster") + fun name(e: Int) : String = names[e] + } +} diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.kt b/tests/MyGame/Example/AnyAmbiguousAliases.kt new file mode 100644 index 000000000..cee13c51e --- /dev/null +++ b/tests/MyGame/Example/AnyAmbiguousAliases.kt @@ -0,0 +1,16 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +@Suppress("unused") +@ExperimentalUnsignedTypes +class AnyAmbiguousAliases private constructor() { + companion object { + const val NONE: UByte = 0u + const val M1: UByte = 1u + const val M2: UByte = 2u + const val M3: UByte = 3u + val names : Array = arrayOf("NONE", "M1", "M2", "M3") + fun name(e: Int) : String = names[e] + } +} diff --git a/tests/MyGame/Example/AnyUniqueAliases.kt b/tests/MyGame/Example/AnyUniqueAliases.kt new file mode 100644 index 000000000..1902d5d60 --- /dev/null +++ b/tests/MyGame/Example/AnyUniqueAliases.kt @@ -0,0 +1,16 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +@Suppress("unused") +@ExperimentalUnsignedTypes +class AnyUniqueAliases private constructor() { + companion object { + const val NONE: UByte = 0u + const val M: UByte = 1u + const val TS: UByte = 2u + const val M2: UByte = 3u + val names : Array = arrayOf("NONE", "M", "TS", "M2") + fun name(e: Int) : String = names[e] + } +} diff --git a/tests/MyGame/Example/Color.kt b/tests/MyGame/Example/Color.kt new file mode 100644 index 000000000..4c27ba35d --- /dev/null +++ b/tests/MyGame/Example/Color.kt @@ -0,0 +1,25 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +/** + * Composite components of Monster color. + */ +@Suppress("unused") +@ExperimentalUnsignedTypes +class Color private constructor() { + companion object { + const val Red: UByte = 1u + /** + * \brief color Green + * Green is bit_flag with value (1u << 1) + */ + const val Green: UByte = 2u + /** + * \brief color Blue (1u << 3) + */ + const val Blue: UByte = 8u + val names : Array = arrayOf("Red", "Green", "", "", "", "", "", "Blue") + fun name(e: Int) : String = names[e - Red.toInt()] + } +} diff --git a/tests/MyGame/Example/Monster.kt b/tests/MyGame/Example/Monster.kt new file mode 100644 index 000000000..71d72b8d4 --- /dev/null +++ b/tests/MyGame/Example/Monster.kt @@ -0,0 +1,974 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +/** + * an example documentation comment: monster object + */ +@Suppress("unused") +@ExperimentalUnsignedTypes +class Monster : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Monster { + __init(_i, _bb) + return this + } + val pos : MyGame.Example.Vec3? get() = pos(MyGame.Example.Vec3()) + fun pos(obj: MyGame.Example.Vec3) : MyGame.Example.Vec3? { + val o = __offset(4) + return if (o != 0) { + obj.__assign(o + bb_pos, bb) + } else { + null + } + } + val mana : Short + get() { + val o = __offset(6) + return if(o != 0) bb.getShort(o + bb_pos) else 150 + } + fun mutateMana(mana: Short) : Boolean { + val o = __offset(6) + return if (o != 0) { + bb.putShort(o + bb_pos, mana) + true + } else { + false + } + } + val hp : Short + get() { + val o = __offset(8) + return if(o != 0) bb.getShort(o + bb_pos) else 100 + } + fun mutateHp(hp: Short) : Boolean { + val o = __offset(8) + return if (o != 0) { + bb.putShort(o + bb_pos, hp) + true + } else { + false + } + } + val name : String? + get() { + val o = __offset(10) + return if (o != 0) __string(o + bb_pos) else null + } + val nameAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(10, 1) + fun nameInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 10, 1) + fun inventory(j: Int) : UByte { + val o = __offset(14) + return if (o != 0) { + bb.get(__vector(o) + j * 1).toUByte() + } else { + 0u + } + } + val inventoryLength : Int + get() { + val o = __offset(14); return if (o != 0) __vector_len(o) else 0 + } + val inventoryAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(14, 1) + fun inventoryInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 14, 1) + fun mutateInventory(j: Int, inventory: UByte) : Boolean { + val o = __offset(14) + return if (o != 0) { + bb.put(__vector(o) + j * 1, inventory.toByte()) + true + } else { + false + } + } + val color : UByte + get() { + val o = __offset(16) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 8u + } + fun mutateColor(color: UByte) : Boolean { + val o = __offset(16) + return if (o != 0) { + bb.put(o + bb_pos, color.toByte()) + true + } else { + false + } + } + val testType : UByte + get() { + val o = __offset(18) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u + } + fun mutateTestType(testType: UByte) : Boolean { + val o = __offset(18) + return if (o != 0) { + bb.put(o + bb_pos, testType.toByte()) + true + } else { + false + } + } + fun test(obj: Table) : Table? { + val o = __offset(20); return if (o != 0) __union(obj, o) else null + } + fun test4(j: Int) : MyGame.Example.Test? = test4(MyGame.Example.Test(), j) + fun test4(obj: MyGame.Example.Test, j: Int) : MyGame.Example.Test? { + val o = __offset(22) + return if (o != 0) { + obj.__assign(__vector(o) + j * 4, bb) + } else { + null + } + } + val test4Length : Int + get() { + val o = __offset(22); return if (o != 0) __vector_len(o) else 0 + } + fun testarrayofstring(j: Int) : String? { + val o = __offset(24) + return if (o != 0) { + __string(__vector(o) + j * 4) + } else { + null + } + } + val testarrayofstringLength : Int + get() { + val o = __offset(24); return if (o != 0) __vector_len(o) else 0 + } + /** + * an example documentation comment: this will end up in the generated code + * multiline too + */ + fun testarrayoftables(j: Int) : MyGame.Example.Monster? = testarrayoftables(MyGame.Example.Monster(), j) + fun testarrayoftables(obj: MyGame.Example.Monster, j: Int) : MyGame.Example.Monster? { + val o = __offset(26) + return if (o != 0) { + obj.__assign(__indirect(__vector(o) + j * 4), bb) + } else { + null + } + } + val testarrayoftablesLength : Int + get() { + val o = __offset(26); return if (o != 0) __vector_len(o) else 0 + } + fun testarrayoftablesByKey(key: String) : MyGame.Example.Monster? { + val o = __offset(26) + return if (o != 0) { + MyGame.Example.Monster.__lookup_by_key(null, __vector(o), key, bb) + } else { + null + } + } + fun testarrayoftablesByKey(obj: MyGame.Example.Monster, key: String) : MyGame.Example.Monster? { + val o = __offset(26) + return if (o != 0) { + MyGame.Example.Monster.__lookup_by_key(obj, __vector(o), key, bb) + } else { + null + } + } + val enemy : MyGame.Example.Monster? get() = enemy(MyGame.Example.Monster()) + fun enemy(obj: MyGame.Example.Monster) : MyGame.Example.Monster? { + val o = __offset(28) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + fun testnestedflatbuffer(j: Int) : UByte { + val o = __offset(30) + return if (o != 0) { + bb.get(__vector(o) + j * 1).toUByte() + } else { + 0u + } + } + val testnestedflatbufferLength : Int + get() { + val o = __offset(30); return if (o != 0) __vector_len(o) else 0 + } + val testnestedflatbufferAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(30, 1) + fun testnestedflatbufferInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 30, 1) + val testnestedflatbufferAsMonster : MyGame.Example.Monster? get() = testnestedflatbufferAsMonster(MyGame.Example.Monster()) + fun testnestedflatbufferAsMonster(obj: MyGame.Example.Monster) : MyGame.Example.Monster? { + val o = __offset(30) + return if (o != 0) { + obj.__assign(__indirect(__vector(o)), bb) + } else { + null + } + } + fun mutateTestnestedflatbuffer(j: Int, testnestedflatbuffer: UByte) : Boolean { + val o = __offset(30) + return if (o != 0) { + bb.put(__vector(o) + j * 1, testnestedflatbuffer.toByte()) + true + } else { + false + } + } + val testempty : MyGame.Example.Stat? get() = testempty(MyGame.Example.Stat()) + fun testempty(obj: MyGame.Example.Stat) : MyGame.Example.Stat? { + val o = __offset(32) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + val testbool : Boolean + get() { + val o = __offset(34) + return if(o != 0) 0.toByte() != bb.get(o + bb_pos) else false + } + fun mutateTestbool(testbool: Boolean) : Boolean { + val o = __offset(34) + return if (o != 0) { + bb.put(o + bb_pos, (if(testbool) 1 else 0).toByte()) + true + } else { + false + } + } + val testhashs32Fnv1 : Int + get() { + val o = __offset(36) + return if(o != 0) bb.getInt(o + bb_pos) else 0 + } + fun mutateTesthashs32Fnv1(testhashs32Fnv1: Int) : Boolean { + val o = __offset(36) + return if (o != 0) { + bb.putInt(o + bb_pos, testhashs32Fnv1) + true + } else { + false + } + } + val testhashu32Fnv1 : UInt + get() { + val o = __offset(38) + return if(o != 0) bb.getInt(o + bb_pos).toUInt() else 0u + } + fun mutateTesthashu32Fnv1(testhashu32Fnv1: UInt) : Boolean { + val o = __offset(38) + return if (o != 0) { + bb.putInt(o + bb_pos, testhashu32Fnv1.toInt()) + true + } else { + false + } + } + val testhashs64Fnv1 : Long + get() { + val o = __offset(40) + return if(o != 0) bb.getLong(o + bb_pos) else 0L + } + fun mutateTesthashs64Fnv1(testhashs64Fnv1: Long) : Boolean { + val o = __offset(40) + return if (o != 0) { + bb.putLong(o + bb_pos, testhashs64Fnv1) + true + } else { + false + } + } + val testhashu64Fnv1 : ULong + get() { + val o = __offset(42) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateTesthashu64Fnv1(testhashu64Fnv1: ULong) : Boolean { + val o = __offset(42) + return if (o != 0) { + bb.putLong(o + bb_pos, testhashu64Fnv1.toLong()) + true + } else { + false + } + } + val testhashs32Fnv1a : Int + get() { + val o = __offset(44) + return if(o != 0) bb.getInt(o + bb_pos) else 0 + } + fun mutateTesthashs32Fnv1a(testhashs32Fnv1a: Int) : Boolean { + val o = __offset(44) + return if (o != 0) { + bb.putInt(o + bb_pos, testhashs32Fnv1a) + true + } else { + false + } + } + val testhashu32Fnv1a : UInt + get() { + val o = __offset(46) + return if(o != 0) bb.getInt(o + bb_pos).toUInt() else 0u + } + fun mutateTesthashu32Fnv1a(testhashu32Fnv1a: UInt) : Boolean { + val o = __offset(46) + return if (o != 0) { + bb.putInt(o + bb_pos, testhashu32Fnv1a.toInt()) + true + } else { + false + } + } + val testhashs64Fnv1a : Long + get() { + val o = __offset(48) + return if(o != 0) bb.getLong(o + bb_pos) else 0L + } + fun mutateTesthashs64Fnv1a(testhashs64Fnv1a: Long) : Boolean { + val o = __offset(48) + return if (o != 0) { + bb.putLong(o + bb_pos, testhashs64Fnv1a) + true + } else { + false + } + } + val testhashu64Fnv1a : ULong + get() { + val o = __offset(50) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateTesthashu64Fnv1a(testhashu64Fnv1a: ULong) : Boolean { + val o = __offset(50) + return if (o != 0) { + bb.putLong(o + bb_pos, testhashu64Fnv1a.toLong()) + true + } else { + false + } + } + fun testarrayofbools(j: Int) : Boolean { + val o = __offset(52) + return if (o != 0) { + 0.toByte() != bb.get(__vector(o) + j * 1) + } else { + false + } + } + val testarrayofboolsLength : Int + get() { + val o = __offset(52); return if (o != 0) __vector_len(o) else 0 + } + val testarrayofboolsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(52, 1) + fun testarrayofboolsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 52, 1) + fun mutateTestarrayofbools(j: Int, testarrayofbools: Boolean) : Boolean { + val o = __offset(52) + return if (o != 0) { + bb.put(__vector(o) + j * 1, (if(testarrayofbools) 1 else 0).toByte()) + true + } else { + false + } + } + val testf : Float + get() { + val o = __offset(54) + return if(o != 0) bb.getFloat(o + bb_pos) else 3.14159f + } + fun mutateTestf(testf: Float) : Boolean { + val o = __offset(54) + return if (o != 0) { + bb.putFloat(o + bb_pos, testf) + true + } else { + false + } + } + val testf2 : Float + get() { + val o = __offset(56) + return if(o != 0) bb.getFloat(o + bb_pos) else 3.0f + } + fun mutateTestf2(testf2: Float) : Boolean { + val o = __offset(56) + return if (o != 0) { + bb.putFloat(o + bb_pos, testf2) + true + } else { + false + } + } + val testf3 : Float + get() { + val o = __offset(58) + return if(o != 0) bb.getFloat(o + bb_pos) else 0.0f + } + fun mutateTestf3(testf3: Float) : Boolean { + val o = __offset(58) + return if (o != 0) { + bb.putFloat(o + bb_pos, testf3) + true + } else { + false + } + } + fun testarrayofstring2(j: Int) : String? { + val o = __offset(60) + return if (o != 0) { + __string(__vector(o) + j * 4) + } else { + null + } + } + val testarrayofstring2Length : Int + get() { + val o = __offset(60); return if (o != 0) __vector_len(o) else 0 + } + fun testarrayofsortedstruct(j: Int) : MyGame.Example.Ability? = testarrayofsortedstruct(MyGame.Example.Ability(), j) + fun testarrayofsortedstruct(obj: MyGame.Example.Ability, j: Int) : MyGame.Example.Ability? { + val o = __offset(62) + return if (o != 0) { + obj.__assign(__vector(o) + j * 8, bb) + } else { + null + } + } + val testarrayofsortedstructLength : Int + get() { + val o = __offset(62); return if (o != 0) __vector_len(o) else 0 + } + fun flex(j: Int) : UByte { + val o = __offset(64) + return if (o != 0) { + bb.get(__vector(o) + j * 1).toUByte() + } else { + 0u + } + } + val flexLength : Int + get() { + val o = __offset(64); return if (o != 0) __vector_len(o) else 0 + } + val flexAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(64, 1) + fun flexInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 64, 1) + fun mutateFlex(j: Int, flex: UByte) : Boolean { + val o = __offset(64) + return if (o != 0) { + bb.put(__vector(o) + j * 1, flex.toByte()) + true + } else { + false + } + } + fun test5(j: Int) : MyGame.Example.Test? = test5(MyGame.Example.Test(), j) + fun test5(obj: MyGame.Example.Test, j: Int) : MyGame.Example.Test? { + val o = __offset(66) + return if (o != 0) { + obj.__assign(__vector(o) + j * 4, bb) + } else { + null + } + } + val test5Length : Int + get() { + val o = __offset(66); return if (o != 0) __vector_len(o) else 0 + } + fun vectorOfLongs(j: Int) : Long { + val o = __offset(68) + return if (o != 0) { + bb.getLong(__vector(o) + j * 8) + } else { + 0 + } + } + val vectorOfLongsLength : Int + get() { + val o = __offset(68); return if (o != 0) __vector_len(o) else 0 + } + val vectorOfLongsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(68, 8) + fun vectorOfLongsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 68, 8) + fun mutateVectorOfLongs(j: Int, vectorOfLongs: Long) : Boolean { + val o = __offset(68) + return if (o != 0) { + bb.putLong(__vector(o) + j * 8, vectorOfLongs) + true + } else { + false + } + } + fun vectorOfDoubles(j: Int) : Double { + val o = __offset(70) + return if (o != 0) { + bb.getDouble(__vector(o) + j * 8) + } else { + 0.0 + } + } + val vectorOfDoublesLength : Int + get() { + val o = __offset(70); return if (o != 0) __vector_len(o) else 0 + } + val vectorOfDoublesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(70, 8) + fun vectorOfDoublesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 70, 8) + fun mutateVectorOfDoubles(j: Int, vectorOfDoubles: Double) : Boolean { + val o = __offset(70) + return if (o != 0) { + bb.putDouble(__vector(o) + j * 8, vectorOfDoubles) + true + } else { + false + } + } + val parentNamespaceTest : MyGame.InParentNamespace? get() = parentNamespaceTest(MyGame.InParentNamespace()) + fun parentNamespaceTest(obj: MyGame.InParentNamespace) : MyGame.InParentNamespace? { + val o = __offset(72) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + fun vectorOfReferrables(j: Int) : MyGame.Example.Referrable? = vectorOfReferrables(MyGame.Example.Referrable(), j) + fun vectorOfReferrables(obj: MyGame.Example.Referrable, j: Int) : MyGame.Example.Referrable? { + val o = __offset(74) + return if (o != 0) { + obj.__assign(__indirect(__vector(o) + j * 4), bb) + } else { + null + } + } + val vectorOfReferrablesLength : Int + get() { + val o = __offset(74); return if (o != 0) __vector_len(o) else 0 + } + fun vectorOfReferrablesByKey(key: ULong) : MyGame.Example.Referrable? { + val o = __offset(74) + return if (o != 0) { + MyGame.Example.Referrable.__lookup_by_key(null, __vector(o), key, bb) + } else { + null + } + } + fun vectorOfReferrablesByKey(obj: MyGame.Example.Referrable, key: ULong) : MyGame.Example.Referrable? { + val o = __offset(74) + return if (o != 0) { + MyGame.Example.Referrable.__lookup_by_key(obj, __vector(o), key, bb) + } else { + null + } + } + val singleWeakReference : ULong + get() { + val o = __offset(76) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateSingleWeakReference(singleWeakReference: ULong) : Boolean { + val o = __offset(76) + return if (o != 0) { + bb.putLong(o + bb_pos, singleWeakReference.toLong()) + true + } else { + false + } + } + fun vectorOfWeakReferences(j: Int) : ULong { + val o = __offset(78) + return if (o != 0) { + bb.getLong(__vector(o) + j * 8).toULong() + } else { + 0uL + } + } + val vectorOfWeakReferencesLength : Int + get() { + val o = __offset(78); return if (o != 0) __vector_len(o) else 0 + } + val vectorOfWeakReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(78, 8) + fun vectorOfWeakReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 78, 8) + fun mutateVectorOfWeakReferences(j: Int, vectorOfWeakReferences: ULong) : Boolean { + val o = __offset(78) + return if (o != 0) { + bb.putLong(__vector(o) + j * 8, vectorOfWeakReferences.toLong()) + true + } else { + false + } + } + fun vectorOfStrongReferrables(j: Int) : MyGame.Example.Referrable? = vectorOfStrongReferrables(MyGame.Example.Referrable(), j) + fun vectorOfStrongReferrables(obj: MyGame.Example.Referrable, j: Int) : MyGame.Example.Referrable? { + val o = __offset(80) + return if (o != 0) { + obj.__assign(__indirect(__vector(o) + j * 4), bb) + } else { + null + } + } + val vectorOfStrongReferrablesLength : Int + get() { + val o = __offset(80); return if (o != 0) __vector_len(o) else 0 + } + fun vectorOfStrongReferrablesByKey(key: ULong) : MyGame.Example.Referrable? { + val o = __offset(80) + return if (o != 0) { + MyGame.Example.Referrable.__lookup_by_key(null, __vector(o), key, bb) + } else { + null + } + } + fun vectorOfStrongReferrablesByKey(obj: MyGame.Example.Referrable, key: ULong) : MyGame.Example.Referrable? { + val o = __offset(80) + return if (o != 0) { + MyGame.Example.Referrable.__lookup_by_key(obj, __vector(o), key, bb) + } else { + null + } + } + val coOwningReference : ULong + get() { + val o = __offset(82) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateCoOwningReference(coOwningReference: ULong) : Boolean { + val o = __offset(82) + return if (o != 0) { + bb.putLong(o + bb_pos, coOwningReference.toLong()) + true + } else { + false + } + } + fun vectorOfCoOwningReferences(j: Int) : ULong { + val o = __offset(84) + return if (o != 0) { + bb.getLong(__vector(o) + j * 8).toULong() + } else { + 0uL + } + } + val vectorOfCoOwningReferencesLength : Int + get() { + val o = __offset(84); return if (o != 0) __vector_len(o) else 0 + } + val vectorOfCoOwningReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(84, 8) + fun vectorOfCoOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 84, 8) + fun mutateVectorOfCoOwningReferences(j: Int, vectorOfCoOwningReferences: ULong) : Boolean { + val o = __offset(84) + return if (o != 0) { + bb.putLong(__vector(o) + j * 8, vectorOfCoOwningReferences.toLong()) + true + } else { + false + } + } + val nonOwningReference : ULong + get() { + val o = __offset(86) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateNonOwningReference(nonOwningReference: ULong) : Boolean { + val o = __offset(86) + return if (o != 0) { + bb.putLong(o + bb_pos, nonOwningReference.toLong()) + true + } else { + false + } + } + fun vectorOfNonOwningReferences(j: Int) : ULong { + val o = __offset(88) + return if (o != 0) { + bb.getLong(__vector(o) + j * 8).toULong() + } else { + 0uL + } + } + val vectorOfNonOwningReferencesLength : Int + get() { + val o = __offset(88); return if (o != 0) __vector_len(o) else 0 + } + val vectorOfNonOwningReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(88, 8) + fun vectorOfNonOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 88, 8) + fun mutateVectorOfNonOwningReferences(j: Int, vectorOfNonOwningReferences: ULong) : Boolean { + val o = __offset(88) + return if (o != 0) { + bb.putLong(__vector(o) + j * 8, vectorOfNonOwningReferences.toLong()) + true + } else { + false + } + } + val anyUniqueType : UByte + get() { + val o = __offset(90) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u + } + fun mutateAnyUniqueType(anyUniqueType: UByte) : Boolean { + val o = __offset(90) + return if (o != 0) { + bb.put(o + bb_pos, anyUniqueType.toByte()) + true + } else { + false + } + } + fun anyUnique(obj: Table) : Table? { + val o = __offset(92); return if (o != 0) __union(obj, o) else null + } + val anyAmbiguousType : UByte + get() { + val o = __offset(94) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u + } + fun mutateAnyAmbiguousType(anyAmbiguousType: UByte) : Boolean { + val o = __offset(94) + return if (o != 0) { + bb.put(o + bb_pos, anyAmbiguousType.toByte()) + true + } else { + false + } + } + fun anyAmbiguous(obj: Table) : Table? { + val o = __offset(96); return if (o != 0) __union(obj, o) else null + } + fun vectorOfEnums(j: Int) : UByte { + val o = __offset(98) + return if (o != 0) { + bb.get(__vector(o) + j * 1).toUByte() + } else { + 0u + } + } + val vectorOfEnumsLength : Int + get() { + val o = __offset(98); return if (o != 0) __vector_len(o) else 0 + } + val vectorOfEnumsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(98, 1) + fun vectorOfEnumsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 98, 1) + fun mutateVectorOfEnums(j: Int, vectorOfEnums: UByte) : Boolean { + val o = __offset(98) + return if (o != 0) { + bb.put(__vector(o) + j * 1, vectorOfEnums.toByte()) + true + } else { + false + } + } + override fun keysCompare(o1: Int, o2: Int, _bb: ByteBuffer) : Int { + return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb) + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsMonster(_bb: ByteBuffer): Monster = getRootAsMonster(_bb, Monster()) + fun getRootAsMonster(_bb: ByteBuffer, obj: Monster): Monster { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun MonsterBufferHasIdentifier(_bb: ByteBuffer) : Boolean = __has_identifier(_bb, "MONS") + fun startMonster(builder: FlatBufferBuilder) = builder.startTable(48) + fun addPos(builder: FlatBufferBuilder, pos: Int) = builder.addStruct(0, pos, 0) + fun addMana(builder: FlatBufferBuilder, mana: Short) = builder.addShort(1, mana, 150) + fun addHp(builder: FlatBufferBuilder, hp: Short) = builder.addShort(2, hp, 100) + fun addName(builder: FlatBufferBuilder, name: Int) = builder.addOffset(3, name, 0) + fun addInventory(builder: FlatBufferBuilder, inventory: Int) = builder.addOffset(5, inventory, 0) + fun createInventoryVector(builder: FlatBufferBuilder, data: UByteArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addByte(data[i].toByte()) + } + return builder.endVector() + } + fun startInventoryVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun addColor(builder: FlatBufferBuilder, color: UByte) = builder.addByte(6, color.toByte(), 8) + fun addTestType(builder: FlatBufferBuilder, testType: UByte) = builder.addByte(7, testType.toByte(), 0) + fun addTest(builder: FlatBufferBuilder, test: Int) = builder.addOffset(8, test, 0) + fun addTest4(builder: FlatBufferBuilder, test4: Int) = builder.addOffset(9, test4, 0) + fun startTest4Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 2) + fun addTestarrayofstring(builder: FlatBufferBuilder, testarrayofstring: Int) = builder.addOffset(10, testarrayofstring, 0) + fun createTestarrayofstringVector(builder: FlatBufferBuilder, data: IntArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addOffset(data[i]) + } + return builder.endVector() + } + fun startTestarrayofstringVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun addTestarrayoftables(builder: FlatBufferBuilder, testarrayoftables: Int) = builder.addOffset(11, testarrayoftables, 0) + fun createTestarrayoftablesVector(builder: FlatBufferBuilder, data: IntArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addOffset(data[i]) + } + return builder.endVector() + } + fun startTestarrayoftablesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun addEnemy(builder: FlatBufferBuilder, enemy: Int) = builder.addOffset(12, enemy, 0) + fun addTestnestedflatbuffer(builder: FlatBufferBuilder, testnestedflatbuffer: Int) = builder.addOffset(13, testnestedflatbuffer, 0) + fun createTestnestedflatbufferVector(builder: FlatBufferBuilder, data: UByteArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addByte(data[i].toByte()) + } + return builder.endVector() + } + fun startTestnestedflatbufferVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun addTestempty(builder: FlatBufferBuilder, testempty: Int) = builder.addOffset(14, testempty, 0) + fun addTestbool(builder: FlatBufferBuilder, testbool: Boolean) = builder.addBoolean(15, testbool, false) + fun addTesthashs32Fnv1(builder: FlatBufferBuilder, testhashs32Fnv1: Int) = builder.addInt(16, testhashs32Fnv1, 0) + fun addTesthashu32Fnv1(builder: FlatBufferBuilder, testhashu32Fnv1: UInt) = builder.addInt(17, testhashu32Fnv1.toInt(), 0) + fun addTesthashs64Fnv1(builder: FlatBufferBuilder, testhashs64Fnv1: Long) = builder.addLong(18, testhashs64Fnv1, 0L) + fun addTesthashu64Fnv1(builder: FlatBufferBuilder, testhashu64Fnv1: ULong) = builder.addLong(19, testhashu64Fnv1.toLong(), 0) + fun addTesthashs32Fnv1a(builder: FlatBufferBuilder, testhashs32Fnv1a: Int) = builder.addInt(20, testhashs32Fnv1a, 0) + fun addTesthashu32Fnv1a(builder: FlatBufferBuilder, testhashu32Fnv1a: UInt) = builder.addInt(21, testhashu32Fnv1a.toInt(), 0) + fun addTesthashs64Fnv1a(builder: FlatBufferBuilder, testhashs64Fnv1a: Long) = builder.addLong(22, testhashs64Fnv1a, 0L) + fun addTesthashu64Fnv1a(builder: FlatBufferBuilder, testhashu64Fnv1a: ULong) = builder.addLong(23, testhashu64Fnv1a.toLong(), 0) + fun addTestarrayofbools(builder: FlatBufferBuilder, testarrayofbools: Int) = builder.addOffset(24, testarrayofbools, 0) + fun createTestarrayofboolsVector(builder: FlatBufferBuilder, data: BooleanArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addBoolean(data[i]) + } + return builder.endVector() + } + fun startTestarrayofboolsVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun addTestf(builder: FlatBufferBuilder, testf: Float) = builder.addFloat(25, testf, 3.14159) + fun addTestf2(builder: FlatBufferBuilder, testf2: Float) = builder.addFloat(26, testf2, 3.0) + fun addTestf3(builder: FlatBufferBuilder, testf3: Float) = builder.addFloat(27, testf3, 0.0) + fun addTestarrayofstring2(builder: FlatBufferBuilder, testarrayofstring2: Int) = builder.addOffset(28, testarrayofstring2, 0) + fun createTestarrayofstring2Vector(builder: FlatBufferBuilder, data: IntArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addOffset(data[i]) + } + return builder.endVector() + } + fun startTestarrayofstring2Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun addTestarrayofsortedstruct(builder: FlatBufferBuilder, testarrayofsortedstruct: Int) = builder.addOffset(29, testarrayofsortedstruct, 0) + fun startTestarrayofsortedstructVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 4) + fun addFlex(builder: FlatBufferBuilder, flex: Int) = builder.addOffset(30, flex, 0) + fun createFlexVector(builder: FlatBufferBuilder, data: UByteArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addByte(data[i].toByte()) + } + return builder.endVector() + } + fun startFlexVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun addTest5(builder: FlatBufferBuilder, test5: Int) = builder.addOffset(31, test5, 0) + fun startTest5Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 2) + fun addVectorOfLongs(builder: FlatBufferBuilder, vectorOfLongs: Int) = builder.addOffset(32, vectorOfLongs, 0) + fun createVectorOfLongsVector(builder: FlatBufferBuilder, data: LongArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addLong(data[i]) + } + return builder.endVector() + } + fun startVectorOfLongsVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun addVectorOfDoubles(builder: FlatBufferBuilder, vectorOfDoubles: Int) = builder.addOffset(33, vectorOfDoubles, 0) + fun createVectorOfDoublesVector(builder: FlatBufferBuilder, data: DoubleArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addDouble(data[i]) + } + return builder.endVector() + } + fun startVectorOfDoublesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun addParentNamespaceTest(builder: FlatBufferBuilder, parentNamespaceTest: Int) = builder.addOffset(34, parentNamespaceTest, 0) + fun addVectorOfReferrables(builder: FlatBufferBuilder, vectorOfReferrables: Int) = builder.addOffset(35, vectorOfReferrables, 0) + fun createVectorOfReferrablesVector(builder: FlatBufferBuilder, data: IntArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addOffset(data[i]) + } + return builder.endVector() + } + fun startVectorOfReferrablesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun addSingleWeakReference(builder: FlatBufferBuilder, singleWeakReference: ULong) = builder.addLong(36, singleWeakReference.toLong(), 0) + fun addVectorOfWeakReferences(builder: FlatBufferBuilder, vectorOfWeakReferences: Int) = builder.addOffset(37, vectorOfWeakReferences, 0) + fun createVectorOfWeakReferencesVector(builder: FlatBufferBuilder, data: ULongArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addLong(data[i].toLong()) + } + return builder.endVector() + } + fun startVectorOfWeakReferencesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun addVectorOfStrongReferrables(builder: FlatBufferBuilder, vectorOfStrongReferrables: Int) = builder.addOffset(38, vectorOfStrongReferrables, 0) + fun createVectorOfStrongReferrablesVector(builder: FlatBufferBuilder, data: IntArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addOffset(data[i]) + } + return builder.endVector() + } + fun startVectorOfStrongReferrablesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun addCoOwningReference(builder: FlatBufferBuilder, coOwningReference: ULong) = builder.addLong(39, coOwningReference.toLong(), 0) + fun addVectorOfCoOwningReferences(builder: FlatBufferBuilder, vectorOfCoOwningReferences: Int) = builder.addOffset(40, vectorOfCoOwningReferences, 0) + fun createVectorOfCoOwningReferencesVector(builder: FlatBufferBuilder, data: ULongArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addLong(data[i].toLong()) + } + return builder.endVector() + } + fun startVectorOfCoOwningReferencesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun addNonOwningReference(builder: FlatBufferBuilder, nonOwningReference: ULong) = builder.addLong(41, nonOwningReference.toLong(), 0) + fun addVectorOfNonOwningReferences(builder: FlatBufferBuilder, vectorOfNonOwningReferences: Int) = builder.addOffset(42, vectorOfNonOwningReferences, 0) + fun createVectorOfNonOwningReferencesVector(builder: FlatBufferBuilder, data: ULongArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addLong(data[i].toLong()) + } + return builder.endVector() + } + fun startVectorOfNonOwningReferencesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun addAnyUniqueType(builder: FlatBufferBuilder, anyUniqueType: UByte) = builder.addByte(43, anyUniqueType.toByte(), 0) + fun addAnyUnique(builder: FlatBufferBuilder, anyUnique: Int) = builder.addOffset(44, anyUnique, 0) + fun addAnyAmbiguousType(builder: FlatBufferBuilder, anyAmbiguousType: UByte) = builder.addByte(45, anyAmbiguousType.toByte(), 0) + fun addAnyAmbiguous(builder: FlatBufferBuilder, anyAmbiguous: Int) = builder.addOffset(46, anyAmbiguous, 0) + fun addVectorOfEnums(builder: FlatBufferBuilder, vectorOfEnums: Int) = builder.addOffset(47, vectorOfEnums, 0) + fun createVectorOfEnumsVector(builder: FlatBufferBuilder, data: UByteArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addByte(data[i].toByte()) + } + return builder.endVector() + } + fun startVectorOfEnumsVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun endMonster(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + builder.required(o, 10) + return o + } + fun finishMonsterBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset, "MONS") + fun finishSizePrefixedMonsterBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset, "MONS") + fun __lookup_by_key(obj: Monster?, vectorLocation: Int, key: String, bb: ByteBuffer) : Monster? { + val byteKey = key.toByteArray(Table.UTF8_CHARSET.get()!!) + var span = bb.getInt(vectorLocation - 4) + var start = 0 + while (span != 0) { + var middle = span / 2 + val tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb) + val comp = compareStrings(__offset(10, bb.capacity() - tableOffset, bb), byteKey, bb) + when { + comp > 0 -> span = middle + comp < 0 -> { + middle++ + start += middle + span -= middle + } + else -> { + return (obj ?: Monster()).__assign(tableOffset, bb) + } + } + } + return null + } + } +} diff --git a/tests/MyGame/Example/Referrable.kt b/tests/MyGame/Example/Referrable.kt new file mode 100644 index 000000000..55ff1d82d --- /dev/null +++ b/tests/MyGame/Example/Referrable.kt @@ -0,0 +1,80 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Referrable : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Referrable { + __init(_i, _bb) + return this + } + val id : ULong + get() { + val o = __offset(4) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateId(id: ULong) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.putLong(o + bb_pos, id.toLong()) + true + } else { + false + } + } + override fun keysCompare(o1: Int, o2: Int, _bb: ByteBuffer) : Int { + val val_1 = _bb.getLong(__offset(4, o1, _bb)) + val val_2 = _bb.getLong(__offset(4, o2, _bb)) + return (val_1 - val_2).sign + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsReferrable(_bb: ByteBuffer): Referrable = getRootAsReferrable(_bb, Referrable()) + fun getRootAsReferrable(_bb: ByteBuffer, obj: Referrable): Referrable { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createReferrable(builder: FlatBufferBuilder, id: ULong) : Int { + builder.startTable(1) + addId(builder, id) + return endReferrable(builder) + } + fun startReferrable(builder: FlatBufferBuilder) = builder.startTable(1) + fun addId(builder: FlatBufferBuilder, id: ULong) = builder.addLong(0, id.toLong(), 0) + fun endReferrable(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + fun __lookup_by_key(obj: Referrable?, vectorLocation: Int, key: ULong, bb: ByteBuffer) : Referrable? { + var span = bb.getInt(vectorLocation - 4) + var start = 0 + while (span != 0) { + var middle = span / 2 + val tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb) + val value = bb.getLong(__offset(4, bb.capacity() - tableOffset, bb)).toULong() + val comp = value.compareTo(key) + when { + comp > 0 -> span = middle + comp < 0 -> { + middle++ + start += middle + span -= middle + } + else -> { + return (obj ?: Referrable()).__assign(tableOffset, bb) + } + } + } + return null + } + } +} diff --git a/tests/MyGame/Example/Stat.kt b/tests/MyGame/Example/Stat.kt new file mode 100644 index 000000000..26b293cdb --- /dev/null +++ b/tests/MyGame/Example/Stat.kt @@ -0,0 +1,78 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Stat : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Stat { + __init(_i, _bb) + return this + } + val id : String? + get() { + val o = __offset(4) + return if (o != 0) __string(o + bb_pos) else null + } + val idAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(4, 1) + fun idInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 4, 1) + val val_ : Long + get() { + val o = __offset(6) + return if(o != 0) bb.getLong(o + bb_pos) else 0L + } + fun mutateVal_(val_: Long) : Boolean { + val o = __offset(6) + return if (o != 0) { + bb.putLong(o + bb_pos, val_) + true + } else { + false + } + } + val count : UShort + get() { + val o = __offset(8) + return if(o != 0) bb.getShort(o + bb_pos).toUShort() else 0u + } + fun mutateCount(count: UShort) : Boolean { + val o = __offset(8) + return if (o != 0) { + bb.putShort(o + bb_pos, count.toShort()) + true + } else { + false + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsStat(_bb: ByteBuffer): Stat = getRootAsStat(_bb, Stat()) + fun getRootAsStat(_bb: ByteBuffer, obj: Stat): Stat { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createStat(builder: FlatBufferBuilder, idOffset: Int, val_: Long, count: UShort) : Int { + builder.startTable(3) + addVal_(builder, val_) + addId(builder, idOffset) + addCount(builder, count) + return endStat(builder) + } + fun startStat(builder: FlatBufferBuilder) = builder.startTable(3) + fun addId(builder: FlatBufferBuilder, id: Int) = builder.addOffset(0, id, 0) + fun addVal_(builder: FlatBufferBuilder, val_: Long) = builder.addLong(1, val_, 0L) + fun addCount(builder: FlatBufferBuilder, count: UShort) = builder.addShort(2, count.toShort(), 0) + fun endStat(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/MyGame/Example/Test.kt b/tests/MyGame/Example/Test.kt new file mode 100644 index 000000000..f2ceed6f5 --- /dev/null +++ b/tests/MyGame/Example/Test.kt @@ -0,0 +1,33 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Test : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Test { + __init(_i, _bb) + return this + } + val a : Short get() = bb.getShort(bb_pos + 0) + fun mutateA(a: Short) : ByteBuffer = bb.putShort(bb_pos + 0, a) + val b : Byte get() = bb.get(bb_pos + 2) + fun mutateB(b: Byte) : ByteBuffer = bb.put(bb_pos + 2, b) + companion object { + fun createTest(builder: FlatBufferBuilder, a: Short, b: Byte) : Int { + builder.prep(2, 4) + builder.pad(1) + builder.putByte(b) + builder.putShort(a) + return builder.offset() + } + } +} diff --git a/tests/MyGame/Example/TestEnum.kt b/tests/MyGame/Example/TestEnum.kt new file mode 100644 index 000000000..ca4d7f879 --- /dev/null +++ b/tests/MyGame/Example/TestEnum.kt @@ -0,0 +1,14 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +@Suppress("unused") +class TestEnum private constructor() { + companion object { + const val A: Byte = 0 + const val B: Byte = 1 + const val C: Byte = 2 + val names : Array = arrayOf("A", "B", "C") + fun name(e: Int) : String = names[e] + } +} diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.kt b/tests/MyGame/Example/TestSimpleTableWithEnum.kt new file mode 100644 index 000000000..68c6abfde --- /dev/null +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.kt @@ -0,0 +1,53 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class TestSimpleTableWithEnum : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : TestSimpleTableWithEnum { + __init(_i, _bb) + return this + } + val color : UByte + get() { + val o = __offset(4) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 2u + } + fun mutateColor(color: UByte) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.put(o + bb_pos, color.toByte()) + true + } else { + false + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsTestSimpleTableWithEnum(_bb: ByteBuffer): TestSimpleTableWithEnum = getRootAsTestSimpleTableWithEnum(_bb, TestSimpleTableWithEnum()) + fun getRootAsTestSimpleTableWithEnum(_bb: ByteBuffer, obj: TestSimpleTableWithEnum): TestSimpleTableWithEnum { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createTestSimpleTableWithEnum(builder: FlatBufferBuilder, color: UByte) : Int { + builder.startTable(1) + addColor(builder, color) + return endTestSimpleTableWithEnum(builder) + } + fun startTestSimpleTableWithEnum(builder: FlatBufferBuilder) = builder.startTable(1) + fun addColor(builder: FlatBufferBuilder, color: UByte) = builder.addByte(0, color.toByte(), 2) + fun endTestSimpleTableWithEnum(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/MyGame/Example/TypeAliases.kt b/tests/MyGame/Example/TypeAliases.kt new file mode 100644 index 000000000..d1e881626 --- /dev/null +++ b/tests/MyGame/Example/TypeAliases.kt @@ -0,0 +1,263 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class TypeAliases : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : TypeAliases { + __init(_i, _bb) + return this + } + val i8 : Byte + get() { + val o = __offset(4) + return if(o != 0) bb.get(o + bb_pos) else 0 + } + fun mutateI8(i8: Byte) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.put(o + bb_pos, i8) + true + } else { + false + } + } + val u8 : UByte + get() { + val o = __offset(6) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u + } + fun mutateU8(u8: UByte) : Boolean { + val o = __offset(6) + return if (o != 0) { + bb.put(o + bb_pos, u8.toByte()) + true + } else { + false + } + } + val i16 : Short + get() { + val o = __offset(8) + return if(o != 0) bb.getShort(o + bb_pos) else 0 + } + fun mutateI16(i16: Short) : Boolean { + val o = __offset(8) + return if (o != 0) { + bb.putShort(o + bb_pos, i16) + true + } else { + false + } + } + val u16 : UShort + get() { + val o = __offset(10) + return if(o != 0) bb.getShort(o + bb_pos).toUShort() else 0u + } + fun mutateU16(u16: UShort) : Boolean { + val o = __offset(10) + return if (o != 0) { + bb.putShort(o + bb_pos, u16.toShort()) + true + } else { + false + } + } + val i32 : Int + get() { + val o = __offset(12) + return if(o != 0) bb.getInt(o + bb_pos) else 0 + } + fun mutateI32(i32: Int) : Boolean { + val o = __offset(12) + return if (o != 0) { + bb.putInt(o + bb_pos, i32) + true + } else { + false + } + } + val u32 : UInt + get() { + val o = __offset(14) + return if(o != 0) bb.getInt(o + bb_pos).toUInt() else 0u + } + fun mutateU32(u32: UInt) : Boolean { + val o = __offset(14) + return if (o != 0) { + bb.putInt(o + bb_pos, u32.toInt()) + true + } else { + false + } + } + val i64 : Long + get() { + val o = __offset(16) + return if(o != 0) bb.getLong(o + bb_pos) else 0L + } + fun mutateI64(i64: Long) : Boolean { + val o = __offset(16) + return if (o != 0) { + bb.putLong(o + bb_pos, i64) + true + } else { + false + } + } + val u64 : ULong + get() { + val o = __offset(18) + return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL + } + fun mutateU64(u64: ULong) : Boolean { + val o = __offset(18) + return if (o != 0) { + bb.putLong(o + bb_pos, u64.toLong()) + true + } else { + false + } + } + val f32 : Float + get() { + val o = __offset(20) + return if(o != 0) bb.getFloat(o + bb_pos) else 0.0f + } + fun mutateF32(f32: Float) : Boolean { + val o = __offset(20) + return if (o != 0) { + bb.putFloat(o + bb_pos, f32) + true + } else { + false + } + } + val f64 : Double + get() { + val o = __offset(22) + return if(o != 0) bb.getDouble(o + bb_pos) else 0.0 + } + fun mutateF64(f64: Double) : Boolean { + val o = __offset(22) + return if (o != 0) { + bb.putDouble(o + bb_pos, f64) + true + } else { + false + } + } + fun v8(j: Int) : Byte { + val o = __offset(24) + return if (o != 0) { + bb.get(__vector(o) + j * 1) + } else { + 0 + } + } + val v8Length : Int + get() { + val o = __offset(24); return if (o != 0) __vector_len(o) else 0 + } + val v8AsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(24, 1) + fun v8InByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 24, 1) + fun mutateV8(j: Int, v8: Byte) : Boolean { + val o = __offset(24) + return if (o != 0) { + bb.put(__vector(o) + j * 1, v8) + true + } else { + false + } + } + fun vf64(j: Int) : Double { + val o = __offset(26) + return if (o != 0) { + bb.getDouble(__vector(o) + j * 8) + } else { + 0.0 + } + } + val vf64Length : Int + get() { + val o = __offset(26); return if (o != 0) __vector_len(o) else 0 + } + val vf64AsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(26, 8) + fun vf64InByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 26, 8) + fun mutateVf64(j: Int, vf64: Double) : Boolean { + val o = __offset(26) + return if (o != 0) { + bb.putDouble(__vector(o) + j * 8, vf64) + true + } else { + false + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsTypeAliases(_bb: ByteBuffer): TypeAliases = getRootAsTypeAliases(_bb, TypeAliases()) + fun getRootAsTypeAliases(_bb: ByteBuffer, obj: TypeAliases): TypeAliases { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createTypeAliases(builder: FlatBufferBuilder, i8: Byte, u8: UByte, i16: Short, u16: UShort, i32: Int, u32: UInt, i64: Long, u64: ULong, f32: Float, f64: Double, v8Offset: Int, vf64Offset: Int) : Int { + builder.startTable(12) + addF64(builder, f64) + addU64(builder, u64) + addI64(builder, i64) + addVf64(builder, vf64Offset) + addV8(builder, v8Offset) + addF32(builder, f32) + addU32(builder, u32) + addI32(builder, i32) + addU16(builder, u16) + addI16(builder, i16) + addU8(builder, u8) + addI8(builder, i8) + return endTypeAliases(builder) + } + fun startTypeAliases(builder: FlatBufferBuilder) = builder.startTable(12) + fun addI8(builder: FlatBufferBuilder, i8: Byte) = builder.addByte(0, i8, 0) + fun addU8(builder: FlatBufferBuilder, u8: UByte) = builder.addByte(1, u8.toByte(), 0) + fun addI16(builder: FlatBufferBuilder, i16: Short) = builder.addShort(2, i16, 0) + fun addU16(builder: FlatBufferBuilder, u16: UShort) = builder.addShort(3, u16.toShort(), 0) + fun addI32(builder: FlatBufferBuilder, i32: Int) = builder.addInt(4, i32, 0) + fun addU32(builder: FlatBufferBuilder, u32: UInt) = builder.addInt(5, u32.toInt(), 0) + fun addI64(builder: FlatBufferBuilder, i64: Long) = builder.addLong(6, i64, 0L) + fun addU64(builder: FlatBufferBuilder, u64: ULong) = builder.addLong(7, u64.toLong(), 0) + fun addF32(builder: FlatBufferBuilder, f32: Float) = builder.addFloat(8, f32, 0.0) + fun addF64(builder: FlatBufferBuilder, f64: Double) = builder.addDouble(9, f64, 0.0) + fun addV8(builder: FlatBufferBuilder, v8: Int) = builder.addOffset(10, v8, 0) + fun createV8Vector(builder: FlatBufferBuilder, data: ByteArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addByte(data[i]) + } + return builder.endVector() + } + fun startV8Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun addVf64(builder: FlatBufferBuilder, vf64: Int) = builder.addOffset(11, vf64, 0) + fun createVf64Vector(builder: FlatBufferBuilder, data: DoubleArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addDouble(data[i]) + } + return builder.endVector() + } + fun startVf64Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun endTypeAliases(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/MyGame/Example/Vec3.kt b/tests/MyGame/Example/Vec3.kt new file mode 100644 index 000000000..90f1b4ad0 --- /dev/null +++ b/tests/MyGame/Example/Vec3.kt @@ -0,0 +1,50 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Vec3 : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Vec3 { + __init(_i, _bb) + return this + } + val x : Float get() = bb.getFloat(bb_pos + 0) + fun mutateX(x: Float) : ByteBuffer = bb.putFloat(bb_pos + 0, x) + val y : Float get() = bb.getFloat(bb_pos + 4) + fun mutateY(y: Float) : ByteBuffer = bb.putFloat(bb_pos + 4, y) + val z : Float get() = bb.getFloat(bb_pos + 8) + fun mutateZ(z: Float) : ByteBuffer = bb.putFloat(bb_pos + 8, z) + val test1 : Double get() = bb.getDouble(bb_pos + 16) + fun mutateTest1(test1: Double) : ByteBuffer = bb.putDouble(bb_pos + 16, test1) + val test2 : UByte get() = bb.get(bb_pos + 24).toUByte() + fun mutateTest2(test2: UByte) : ByteBuffer = bb.put(bb_pos + 24, test2.toByte()) + val test3 : MyGame.Example.Test? get() = test3(MyGame.Example.Test()) + fun test3(obj: MyGame.Example.Test) : MyGame.Example.Test? = obj.__assign(bb_pos + 26, bb) + companion object { + fun createVec3(builder: FlatBufferBuilder, x: Float, y: Float, z: Float, test1: Double, test2: UByte, test3_a: Short, test3_b: Byte) : Int { + builder.prep(8, 32) + builder.pad(2) + builder.prep(2, 4) + builder.pad(1) + builder.putByte(test3_b) + builder.putShort(test3_a) + builder.pad(1) + builder.putByte(test2.toByte()) + builder.putDouble(test1) + builder.pad(4) + builder.putFloat(z) + builder.putFloat(y) + builder.putFloat(x) + return builder.offset() + } + } +} diff --git a/tests/MyGame/Example2/Monster.kt b/tests/MyGame/Example2/Monster.kt new file mode 100644 index 000000000..de587ba98 --- /dev/null +++ b/tests/MyGame/Example2/Monster.kt @@ -0,0 +1,33 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example2 + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Monster : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Monster { + __init(_i, _bb) + return this + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsMonster(_bb: ByteBuffer): Monster = getRootAsMonster(_bb, Monster()) + fun getRootAsMonster(_bb: ByteBuffer, obj: Monster): Monster { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun startMonster(builder: FlatBufferBuilder) = builder.startTable(0) + fun endMonster(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/MyGame/InParentNamespace.kt b/tests/MyGame/InParentNamespace.kt new file mode 100644 index 000000000..76779fc11 --- /dev/null +++ b/tests/MyGame/InParentNamespace.kt @@ -0,0 +1,33 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class InParentNamespace : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : InParentNamespace { + __init(_i, _bb) + return this + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsInParentNamespace(_bb: ByteBuffer): InParentNamespace = getRootAsInParentNamespace(_bb, InParentNamespace()) + fun getRootAsInParentNamespace(_bb: ByteBuffer, obj: InParentNamespace): InParentNamespace { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun startInParentNamespace(builder: FlatBufferBuilder) = builder.startTable(0) + fun endInParentNamespace(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/MyGame/MonsterExtra.kt b/tests/MyGame/MonsterExtra.kt new file mode 100644 index 000000000..f0ea5fad1 --- /dev/null +++ b/tests/MyGame/MonsterExtra.kt @@ -0,0 +1,202 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class MonsterExtra : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : MonsterExtra { + __init(_i, _bb) + return this + } + val testfNan : Float + get() { + val o = __offset(4) + return if(o != 0) bb.getFloat(o + bb_pos) else Float.NaN + } + fun mutateTestfNan(testfNan: Float) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.putFloat(o + bb_pos, testfNan) + true + } else { + false + } + } + val testfPinf : Float + get() { + val o = __offset(6) + return if(o != 0) bb.getFloat(o + bb_pos) else Float.POSITIVE_INFINITY + } + fun mutateTestfPinf(testfPinf: Float) : Boolean { + val o = __offset(6) + return if (o != 0) { + bb.putFloat(o + bb_pos, testfPinf) + true + } else { + false + } + } + val testfNinf : Float + get() { + val o = __offset(8) + return if(o != 0) bb.getFloat(o + bb_pos) else Float.NEGATIVE_INFINITY + } + fun mutateTestfNinf(testfNinf: Float) : Boolean { + val o = __offset(8) + return if (o != 0) { + bb.putFloat(o + bb_pos, testfNinf) + true + } else { + false + } + } + val testdNan : Double + get() { + val o = __offset(10) + return if(o != 0) bb.getDouble(o + bb_pos) else Double.NaN + } + fun mutateTestdNan(testdNan: Double) : Boolean { + val o = __offset(10) + return if (o != 0) { + bb.putDouble(o + bb_pos, testdNan) + true + } else { + false + } + } + val testdPinf : Double + get() { + val o = __offset(12) + return if(o != 0) bb.getDouble(o + bb_pos) else Double.POSITIVE_INFINITY + } + fun mutateTestdPinf(testdPinf: Double) : Boolean { + val o = __offset(12) + return if (o != 0) { + bb.putDouble(o + bb_pos, testdPinf) + true + } else { + false + } + } + val testdNinf : Double + get() { + val o = __offset(14) + return if(o != 0) bb.getDouble(o + bb_pos) else Double.NEGATIVE_INFINITY + } + fun mutateTestdNinf(testdNinf: Double) : Boolean { + val o = __offset(14) + return if (o != 0) { + bb.putDouble(o + bb_pos, testdNinf) + true + } else { + false + } + } + fun testfVec(j: Int) : Float { + val o = __offset(16) + return if (o != 0) { + bb.getFloat(__vector(o) + j * 4) + } else { + 0.0f + } + } + val testfVecLength : Int + get() { + val o = __offset(16); return if (o != 0) __vector_len(o) else 0 + } + val testfVecAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(16, 4) + fun testfVecInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 16, 4) + fun mutateTestfVec(j: Int, testfVec: Float) : Boolean { + val o = __offset(16) + return if (o != 0) { + bb.putFloat(__vector(o) + j * 4, testfVec) + true + } else { + false + } + } + fun testdVec(j: Int) : Double { + val o = __offset(18) + return if (o != 0) { + bb.getDouble(__vector(o) + j * 8) + } else { + 0.0 + } + } + val testdVecLength : Int + get() { + val o = __offset(18); return if (o != 0) __vector_len(o) else 0 + } + val testdVecAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(18, 8) + fun testdVecInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 18, 8) + fun mutateTestdVec(j: Int, testdVec: Double) : Boolean { + val o = __offset(18) + return if (o != 0) { + bb.putDouble(__vector(o) + j * 8, testdVec) + true + } else { + false + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsMonsterExtra(_bb: ByteBuffer): MonsterExtra = getRootAsMonsterExtra(_bb, MonsterExtra()) + fun getRootAsMonsterExtra(_bb: ByteBuffer, obj: MonsterExtra): MonsterExtra { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun MonsterExtraBufferHasIdentifier(_bb: ByteBuffer) : Boolean = __has_identifier(_bb, "MONE") + fun createMonsterExtra(builder: FlatBufferBuilder, testfNan: Float, testfPinf: Float, testfNinf: Float, testdNan: Double, testdPinf: Double, testdNinf: Double, testfVecOffset: Int, testdVecOffset: Int) : Int { + builder.startTable(8) + addTestdNinf(builder, testdNinf) + addTestdPinf(builder, testdPinf) + addTestdNan(builder, testdNan) + addTestdVec(builder, testdVecOffset) + addTestfVec(builder, testfVecOffset) + addTestfNinf(builder, testfNinf) + addTestfPinf(builder, testfPinf) + addTestfNan(builder, testfNan) + return endMonsterExtra(builder) + } + fun startMonsterExtra(builder: FlatBufferBuilder) = builder.startTable(8) + fun addTestfNan(builder: FlatBufferBuilder, testfNan: Float) = builder.addFloat(0, testfNan, Double.NaN) + fun addTestfPinf(builder: FlatBufferBuilder, testfPinf: Float) = builder.addFloat(1, testfPinf, Double.POSITIVE_INFINITY) + fun addTestfNinf(builder: FlatBufferBuilder, testfNinf: Float) = builder.addFloat(2, testfNinf, Double.NEGATIVE_INFINITY) + fun addTestdNan(builder: FlatBufferBuilder, testdNan: Double) = builder.addDouble(3, testdNan, Double.NaN) + fun addTestdPinf(builder: FlatBufferBuilder, testdPinf: Double) = builder.addDouble(4, testdPinf, Double.POSITIVE_INFINITY) + fun addTestdNinf(builder: FlatBufferBuilder, testdNinf: Double) = builder.addDouble(5, testdNinf, Double.NEGATIVE_INFINITY) + fun addTestfVec(builder: FlatBufferBuilder, testfVec: Int) = builder.addOffset(6, testfVec, 0) + fun createTestfVecVector(builder: FlatBufferBuilder, data: FloatArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addFloat(data[i]) + } + return builder.endVector() + } + fun startTestfVecVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun addTestdVec(builder: FlatBufferBuilder, testdVec: Int) = builder.addOffset(7, testdVec, 0) + fun createTestdVecVector(builder: FlatBufferBuilder, data: DoubleArray) : Int { + builder.startVector(8, data.size, 8) + for (i in data.size - 1 downTo 0) { + builder.addDouble(data[i]) + } + return builder.endVector() + } + fun startTestdVecVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8) + fun endMonsterExtra(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + fun finishMonsterExtraBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset, "MONE") + fun finishSizePrefixedMonsterExtraBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset, "MONE") + } +} diff --git a/tests/TestAll.sh b/tests/TestAll.sh index e36d079af..0fc0acdbc 100644 --- a/tests/TestAll.sh +++ b/tests/TestAll.sh @@ -2,6 +2,10 @@ echo "************************ Java:" sh JavaTest.sh +echo "************************ Kotlin:" + +sh KotlinTest.sh + echo "************************ Go:" sh GoTest.sh diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 3220b9871..d086c2f51 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -15,16 +15,16 @@ # limitations under the License. set -e -../flatc --cpp --java --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --grpc --gen-mutable --reflect-names --gen-object-api --gen-compare --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 --lobster --lua --python --js --ts --php --rust --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 --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs +../flatc --cpp --java --kotlin --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --grpc --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json +../flatc --cpp --java --kotlin --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --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 --kotlin --csharp --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs ../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs ../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs ../flatc --jsonschema --schema -I include_test monster_test.fbs -../flatc --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs monsterdata_extra.json +../flatc --cpp --java --kotlin --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs monsterdata_extra.json ../flatc --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --scoped-enums --jsonschema --cpp-ptr-type flatbuffers::unique_ptr arrays_test.fbs cd ../samples -../flatc --cpp --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs +../flatc --cpp --kotlin --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs ../flatc -b --schema --bfbs-comments --bfbs-builtins monster.fbs cd ../reflection ./generate_code.sh diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt new file mode 100644 index 000000000..0ede58cab --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt @@ -0,0 +1,15 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package NamespaceA.NamespaceB + +@Suppress("unused") +@ExperimentalUnsignedTypes +class EnumInNestedNS private constructor() { + companion object { + const val A: Byte = 0 + const val B: Byte = 1 + const val C: Byte = 2 + val names : Array = arrayOf("A", "B", "C") + fun name(e: Int) : String = names[e] + } +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt new file mode 100644 index 000000000..0273bb118 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt @@ -0,0 +1,32 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package NamespaceA.NamespaceB + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class StructInNestedNS : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : StructInNestedNS { + __init(_i, _bb) + return this + } + val a : Int get() = bb.getInt(bb_pos + 0) + fun mutateA(a: Int) : ByteBuffer = bb.putInt(bb_pos + 0, a) + val b : Int get() = bb.getInt(bb_pos + 4) + fun mutateB(b: Int) : ByteBuffer = bb.putInt(bb_pos + 4, b) + companion object { + fun createStructInNestedNS(builder: FlatBufferBuilder, a: Int, b: Int) : Int { + builder.prep(4, 8) + builder.putInt(b) + builder.putInt(a) + return builder.offset() + } + } +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt new file mode 100644 index 000000000..59ebdc9b9 --- /dev/null +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt @@ -0,0 +1,53 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package NamespaceA.NamespaceB + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class TableInNestedNS : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : TableInNestedNS { + __init(_i, _bb) + return this + } + val foo : Int + get() { + val o = __offset(4) + return if(o != 0) bb.getInt(o + bb_pos) else 0 + } + fun mutateFoo(foo: Int) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.putInt(o + bb_pos, foo) + true + } else { + false + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsTableInNestedNS(_bb: ByteBuffer): TableInNestedNS = getRootAsTableInNestedNS(_bb, TableInNestedNS()) + fun getRootAsTableInNestedNS(_bb: ByteBuffer, obj: TableInNestedNS): TableInNestedNS { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createTableInNestedNS(builder: FlatBufferBuilder, foo: Int) : Int { + builder.startTable(1) + addFoo(builder, foo) + return endTableInNestedNS(builder) + } + fun startTableInNestedNS(builder: FlatBufferBuilder) = builder.startTable(1) + fun addFoo(builder: FlatBufferBuilder, foo: Int) = builder.addInt(0, foo, 0) + fun endTableInNestedNS(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.kt b/tests/namespace_test/NamespaceA/SecondTableInA.kt new file mode 100644 index 000000000..8261443f8 --- /dev/null +++ b/tests/namespace_test/NamespaceA/SecondTableInA.kt @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package NamespaceA + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class SecondTableInA : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : SecondTableInA { + __init(_i, _bb) + return this + } + val referToC : NamespaceC.TableInC? get() = referToC(NamespaceC.TableInC()) + fun referToC(obj: NamespaceC.TableInC) : NamespaceC.TableInC? { + val o = __offset(4) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsSecondTableInA(_bb: ByteBuffer): SecondTableInA = getRootAsSecondTableInA(_bb, SecondTableInA()) + fun getRootAsSecondTableInA(_bb: ByteBuffer, obj: SecondTableInA): SecondTableInA { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createSecondTableInA(builder: FlatBufferBuilder, referToCOffset: Int) : Int { + builder.startTable(1) + addReferToC(builder, referToCOffset) + return endSecondTableInA(builder) + } + fun startSecondTableInA(builder: FlatBufferBuilder) = builder.startTable(1) + fun addReferToC(builder: FlatBufferBuilder, referToC: Int) = builder.addOffset(0, referToC, 0) + fun endSecondTableInA(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.kt b/tests/namespace_test/NamespaceA/TableInFirstNS.kt new file mode 100644 index 000000000..1ba0afcd4 --- /dev/null +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.kt @@ -0,0 +1,68 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package NamespaceA + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class TableInFirstNS : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : TableInFirstNS { + __init(_i, _bb) + return this + } + val fooTable : NamespaceA.NamespaceB.TableInNestedNS? get() = fooTable(NamespaceA.NamespaceB.TableInNestedNS()) + fun fooTable(obj: NamespaceA.NamespaceB.TableInNestedNS) : NamespaceA.NamespaceB.TableInNestedNS? { + val o = __offset(4) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + val fooEnum : Byte + get() { + val o = __offset(6) + return if(o != 0) bb.get(o + bb_pos) else 0 + } + fun mutateFooEnum(fooEnum: Byte) : Boolean { + val o = __offset(6) + return if (o != 0) { + bb.put(o + bb_pos, fooEnum) + true + } else { + false + } + } + val fooStruct : NamespaceA.NamespaceB.StructInNestedNS? get() = fooStruct(NamespaceA.NamespaceB.StructInNestedNS()) + fun fooStruct(obj: NamespaceA.NamespaceB.StructInNestedNS) : NamespaceA.NamespaceB.StructInNestedNS? { + val o = __offset(8) + return if (o != 0) { + obj.__assign(o + bb_pos, bb) + } else { + null + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsTableInFirstNS(_bb: ByteBuffer): TableInFirstNS = getRootAsTableInFirstNS(_bb, TableInFirstNS()) + fun getRootAsTableInFirstNS(_bb: ByteBuffer, obj: TableInFirstNS): TableInFirstNS { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun startTableInFirstNS(builder: FlatBufferBuilder) = builder.startTable(3) + fun addFooTable(builder: FlatBufferBuilder, fooTable: Int) = builder.addOffset(0, fooTable, 0) + fun addFooEnum(builder: FlatBufferBuilder, fooEnum: Byte) = builder.addByte(1, fooEnum, 0) + fun addFooStruct(builder: FlatBufferBuilder, fooStruct: Int) = builder.addStruct(2, fooStruct, 0) + fun endTableInFirstNS(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/namespace_test/NamespaceC/TableInC.kt b/tests/namespace_test/NamespaceC/TableInC.kt new file mode 100644 index 000000000..e46864284 --- /dev/null +++ b/tests/namespace_test/NamespaceC/TableInC.kt @@ -0,0 +1,59 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package NamespaceC + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class TableInC : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : TableInC { + __init(_i, _bb) + return this + } + val referToA1 : NamespaceA.TableInFirstNS? get() = referToA1(NamespaceA.TableInFirstNS()) + fun referToA1(obj: NamespaceA.TableInFirstNS) : NamespaceA.TableInFirstNS? { + val o = __offset(4) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + val referToA2 : NamespaceA.SecondTableInA? get() = referToA2(NamespaceA.SecondTableInA()) + fun referToA2(obj: NamespaceA.SecondTableInA) : NamespaceA.SecondTableInA? { + val o = __offset(6) + return if (o != 0) { + obj.__assign(__indirect(o + bb_pos), bb) + } else { + null + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsTableInC(_bb: ByteBuffer): TableInC = getRootAsTableInC(_bb, TableInC()) + fun getRootAsTableInC(_bb: ByteBuffer, obj: TableInC): TableInC { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createTableInC(builder: FlatBufferBuilder, referToA1Offset: Int, referToA2Offset: Int) : Int { + builder.startTable(2) + addReferToA2(builder, referToA2Offset) + addReferToA1(builder, referToA1Offset) + return endTableInC(builder) + } + fun startTableInC(builder: FlatBufferBuilder) = builder.startTable(2) + fun addReferToA1(builder: FlatBufferBuilder, referToA1: Int) = builder.addOffset(0, referToA1, 0) + fun addReferToA2(builder: FlatBufferBuilder, referToA2: Int) = builder.addOffset(1, referToA2, 0) + fun endTableInC(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/union_vector/Attacker.kt b/tests/union_vector/Attacker.kt new file mode 100644 index 000000000..7d3dc6813 --- /dev/null +++ b/tests/union_vector/Attacker.kt @@ -0,0 +1,51 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Attacker : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Attacker { + __init(_i, _bb) + return this + } + val swordAttackDamage : Int + get() { + val o = __offset(4) + return if(o != 0) bb.getInt(o + bb_pos) else 0 + } + fun mutateSwordAttackDamage(swordAttackDamage: Int) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.putInt(o + bb_pos, swordAttackDamage) + true + } else { + false + } + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsAttacker(_bb: ByteBuffer): Attacker = getRootAsAttacker(_bb, Attacker()) + fun getRootAsAttacker(_bb: ByteBuffer, obj: Attacker): Attacker { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun createAttacker(builder: FlatBufferBuilder, swordAttackDamage: Int) : Int { + builder.startTable(1) + addSwordAttackDamage(builder, swordAttackDamage) + return endAttacker(builder) + } + fun startAttacker(builder: FlatBufferBuilder) = builder.startTable(1) + fun addSwordAttackDamage(builder: FlatBufferBuilder, swordAttackDamage: Int) = builder.addInt(0, swordAttackDamage, 0) + fun endAttacker(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + } +} diff --git a/tests/union_vector/BookReader.kt b/tests/union_vector/BookReader.kt new file mode 100644 index 000000000..fc41473b1 --- /dev/null +++ b/tests/union_vector/BookReader.kt @@ -0,0 +1,27 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class BookReader : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : BookReader { + __init(_i, _bb) + return this + } + val booksRead : Int get() = bb.getInt(bb_pos + 0) + fun mutateBooksRead(booksRead: Int) : ByteBuffer = bb.putInt(bb_pos + 0, booksRead) + companion object { + fun createBookReader(builder: FlatBufferBuilder, booksRead: Int) : Int { + builder.prep(4, 4) + builder.putInt(booksRead) + return builder.offset() + } + } +} diff --git a/tests/union_vector/Character.kt b/tests/union_vector/Character.kt new file mode 100644 index 000000000..ff7dd5e84 --- /dev/null +++ b/tests/union_vector/Character.kt @@ -0,0 +1,17 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Character_ private constructor() { + companion object { + const val NONE: UByte = 0u + const val MuLan: UByte = 1u + const val Rapunzel: UByte = 2u + const val Belle: UByte = 3u + const val BookFan: UByte = 4u + const val Other: UByte = 5u + const val Unused: UByte = 6u + val names : Array = arrayOf("NONE", "MuLan", "Rapunzel", "Belle", "BookFan", "Other", "Unused") + fun name(e: Int) : String = names[e] + } +} diff --git a/tests/union_vector/Movie.kt b/tests/union_vector/Movie.kt new file mode 100644 index 000000000..b8a135ba8 --- /dev/null +++ b/tests/union_vector/Movie.kt @@ -0,0 +1,114 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Movie : Table() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Movie { + __init(_i, _bb) + return this + } + val mainCharacterType : UByte + get() { + val o = __offset(4) + return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u + } + fun mutateMainCharacterType(mainCharacterType: UByte) : Boolean { + val o = __offset(4) + return if (o != 0) { + bb.put(o + bb_pos, mainCharacterType.toByte()) + true + } else { + false + } + } + fun mainCharacter(obj: Table) : Table? { + val o = __offset(6); return if (o != 0) __union(obj, o) else null + } + fun charactersType(j: Int) : UByte { + val o = __offset(8) + return if (o != 0) { + bb.get(__vector(o) + j * 1).toUByte() + } else { + 0u + } + } + val charactersTypeLength : Int + get() { + val o = __offset(8); return if (o != 0) __vector_len(o) else 0 + } + val charactersTypeAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(8, 1) + fun charactersTypeInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 8, 1) + fun mutateCharactersType(j: Int, charactersType: UByte) : Boolean { + val o = __offset(8) + return if (o != 0) { + bb.put(__vector(o) + j * 1, charactersType.toByte()) + true + } else { + false + } + } + fun characters(obj: Table, j: Int) : Table? { + val o = __offset(10) + return if (o != 0) { + __union(obj, __vector(o) + j * 4 - bb_pos) + } else { + null + } + } + val charactersLength : Int + get() { + val o = __offset(10); return if (o != 0) __vector_len(o) else 0 + } + companion object { + fun validateVersion() = Constants.FLATBUFFERS_1_11_1() + fun getRootAsMovie(_bb: ByteBuffer): Movie = getRootAsMovie(_bb, Movie()) + fun getRootAsMovie(_bb: ByteBuffer, obj: Movie): Movie { + _bb.order(ByteOrder.LITTLE_ENDIAN) + return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) + } + fun MovieBufferHasIdentifier(_bb: ByteBuffer) : Boolean = __has_identifier(_bb, "MOVI") + fun createMovie(builder: FlatBufferBuilder, mainCharacterType: UByte, mainCharacterOffset: Int, charactersTypeOffset: Int, charactersOffset: Int) : Int { + builder.startTable(4) + addCharacters(builder, charactersOffset) + addCharactersType(builder, charactersTypeOffset) + addMainCharacter(builder, mainCharacterOffset) + addMainCharacterType(builder, mainCharacterType) + return endMovie(builder) + } + fun startMovie(builder: FlatBufferBuilder) = builder.startTable(4) + fun addMainCharacterType(builder: FlatBufferBuilder, mainCharacterType: UByte) = builder.addByte(0, mainCharacterType.toByte(), 0) + fun addMainCharacter(builder: FlatBufferBuilder, mainCharacter: Int) = builder.addOffset(1, mainCharacter, 0) + fun addCharactersType(builder: FlatBufferBuilder, charactersType: Int) = builder.addOffset(2, charactersType, 0) + fun createCharactersTypeVector(builder: FlatBufferBuilder, data: UByteArray) : Int { + builder.startVector(1, data.size, 1) + for (i in data.size - 1 downTo 0) { + builder.addByte(data[i].toByte()) + } + return builder.endVector() + } + fun startCharactersTypeVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1) + fun addCharacters(builder: FlatBufferBuilder, characters: Int) = builder.addOffset(3, characters, 0) + fun createCharactersVector(builder: FlatBufferBuilder, data: IntArray) : Int { + builder.startVector(4, data.size, 4) + for (i in data.size - 1 downTo 0) { + builder.addOffset(data[i]) + } + return builder.endVector() + } + fun startCharactersVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4) + fun endMovie(builder: FlatBufferBuilder) : Int { + val o = builder.endTable() + return o + } + fun finishMovieBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset, "MOVI") + fun finishSizePrefixedMovieBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset, "MOVI") + } +} diff --git a/tests/union_vector/Rapunzel.kt b/tests/union_vector/Rapunzel.kt new file mode 100644 index 000000000..080a7f7da --- /dev/null +++ b/tests/union_vector/Rapunzel.kt @@ -0,0 +1,27 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import java.nio.* +import kotlin.math.sign +import com.google.flatbuffers.* + +@Suppress("unused") +@ExperimentalUnsignedTypes +class Rapunzel : Struct() { + + fun __init(_i: Int, _bb: ByteBuffer) { + __reset(_i, _bb) + } + fun __assign(_i: Int, _bb: ByteBuffer) : Rapunzel { + __init(_i, _bb) + return this + } + val hairLength : Int get() = bb.getInt(bb_pos + 0) + fun mutateHairLength(hairLength: Int) : ByteBuffer = bb.putInt(bb_pos + 0, hairLength) + companion object { + fun createRapunzel(builder: FlatBufferBuilder, hairLength: Int) : Int { + builder.prep(4, 4) + builder.putInt(hairLength) + return builder.offset() + } + } +}