From: Derek Bailey Date: Thu, 5 Jul 2018 22:55:57 +0000 (-0700) Subject: Lua (5.3) Language addition (#4804) X-Git-Tag: v1.10.0~86 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ba5eb3b5cfb6eea74727e67cad599409f9d0af99;p=platform%2Fupstream%2Fflatbuffers.git Lua (5.3) Language addition (#4804) * starting Lua port of python implmention. Syncing commit * Bulk of Lua module port from Python done. Not tested, only static analysis. Need to work on binary strings. Started work on flatc lua code generation * Fixed all the basic errors to produced a binary output from the builder, don't know if it is generated correctly, but it contains data, so that must be good * fixed binary set command that was extending the array improperly * continued improvement * Moved lua submodules down a directory so their names don't clash with potential other modules. Added compat module to provide Lua versioning logic * Successful sample port from Python * working on testing Lua code with formal tests * continued to work on tests and fixes to code to make tests pass * Added reading buffer test * Changed binaryarray implmentation to use a temporary table for storing data, and then serialize it to a string when requested. This double the rate of building flatbuffers compared to the string approach. * Didn't need encode module as it just added another layer of indirection that isn't need * profiled reading buffers, optimizations to increase read performance of monster data to ~7 monster / millisecond * Writing profiler improvments. Get about ~2 monsters/millisecond building rate * removed Numpy generation from Lua (came from the Python port) * math.pow is deprecated in Lua 5.3, so changed to ^ notation. Also added .bat script for starting Lua tests * adding results of generate_code.bat * simple edits for code review in PR. * There was a buffer overflow in inserting the keywords into the unorder set for both the Lua and Python code gens. Changed insertion to use iterators. * fixed spacing issue * basic documenation/tutorial updates. Updated sample_binary.lua to reflect the tutorial better * removed windows-specific build step in Lua tests --- diff --git a/.gitignore b/.gitignore index 8f026d3..7773161 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ *.vcxproj.user *.sln *.suo +*.opendb *.keystore +**/.vs/** **/bin/** **/gen/** **/libs/** @@ -25,6 +27,8 @@ **/CMakeTestfile.cmake **/Debug/** **/Release/** +**/RelWithDebInfo/** +**/x64/ #build artifacts from VS build.xml local.properties project.properties diff --git a/CMakeLists.txt b/CMakeLists.txt index 90860c3..ffaff11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ set(FlatBuffers_Compiler_SRCS src/idl_gen_js.cpp src/idl_gen_php.cpp src/idl_gen_python.cpp + src/idl_gen_lua.cpp src/idl_gen_fbs.cpp src/idl_gen_grpc.cpp src/idl_gen_json_schema.cpp diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md index ff27476..351c38e 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, TypeScript, PHP, and Python. +serialization library for C++, C#, C, Go, Java, JavaScript, Lua, TypeScript, PHP, and Python. It was originally created at Google for game development and other performance-critical applications. @@ -134,6 +134,8 @@ sections provide a more in-depth usage guide. 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 + own programs. - How to [use the generated JavaScript code](@ref flatbuffers_guide_use_javascript) in your own programs. - How to [use the generated TypeScript code](@ref flatbuffers_guide_use_typescript) in your diff --git a/docs/source/LuaUsage.md b/docs/source/LuaUsage.md new file mode 100644 index 0000000..75b1f3b --- /dev/null +++ b/docs/source/LuaUsage.md @@ -0,0 +1,81 @@ +Use in Lua {#flatbuffers_guide_use_lua} +============= + +## Before you get started + +Before diving into the FlatBuffers usage in Lua, 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 Lua). This +page is designed to cover the nuances of FlatBuffers usage, specific to +Lua. + +You should also have read the [Building](@ref flatbuffers_guide_building) +documentation to build `flatc` and should be familiar with +[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and +[Writing a schema](@ref flatbuffers_guide_writing_schema). + +## FlatBuffers Lua library code location + +The code for the FlatBuffers Lua library can be found at +`flatbuffers/lua`. You can browse the library code on the +[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/lua). + +## Testing the FlatBuffers Lua library + +The code to test the Lua library can be found at `flatbuffers/tests`. +The test code itself is located in [luatest.lua](https://github.com/google/ +flatbuffers/blob/master/tests/luatest.lua). + +To run the tests, use the [LuaTest.sh](https://github.com/google/flatbuffers/ +blob/master/tests/LuaTest.sh) shell script. + +*Note: This script requires [Lua 5.3](https://www.lua.org/) to be +installed.* + +## Using the FlatBuffers Lua library + +*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth +example of how to use FlatBuffers in Lua.* + +There is support for both reading and writing FlatBuffers in Lua. + +To use FlatBuffers in your own code, first generate Lua classes from your +schema with the `--lua` 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 Lua: +First, require the module and the generated code. Then read a FlatBuffer binary +file into a `string`, which you pass to the `GetRootAsMonster` function: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua} + -- require the library + local flatbuffers = require("flatbuffers") + + -- require the generated code + local monster = require("MyGame.Sample.Monster") + + -- read the flatbuffer from a file into a string + local f = io.open('monster.dat', 'rb') + local buf = f:read('*a') + f:close() + + -- parse the flatbuffer to get an instance to the root monster + local monster1 = monster.GetRootAsMonster(buf, 0) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now you can access values like this: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua} + -- use the : notation to access member data + local hp = monster1:Hp() + local pos = monster1:Pos() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +## Text Parsing + +There currently is no support for parsing text (Schema's and JSON) directly +from Lua, though you could use the C++ parser through SWIG or ctypes. Please +see the C++ documentation for more on text parsing. + +
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index 2d0e0d8..11fe4c8 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -31,6 +31,7 @@ Please select your desired language for our quest: PHP C Dart + Lua \endhtmlonly @@ -136,6 +137,10 @@ For your chosen language, please cross-reference with:
[example.dart](https://github.com/google/flatbuffers/blob/master/dart/example/example.dart)
+
+[sample_binary.lua](https://github.com/google/flatbuffers/blob/master/dart/example/sample_binary.lua) +
+ ## Writing the Monsters' FlatBuffer Schema @@ -322,6 +327,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools. ./../flatc --dart monster.fbs ~~~ +
+~~~{.sh} + cd flatbuffers/sample + ./../flatc --lua monster.fbs +~~~ +
For a more complete guide to using the `flatc` compiler, please read the [Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) @@ -439,6 +450,19 @@ The first step is to import/include the library, generated files, etc. import 'monster_my_game.sample_generated.dart' as myGame; ~~~ +
+~~~{.lua} + -- require the flatbuffers module + local flatbuffers = require("flatbuffers") + + -- require the generated files from `flatc`. + local color = require("MyGame.Sample.Color") + local equipment = require("MyGame.Sample.Equipment") + local monster = require("MyGame.Sample.Monster") + local vec3 = require("MyGame.Sample.Vec3") + local weapon = require("MyGame.Sample.Weapon") +~~~ +
Now we are ready to start building some buffers. In order to start, we need to create an instance of the `FlatBufferBuilder`, which will contain the buffer @@ -518,6 +542,12 @@ which will grow automatically if needed: var builder = new fb.Builder(initialSize: 1024); ~~~ +
+~~~{.lua} + -- get access to the builder, providing an array of size 1024 + local builder = flatbuffers.Builder(1024) +~~~ +
After creating the `builder`, we can start serializing our data. Before we make our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. @@ -705,6 +735,24 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`. ); ~~~ +
+~~~{.lua} + local weaponOne = builder:CreateString("Sword") + local weaponTwo = builder:CreateString("Axe") + + -- Create the first 'Weapon' + weapon.Start(builder) + weapon.AddName(builder, weaponOne) + weapon.AddDamage(builder, 3) + local sword = weapon.End(builder) + + -- Create the second 'Weapon' + weapon.Start(builder) + weapon.AddName(builder, weaponTwo) + weapon.AddDamage(builder, 5) + local axe = weapon.End(builder) +~~~ +
Now let's create our monster, the `orc`. For this `orc`, lets make him `red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him @@ -852,6 +900,21 @@ traversal. This is generally easy to do on any tree structures. final List treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; ~~~ +
+~~~{.py} + -- Serialize a name for our mosnter, called 'orc' + local name = builder:CreateString("Orc") + + -- Create a `vector` representing the inventory of the Orc. Each number + -- could correspond to an item that can be claimed after he is slain. + -- Note: Since we prepend the bytes, this loop iterates in reverse. + monster.StartInventoryVector(builder, 10) + for i=10,1,-1 do + builder:PrependByte(i) + end + local inv = builder:EndVector(10) +~~~ +
We serialized two built-in data types (`string` and `vector`) and captured their return values. These values are offsets into the serialized data, @@ -964,6 +1027,16 @@ offsets. final List weaps = [sword, axe]; ~~~ +
+~~~{.lua} + -- Create a FlatBuffer vector and prepend the weapons. + -- Note: Since we prepend the data, prepend them in reverse order. + monster.StartWeaponsVector(builder, 2) + builder:PrependUOffsetTRelative(axe) + builder:PrependUOffsetTRelative(sword) + local weapons = builder:EndVector(2) +~~~ +

@@ -1063,6 +1136,16 @@ for the `path` field above: ]; ~~~
+
+~~~{.lua} + -- Create a FlatBuffer vector and prepend the path locations. + -- Note: Since we prepend the data, prepend them in reverse order. + monster.StartPathVector(builder, 2) + vec3.CreateVec3(builder, 1.0, 2.0, 3.0) + vec3.CreateVec3(builder, 4.0, 5.0, 6.0) + local path = builder:EndVector(2) +~~~ +
We have now serialized the non-scalar components of the orc, so we can serialize the monster itself: @@ -1267,6 +1350,22 @@ can serialize the monster itself: final int orc = orcBuilder.finish(builder); ~~~ +
+~~~{.lua} + -- Create our monster by using Start() andEnd() + monster.Start(builder) + monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0)) + monster.AddHp(builder, 300) + monster.AddName(builder, name) + monster.AddInventory(builder, inv) + monster.AddColor(builder, color.Red) + monster.AddWeapons(builder, weapons) + monster.AddEquippedType(builder, equipment.Weapon) + monster.AddEquipped(builder, axe) + monster.AddPath(builder, path) + local orc = monster.End(builder) +~~~ +
Note how we create `Vec3` struct in-line in the table. Unlike tables, structs are simple combinations of scalars that are always stored inline, just like @@ -1409,6 +1508,12 @@ Here is a repetition these lines, to help highlight them more clearly: equipped: axe, // Union data ~~~ +
+~~~{.lua} + monster.AddEquippedType(builder, equipment.Weapon) -- Union type + monster.AddEquipped(builder, axe) -- Union data +~~~ +
After you have created your buffer, you will have the offset to the root of the data in the `orc` variable, so you can finish the buffer by calling the @@ -1480,6 +1585,13 @@ appropriate `finish` method. // See the next code section, as in Dart `finish` will also return the byte array. ~~~ +
+~~~{.lua} + -- Call 'Finish()' to instruct the builder that this monster is complete. + builder:Finish(orc) +~~~ +
+ The buffer is now ready to be stored somewhere, sent over the network, be compressed, or whatever you'd like to do with it. You can access the buffer @@ -1577,6 +1689,13 @@ like so: final Uint8List buf = builder.finish(orc); ~~~ +
+~~~{.lua} + -- Get the flatbuffer as a string containing the binary data + local bufAsString = builder:Output() +~~~ +
+ Now you can write the bytes to a file, send them over the network.. **Make sure your file mode (or tranfer protocol) is set to BINARY, not text.** @@ -1690,6 +1809,19 @@ import 'package:flat_buffers/flat_buffers.dart' as fb; import './monster_my_game.sample_generated.dart' as myGame; ~~~ +
+~~~{.lua} + -- require the flatbuffers module + local flatbuffers = require("flatbuffers") + + -- require the generated files from `flatc`. + local color = require("MyGame.Sample.Color") + local equipment = require("MyGame.Sample.Equipment") + local monster = require("MyGame.Sample.Monster") + local vec3 = require("MyGame.Sample.Vec3") + local weapon = require("MyGame.Sample.Weapon") +~~~ +
Then, assuming you have a buffer of bytes received from disk, network, etc., you can create start accessing the buffer like so: @@ -1798,6 +1930,17 @@ List data = ... // the data, e.g. from file or network myGame.Monster monster = new myGame.Monster(data); ~~~ +
+~~~{.lua} + local bufAsString = -- The data you just read in + + -- Convert the string representation into binary array Lua structure + local buf = flatbuffers.binaryArray.New(bufAsString) + + -- Get an accessor to the root object insert the buffer + local mon = monster.GetRootAsMonster(buf, 0) +~~~ +
If you look in the generated files from the schema compiler, you will see it generated accessors for all non-`deprecated` fields. For example: @@ -1876,6 +2019,13 @@ accessors for all non-`deprecated` fields. For example: var name = monster.name; ~~~ +
+~~~{.lua} + local hp = mon:Hp() + local mana = mon:Mana() + local name = mon:Name() +~~~ +
These should hold `300`, `150`, and `"Orc"` respectively. @@ -1969,6 +2119,15 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`: double z = pos.z; ~~~ +
+~~~{.lua} + local pos = mon:Pos() + local x = pos:X() + local y = pos:Y() + local z = pos:Z() +~~~ +
+ `x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively. @@ -2041,6 +2200,12 @@ FlatBuffers `vector`. var thirdItem = monster.inventory[2]; ~~~ +
+~~~{.lua} + local invLength = mon:InventoryLength() + local thirdItem = mon:Inventory(3) -- Lua is 1-based +~~~ +
For `vector`s of `table`s, you can access the elements like any other vector, except your need to handle the result as a FlatBuffer `table`: @@ -2122,6 +2287,13 @@ except your need to handle the result as a FlatBuffer `table`: var secondWeaponDamage = monster.Weapons[1].damage; ~~~ +
+~~~{.lua} + local weaponsLength = mon:WeaponsLength() + local secondWeaponName = mon:Weapon(2):Name() + local secondWeaponDamage = mon:Weapon(2):Damage() +~~~ +
Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created the `union`, we need to get both parts of the `union`: the type and the data. @@ -2257,6 +2429,19 @@ We can access the type to dynamically cast the data as needed (since the } ~~~ +
+~~~{.lua} + local unionType = mon:EquippedType() + + if unionType == equipment.Weapon then + local unionWeapon = weapon.New() + unionWeapon:Init(mon:Equipped().bytes, mon:Equipped().pos) + + local weaponName = unionWeapon:Name() -- 'Axe' + local weaponDamage = unionWeapon:Damage() -- 5 + end +~~~ +
## Mutating FlatBuffers @@ -2337,6 +2522,11 @@ mutators like so: ~~~ +
+~~~{.lua} + +~~~ +
We use the somewhat verbose term `mutate` instead of `set` to indicate that this is a special use case, not to be confused with the default way of constructing @@ -2449,5 +2639,9 @@ For your chosen language, see:
[Use in Dart](@ref flatbuffers_guide_use_dart)
+
+[Use in Lua](@ref flatbuffers_guide_use_lua) +
+
diff --git a/docs/source/doxyfile b/docs/source/doxyfile index b4e84fa..8cc46cc 100644 --- a/docs/source/doxyfile +++ b/docs/source/doxyfile @@ -758,6 +758,7 @@ INPUT = "FlatBuffers.md" \ "TypeScriptUsage.md" \ "PHPUsage.md" \ "PythonUsage.md" \ + "LuaUsage.md" \ "Support.md" \ "Benchmarks.md" \ "WhitePaper.md" \ diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml index c723314..c002295 100644 --- a/docs/source/doxygen_layout.xml +++ b/docs/source/doxygen_layout.xml @@ -41,6 +41,8 @@ title="Use in Python"/> + diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 88d9553..55ef89d 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -408,6 +408,7 @@ struct IDLOptions { kTs = 1 << 9, kJsonSchema = 1 << 10, kDart = 1 << 11, + kLua = 1 << 12, kMAX }; @@ -814,6 +815,12 @@ extern bool GeneratePython(const Parser &parser, const std::string &path, const std::string &file_name); +// Generate Lua files from the definitions in the Parser object. +// See idl_gen_lua.cpp. +extern bool GenerateLua(const Parser &parser, + const std::string &path, + const std::string &file_name); + // Generate Json schema file // See idl_gen_json_schema.cpp. extern bool GenerateJsonSchema(const Parser &parser, diff --git a/lua/flatbuffers.lua b/lua/flatbuffers.lua new file mode 100644 index 0000000..1c85c4e --- /dev/null +++ b/lua/flatbuffers.lua @@ -0,0 +1,8 @@ +local m = {} + +m.Builder = require("flatbuffers.builder").New +m.N = require("flatbuffers.numTypes") +m.view = require("flatbuffers.view") +m.binaryArray = require("flatbuffers.binaryarray") + +return m \ No newline at end of file diff --git a/lua/flatbuffers/binaryarray.lua b/lua/flatbuffers/binaryarray.lua new file mode 100644 index 0000000..bf728cd --- /dev/null +++ b/lua/flatbuffers/binaryarray.lua @@ -0,0 +1,123 @@ +local m = {} -- the module table + +local mt = {} -- the module metatable + +-- given a binary array, set a metamethod to return its length +-- (e.g., #binaryArray, calls this) +function mt:__len() + return self.size +end + +-- Create a new binary array of an initial size +function m.New(sizeOrString) + -- the array storage itself + local o = {} + + if type(sizeOrString) == "string" then + o.str = sizeOrString + o.size = #sizeOrString + elseif type(sizeOrString) == "number" then + o.data = {} + o.size = sizeOrString + else + error("Expect a integer size value or string to construct a binary array") + end + -- set the inheritance + setmetatable(o, {__index = mt, __len = mt.__len}) + return o +end + +-- Get a slice of the binary array from start to end position +function mt:Slice(startPos, endPos) + startPos = startPos or 0 + endPos = endPos or self.size + local d = self.data + if d then + -- if the self.data is defined, we are building the buffer + -- in a Lua table + + -- new table to store the slice components + local b = {} + + -- starting with the startPos, put all + -- values into the new table to be concat later + -- updated the startPos based on the size of the + -- value + while startPos < endPos do + local v = d[startPos] or '/0' + table.insert(b, v) + startPos = startPos + #v + end + + -- combine the table of strings into one string + -- this is faster than doing a bunch of concats by themselves + return table.concat(b) + else + -- n.b start/endPos are 0-based incoming, so need to convert + -- correctly. in python a slice includes start -> end - 1 + return self.str:sub(startPos+1, endPos) + end +end + +-- Grow the binary array to a new size, placing the exisiting data +-- at then end of the new array +function mt:Grow(newsize) + -- the new table to store the data + local newT = {} + + -- the offset to be applied to existing entries + local offset = newsize - self.size + + -- loop over all the current entries and + -- add them to the new table at the correct + -- offset location + local d = self.data + for i,data in pairs(d) do + newT[i + offset] = data + end + + -- update this storage with the new table and size + self.data = newT + self.size = newsize +end + +-- memorization for padding strings +local pads = {} + +-- pad the binary with n \0 bytes at the starting position +function mt:Pad(n, startPos) + -- use memorization to avoid creating a bunch of strings + -- all the time + local s = pads[n] + if not s then + s = string.rep('\0', n) + pads[n] = s + end + + -- store the padding string at the start position in the + -- Lua table + self.data[startPos] = s +end + +-- Sets the binary array value at the specified position +function mt:Set(value, position) + self.data[position] = value +end + +-- locals for slightly faster access +local sunpack = string.unpack +local spack = string.pack + +-- Pack the data into a binary representation +function m.Pack(fmt, ...) + return spack(fmt, ...) +end + +-- Unpack the data from a binary representation in +-- a Lua value +function m.Unpack(fmt, s, pos) + return sunpack(fmt, s.str, pos + 1) +end + +-- Return the binary array module +return m \ No newline at end of file diff --git a/lua/flatbuffers/builder.lua b/lua/flatbuffers/builder.lua new file mode 100644 index 0000000..d20783b --- /dev/null +++ b/lua/flatbuffers/builder.lua @@ -0,0 +1,368 @@ +local N = require("flatbuffers.numTypes") +local ba = require("flatbuffers.binaryarray") +local compat = require("flatbuffers.compat") + +local m = {} + +local mt = {} + +-- get locals for faster access +local VOffsetT = N.VOffsetT +local UOffsetT = N.UOffsetT +local SOffsetT = N.SOffsetT +local Bool = N.Bool +local Uint8 = N.Uint8 +local Uint16 = N.Uint16 +local Uint32 = N.Uint32 +local Uint64 = N.Uint64 +local Int8 = N.Int8 +local Int16 = N.Int16 +local Int32 = N.Int32 +local Int64 = N.Int64 +local Float32 = N.Float32 +local Float64 = N.Float64 + +local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB +local VtableMetadataFields = 2 + +local getAlignSize = compat.GetAlignSize + +local function vtableEqual(a, objectStart, b) + UOffsetT:EnforceNumber(objectStart) + if (#a * VOffsetT.bytewidth) ~= #b then + return false + end + + for i, elem in ipairs(a) do + local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth) + if x ~= 0 or elem ~= 0 then + local y = objectStart - elem + if x ~= y then + return false + end + end + end + return true +end + +function m.New(initialSize) + assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE) + local o = + { + finished = false, + bytes = ba.New(initialSize), + nested = false, + head = initialSize, + minalign = 1, + vtables = {} + } + setmetatable(o, {__index = mt}) + return o +end + +function mt:Output(full) + assert(self.finished, "Builder Not Finished") + if full then + return self.bytes:Slice() + else + return self.bytes:Slice(self.head) + end +end + +function mt:StartObject(numFields) + assert(not self.nested) + + local vtable = {} + + for _=1,numFields do + table.insert(vtable, 0) + end + + self.currentVTable = vtable + self.objectEnd = self:Offset() + self.minalign = 1 + self.nested = true +end + +function mt:WriteVtable() + self:PrependSOffsetTRelative(0) + local objectOffset = self:Offset() + + local exisitingVTable + local i = #self.vtables + while i >= 1 do + if self.vtables[i] == 0 then + table.remove(self.vtables,i) + end + i = i - 1 + end + + while i >= 1 do + + local vt2Offset = self.vtables[i] + local vt2Start = #self.bytes - vt2Offset + local vt2len = VOffsetT:Unpack(self.bytes, vt2Start) + + local metadata = VtableMetadataFields * VOffsetT.bytewidth + local vt2End = vt2Start + vt2Len + local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End) + + if vtableEqual(self.currentVTable, objectOffset, vt2) then + exisitingVTable = vt2Offset + break + end + + i = i - 1 + end + + if not exisitingVTable then + i = #self.currentVTable + while i >= 1 do + local off = 0 + local a = self.currentVTable[i] + if a and a ~= 0 then + off = objectOffset - a + end + self:PrependVOffsetT(off) + + i = i - 1 + end + + local objectSize = objectOffset - self.objectEnd + self:PrependVOffsetT(objectSize) + + local vBytes = #self.currentVTable + VtableMetadataFields + vBytes = vBytes * VOffsetT.bytewidth + self:PrependVOffsetT(vBytes) + + local objectStart = #self.bytes - objectOffset + self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart) + + table.insert(self.vtables, self:Offset()) + else + local objectStart = #self.bytes - objectOffset + self.head = objectStart + self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head) + end + + self.currentVTable = nil + return objectOffset +end + +function mt:EndObject() + assert(self.nested) + self.nested = false + return self:WriteVtable() +end + +local function growByteBuffer(self, desiredSize) + local s = #self.bytes + assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes") + local newsize = s + repeat + newsize = math.min(newsize * 2, MAX_BUFFER_SIZE) + if newsize == 0 then newsize = 1 end + until newsize > desiredSize + + self.bytes:Grow(newsize) +end + +function mt:Head() + return self.head +end + +function mt:Offset() + return #self.bytes - self.head +end + +function mt:Pad(n) + if n > 0 then + -- pads are 8-bit, so skip the bytewidth lookup + local h = self.head - n -- UInt8 + self.head = h + self.bytes:Pad(n, h) + end +end + +function mt:Prep(size, additionalBytes) + if size > self.minalign then + self.minalign = size + end + + local h = self.head + + local k = #self.bytes - h + additionalBytes + local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size) + + local desiredSize = alignsize + size + additionalBytes + + while self.head < desiredSize do + local oldBufSize = #self.bytes + growByteBuffer(self, desiredSize) + local updatedHead = self.head + #self.bytes - oldBufSize + self.head = updatedHead + end + + self:Pad(alignsize) +end + +function mt:PrependSOffsetTRelative(off) + self:Prep(SOffsetT.bytewidth, 0) + assert(off <= self:Offset(), "Offset arithmetic error") + local off2 = self:Offset() - off + SOffsetT.bytewidth + self:Place(off2, SOffsetT) +end + +function mt:PrependUOffsetTRelative(off) + self:Prep(UOffsetT.bytewidth, 0) + local soffset = self:Offset() + if off <= soffset then + local off2 = soffset - off + UOffsetT.bytewidth + self:Place(off2, UOffsetT) + else + error("Offset arithmetic error") + end +end + +function mt:StartVector(elemSize, numElements, alignment) + assert(not self.nested) + self.nested = true + self:Prep(Uint32.bytewidth, elemSize * numElements) + self:Prep(alignment, elemSize * numElements) + return self:Offset() +end + +function mt:EndVector(vectorNumElements) + assert(self.nested) + self.nested = false + self:Place(vectorNumElements, UOffsetT) + return self:Offset() +end + +function mt:CreateString(s) + assert(not self.nested) + self.nested = true + + assert(type(s) == "string") + + self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth) + self:Place(0, Uint8) + + local l = #s + self.head = self.head - l + + self.bytes:Set(s, self.head, self.head + l) + + return self:EndVector(#s) +end + +function mt:CreateByteVector(x) + assert(not self.nested) + self.nested = true + self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth) + + local l = #x + self.head = self.head - l + + self.bytes:Set(x, self.head, self.head + l) + + return self:EndVector(#x) +end + +function mt:Slot(slotnum) + assert(self.nested) + -- n.b. slot number is 0-based + self.currentVTable[slotnum + 1] = self:Offset() +end + +local function finish(self, rootTable, sizePrefix) + UOffsetT:EnforceNumber(rootTable) + local prepSize = UOffsetT.bytewidth + if sizePrefix then + prepSize = prepSize + Int32.bytewidth + end + + self:Prep(self.minalign, prepSize) + self:PrependUOffsetTRelative(rootTable) + if sizePrefix then + local size = #self.bytes - self.head + Int32:EnforceNumber(size) + self:PrependInt32(size) + end + self.finished = true + return self.head +end + +function mt:Finish(rootTable) + return finish(self, rootTable, false) +end + +function mt:FinishSizePrefixed(rootTable) + return finish(self, rootTable, true) +end + +function mt:Prepend(flags, off) + self:Prep(flags.bytewidth, 0) + self:Place(off, flags) +end + +function mt:PrependSlot(flags, o, x, d) + flags:EnforceNumber(x) + flags:EnforceNumber(d) + if x ~= d then + self:Prepend(flags, x) + self:Slot(o) + end +end + +function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end +function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end +function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end +function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end +function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end +function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end +function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end +function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end +function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end +function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end +function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end +function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end + +function mt:PrependUOffsetTRelativeSlot(o,x,d) + if x~=d then + self:PrependUOffsetTRelative(x) + self:Slot(o) + end +end + +function mt:PrependStructSlot(v,x,d) + UOffsetT:EnforceNumber(d) + if x~=d then + UOffsetT:EnforceNumber(x) + assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.") + self:Slot(v) + end +end + +function mt:PrependBool(x) self:Prepend(Bool, x) end +function mt:PrependByte(x) self:Prepend(Uint8, x) end +function mt:PrependUint8(x) self:Prepend(Uint8, x) end +function mt:PrependUint16(x) self:Prepend(Uint16, x) end +function mt:PrependUint32(x) self:Prepend(Uint32, x) end +function mt:PrependUint64(x) self:Prepend(Uint64, x) end +function mt:PrependInt8(x) self:Prepend(Int8, x) end +function mt:PrependInt16(x) self:Prepend(Int16, x) end +function mt:PrependInt32(x) self:Prepend(Int32, x) end +function mt:PrependInt64(x) self:Prepend(Int64, x) end +function mt:PrependFloat32(x) self:Prepend(Float32, x) end +function mt:PrependFloat64(x) self:Prepend(Float64, x) end +function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end + +function mt:Place(x, flags) + local d = flags:EnforceNumberAndPack(x) + local h = self.head - flags.bytewidth + self.head = h + self.bytes:Set(d, h) +end + +return m \ No newline at end of file diff --git a/lua/flatbuffers/compat.lua b/lua/flatbuffers/compat.lua new file mode 100644 index 0000000..89c992b --- /dev/null +++ b/lua/flatbuffers/compat.lua @@ -0,0 +1,17 @@ +local m = {} + +local getAlignSize +if _VERSION == "Lua 5.3" then + getAlignSize = function(k, size) + return ((~k) + 1) & (size - 1) + end +else + getAlignSize = function(self, size, additionalBytes) + local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1 + return bit32.band(alignsize,(size - 1)) + end +end + +m.GetAlignSize = getAlignSize + +return m \ No newline at end of file diff --git a/lua/flatbuffers/numTypes.lua b/lua/flatbuffers/numTypes.lua new file mode 100644 index 0000000..e8d87e1 --- /dev/null +++ b/lua/flatbuffers/numTypes.lua @@ -0,0 +1,198 @@ +local m = {} + +local ba = require("flatbuffers.binaryarray") + +local bpack = ba.Pack +local bunpack = ba.Unpack + +local type_mt = {} + +function type_mt:Pack(value) + return bpack(self.packFmt, value) +end + +function type_mt:Unpack(buf, pos) + return bunpack(self.packFmt, buf, pos) +end + +function type_mt:ValidNumber(n) + if not self.min_value and not self.max_value then return true end + return self.min_value <= n and n <= self.max_value +end + +function type_mt:EnforceNumber(n) + -- duplicate code since the overhead of function calls + -- for such a popular method is time consuming + if not self.min_value and not self.max_value then + return + end + + if self.min_value <= n and n <= self.max_value then + return + end + + error("Number is not in the valid range") +end + +function type_mt:EnforceNumberAndPack(n) + return bpack(self.packFmt, n) +end + +function type_mt:ConvertType(n, otherType) + assert(self.bytewidth == otherType.bytewidth, "Cannot convert between types of different widths") + if self == otherType then + return n + end + return otherType:Unpack(self:Pack(n)) +end + +local bool_mt = +{ + bytewidth = 1, + min_value = false, + max_value = true, + lua_type = type(true), + name = "bool", + packFmt = " + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +#include + +namespace flatbuffers { +namespace lua { + + // Hardcode spaces per indentation. + const char * Indent = " "; + const char * Comment = "-- "; + const char * End = "end\n"; + const char * EndFunc = "end\n"; + const char * SelfData = "self.view"; + const char * SelfDataPos = "self.view.pos"; + const char * SelfDataBytes = "self.view.bytes"; + + class LuaGenerator : public BaseGenerator { + public: + LuaGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "" /* not used */, + "" /* not used */) { + static const char * const keywords[] = { + "and", + "break", + "do", + "else", + "elseif", + "end", + "false", + "for", + "function", + "goto", + "if", + "in", + "local", + "nil", + "not", + "or", + "repeat", + "return", + "then", + "true", + "until", + "while" + }; + keywords_.insert(std::begin(keywords), std::end(keywords)); + } + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that. + std::string OffsetPrefix(const FieldDef &field) { + return std::string(Indent) + + "local o = " + SelfData + ":Offset(" + NumToString(field.value.offset) + ")\n" + + Indent + "if o ~= 0 then\n"; + } + + // Begin a class declaration. + void BeginClass(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "local " + NormalizedName(struct_def) + " = {} -- the module\n"; + code += "local " + NormalizedMetaName(struct_def) + " = {} -- the class metatable\n"; + code += "\n"; + } + + // Begin enum code with a class declaration. + void BeginEnum(const std::string class_name, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "local " + class_name + " = {\n"; + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : "_" + name; + } + + std::string NormalizedName(const Definition &definition) const { + return EscapeKeyword(definition.name); + } + + std::string NormalizedName(const EnumVal &ev) const { + return EscapeKeyword(ev.name); + } + + std::string NormalizedMetaName(const Definition &definition) const { + return EscapeKeyword(definition.name) + "_mt"; + } + + // A single enum member. + void EnumMember(const EnumVal ev, std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Indent) + NormalizedName(ev) + " = " + NumToString(ev.value) + ",\n"; + } + + // End enum code. + void EndEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n"; + } + + void GenerateNewObjectPrototype(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "function " + NormalizedName(struct_def) + ".New()\n"; + code += std::string(Indent) + "local o = {}\n"; + code += std::string(Indent) + "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) + "})\n"; + code += std::string(Indent) + "return o\n"; + code += EndFunc; + } + + // Initialize a new struct or table from existing data. + void NewRootTypeFromBuffer(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "function " + NormalizedName(struct_def) + ".GetRootAs" + NormalizedName(struct_def) + "(buf, offset)\n"; + code += std::string(Indent) + "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n"; + code += std::string(Indent) + "local o = " + NormalizedName(struct_def) + ".New()\n"; + code += std::string(Indent) + "o:Init(buf, n + offset)\n"; + code += std::string(Indent) + "return o\n"; + code += EndFunc; + } + + // Initialize an existing object with other data, to avoid an allocation. + void InitializeExisting(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += "Init(buf, pos)\n"; + code += std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n"; + code += EndFunc; + } + + // Get the length of a vector. + void GetVectorLen(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "Length()\n"; + code += OffsetPrefix(field); + code += std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n"; + code += std::string(Indent) + End; + code += std::string(Indent) + "return 0\n"; + code += EndFunc; + } + + // Get the value of a struct's scalar. + void GetScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += std::string(Indent) + "return " + getter; + code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) + ")\n"; + code += EndFunc; + } + + // Get the value of a table's scalar. + void GetScalarFieldOfTable(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += OffsetPrefix(field); + getter += std::string("o + ") + SelfDataPos + ")"; + auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL; + if (is_bool) { + getter = "(" + getter + " ~= 0)"; + } + code += std::string(Indent) + Indent + "return " + getter + "\n"; + code += std::string(Indent) + End; + std::string default_value; + if (is_bool) { + default_value = field.value.constant == "0" ? "false" : "true"; + } + else { + default_value = field.value.constant; + } + code += std::string(Indent) + "return " + default_value + "\n"; + code += EndFunc; + } + + // Get a struct by initializing an existing struct. + // Specific to Struct. + void GetStructFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(obj)\n"; + code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " + SelfDataPos + " + "; + code += NumToString(field.value.offset) + ")\n"; + code += std::string(Indent) + "return obj\n"; + code += EndFunc; + } + + // Get a struct by initializing an existing struct. + // Specific to Table. + void GetStructFieldOfTable(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += OffsetPrefix(field); + if (field.value.type.struct_def->fixed) { + code += std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n"; + } + else { + code += std::string(Indent) + Indent + "local x = " + SelfData + ":Indirect(o + " + SelfDataPos + ")\n"; + } + code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n"; + code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n"; + code += std::string(Indent) + Indent + "return obj\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a string. + void GetStringField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += OffsetPrefix(field); + code += std::string(Indent) + Indent + "return " + GenGetter(field.value.type); + code += std::string("o + ") + SelfDataPos + ")\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a union from an object. + void GetUnionField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "()\n"; + code += OffsetPrefix(field); + + // TODO(rw): this works and is not the good way to it: + //bool is_native_table = TypeName(field) == "*flatbuffers.Table"; + //if (is_native_table) { + // code += std::string(Indent) + Indent + "from flatbuffers.table import Table\n"; + //} else { + // code += std::string(Indent) + Indent + + // code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n"; + //} + code += std::string(Indent) + Indent + "local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n"; + code += std::string(Indent) + Indent + GenGetter(field.value.type) + "obj, o)\n"; + code += std::string(Indent) + Indent + "return obj\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a vector's struct member. + void GetMemberOfVectorOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(j)\n"; + code += OffsetPrefix(field); + code += std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n"; + code += std::string(Indent) + Indent + "x = x + ((j-1) * "; + code += NumToString(InlineSize(vectortype)) + ")\n"; + if (!(vectortype.struct_def->fixed)) { + code += std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n"; + } + code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n"; + code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n"; + code += std::string(Indent) + Indent + "return obj\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a vector's non-struct member. Uses a named return + // argument to conveniently set the zero value for the result. + void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(j)\n"; + code += OffsetPrefix(field); + code += std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n"; + code += std::string(Indent) + Indent; + code += "return " + GenGetter(field.value.type); + code += "a + ((j-1) * "; + code += NumToString(InlineSize(vectortype)) + "))\n"; + code += std::string(Indent) + End; + if (vectortype.base_type == BASE_TYPE_STRING) { + code += std::string(Indent) + "return ''\n"; + } + else { + code += std::string(Indent) + "return 0\n"; + } + code += EndFunc; + } + + // Begin the creator function signature. + void BeginBuilderArgs(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "function " + NormalizedName(struct_def) + ".Create" + NormalizedName(struct_def); + code += "(builder"; + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void StructBuilderArgs(const StructDef &struct_def, + const char *nameprefix, std::string *code_ptr) { + 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. + StructBuilderArgs(*field.value.type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr); + } + else { + std::string &code = *code_ptr; + code += (std::string) ", " + nameprefix; + code += MakeCamel(NormalizedName(field), false); + } + } + } + + // End the creator function signature. + void EndBuilderArgs(std::string *code_ptr) { + std::string &code = *code_ptr; + code += ")\n"; + } + + // Recursively generate struct construction statements and instert manual + // padding. + void StructBuilderBody(const StructDef &struct_def, + const char *nameprefix, std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Indent) + "builder:Prep(" + NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ")\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) + code += std::string(Indent) + "builder:Pad(" + NumToString(field.padding) + ")\n"; + if (IsStruct(field.value.type)) { + StructBuilderBody(*field.value.type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr); + } + else { + code += std::string(Indent) + "builder:Prepend" + GenMethod(field) + "("; + code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n"; + } + } + } + + void EndBuilderBody(std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Indent) + "return builder:Offset()\n"; + code += EndFunc; + } + + // Get the value of a table's starting offset. + void GetStartOfTable(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".Start"; + code += "(builder) "; + code += "builder:StartObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ") end\n"; + } + + // Set the value of a table's field. + void BuildFieldOfTable(const StructDef &struct_def, + const FieldDef &field, const size_t offset, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".Add" + MakeCamel(NormalizedName(field)); + code += "(builder, "; + code += MakeCamel(NormalizedName(field), false); + code += ") "; + code += "builder:Prepend"; + code += GenMethod(field) + "Slot("; + code += NumToString(offset) + ", "; + // todo: i don't need to cast in Lua, but am I missing something? + // if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + // code += "flatbuffers.N.UOffsetTFlags.py_type"; + // code += "("; + // code += MakeCamel(NormalizedName(field), false) + ")"; + // } else { + code += MakeCamel(NormalizedName(field), false); + // } + code += ", " + field.value.constant; + code += ") end\n"; + } + + // Set the value of one of the members of a table's vector. + void BuildVectorOfTable(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".Start"; + code += MakeCamel(NormalizedName(field)); + code += "Vector(builder, numElems) return builder:StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += ") end\n"; + } + + // Get the offset of the end of a table. + void GetEndOffsetOnTable(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".End"; + code += "(builder) "; + code += "return builder:EndObject() end\n"; + } + + // Generate the receiver for function signatures. + void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedMetaName(struct_def) + ":"; + } + + // Generate a struct field, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, Comment); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + GetScalarFieldOfStruct(struct_def, field, code_ptr); + } + else { + GetScalarFieldOfTable(struct_def, field, code_ptr); + } + } + else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + GetStructFieldOfStruct(struct_def, field, code_ptr); + } + else { + GetStructFieldOfTable(struct_def, field, code_ptr); + } + break; + case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GetMemberOfVectorOfStruct(struct_def, field, code_ptr); + } + else { + GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); + } + break; + } + case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break; + default: FLATBUFFERS_ASSERT(0); + } + } + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + GetVectorLen(struct_def, field, code_ptr); + } + } + + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, + std::string *code_ptr) { + GetStartOfTable(struct_def, code_ptr); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto offset = it - struct_def.fields.vec.begin(); + BuildFieldOfTable(struct_def, field, offset, code_ptr); + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + BuildVectorOfTable(struct_def, field, code_ptr); + } + } + + GetEndOffsetOnTable(struct_def, code_ptr); + } + + // Generate struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + + GenComment(struct_def.doc_comment, code_ptr, nullptr, Comment); + BeginClass(struct_def, code_ptr); + + GenerateNewObjectPrototype(struct_def, code_ptr); + + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + NewRootTypeFromBuffer(struct_def, code_ptr); + } + + // Generate the Init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + InitializeExisting(struct_def, code_ptr); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + GenStructAccessor(struct_def, field, code_ptr); + } + + if (struct_def.fixed) { + // create a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } + else { + // Create a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } + } + + // Generate enum declarations. + void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; + + GenComment(enum_def.doc_comment, code_ptr, nullptr, Comment); + BeginEnum(NormalizedName(enum_def), code_ptr); + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, nullptr, Comment); + EnumMember(ev, code_ptr); + } + EndEnum(code_ptr); + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return std::string(SelfData) + ":String("; + case BASE_TYPE_UNION: return std::string(SelfData) + ":Union("; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + default: + return std::string(SelfData) + ":Get(flatbuffers.N." + + MakeCamel(GenTypeGet(type)) + ", "; + } + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const FieldDef &field) { + return IsScalar(field.value.type.base_type) + ? MakeCamel(GenTypeBasic(field.value.type)) + : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative"); + } + + std::string GenTypeBasic(const Type &type) { + static const char *ctypename[] = { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + #PTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + // clang-format on + }; + return ctypename[type.base_type]; + } + + std::string GenTypePointer(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "string"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return type.struct_def->name; + case BASE_TYPE_UNION: + // fall through + default: return "*flatbuffers.Table"; + } + } + + std::string GenTypeGet(const Type &type) { + return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); + } + + std::string GetNamespace(const Type &type) { + return type.struct_def->defined_namespace->GetFullyQualifiedName(type.struct_def->name); + } + + std::string TypeName(const FieldDef &field) { + return GenTypeGet(field.value.type); + } + + std::string TypeNameWithNamespace(const FieldDef &field) { + return GetNamespace(field.value.type); + } + + // Create a struct with a builder and the struct's arguments. + void GenStructBuilder(const StructDef &struct_def, + std::string *code_ptr) { + BeginBuilderArgs(struct_def, code_ptr); + StructBuilderArgs(struct_def, "", code_ptr); + EndBuilderArgs(code_ptr); + + StructBuilderBody(struct_def, "", code_ptr); + EndBuilderBody(code_ptr); + } + + bool generate() { + if (!generateEnums()) return false; + if (!generateStructs()) return false; + return true; + } + + private: + bool generateEnums() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + std::string enumcode; + GenEnum(enum_def, &enumcode); + if (!SaveType(enum_def, enumcode, false)) return false; + } + return true; + } + + bool generateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + std::string declcode; + GenStruct(struct_def, &declcode); + if (!SaveType(struct_def, declcode, true)) return false; + } + return true; + } + + // Begin by declaring namespace and imports. + void BeginFile(const std::string name_space_name, const bool needs_imports, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n"; + code += std::string(Comment) + "namespace: " + name_space_name + "\n\n"; + if (needs_imports) { + code += "local flatbuffers = require('flatbuffers')\n\n"; + } + } + + // Save out the generated code for a Lua Table type. + bool SaveType(const Definition &def, const std::string &classcode, + bool needs_imports) { + if (!classcode.length()) return true; + + std::string namespace_dir = path_; + auto &namespaces = def.defined_namespace->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (it != namespaces.begin()) namespace_dir += kPathSeparator; + namespace_dir += *it; + //std::string init_py_filename = namespace_dir + "/__init__.py"; + //SaveFile(init_py_filename.c_str(), "", false); + } + + std::string code = ""; + BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code); + code += classcode; + code += "\n"; + code += "return " + NormalizedName(def) + " " + Comment + "return the module"; + std::string filename = + NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua"; + return SaveFile(filename.c_str(), code, false); + } + private: + std::unordered_set keywords_; + }; + +} // namespace lua + +bool GenerateLua(const Parser &parser, const std::string &path, + const std::string &file_name) { + lua::LuaGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index d2f518f..e000ada 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -72,7 +72,7 @@ class PythonGenerator : public BaseGenerator { "with", "yield" }; - for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); + keywords_.insert(std::begin(keywords), std::end(keywords)); } // Most field accessors need to retrieve and test the field offset first, diff --git a/tests/LuaTest.bat b/tests/LuaTest.bat new file mode 100644 index 0000000..2bbf1d0 --- /dev/null +++ b/tests/LuaTest.bat @@ -0,0 +1,6 @@ +set buildtype=Release +if "%1"=="-b" set buildtype=%2 + +..\%buildtype%\flatc.exe --lua -I include_test monster_test.fbs + +lua53.exe luatest.lua \ No newline at end of file diff --git a/tests/MyGame/Example/Ability.lua b/tests/MyGame/Example/Ability.lua new file mode 100644 index 0000000..7fb664a --- /dev/null +++ b/tests/MyGame/Example/Ability.lua @@ -0,0 +1,31 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local Ability = {} -- the module +local Ability_mt = {} -- the class metatable + +function Ability.New() + local o = {} + setmetatable(o, {__index = Ability_mt}) + return o +end +function Ability_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Ability_mt:Id() + return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 0) +end +function Ability_mt:Distance() + return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 4) +end +function Ability.CreateAbility(builder, id, distance) + builder:Prep(4, 8) + builder:PrependUint32(distance) + builder:PrependUint32(id) + return builder:Offset() +end + +return Ability -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Any.lua b/tests/MyGame/Example/Any.lua new file mode 100644 index 0000000..03225ba --- /dev/null +++ b/tests/MyGame/Example/Any.lua @@ -0,0 +1,12 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local Any = { + NONE = 0, + Monster = 1, + TestSimpleTableWithEnum = 2, + MyGame_Example2_Monster = 3, +} + +return Any -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Color.lua b/tests/MyGame/Example/Color.lua new file mode 100644 index 0000000..c3ec092 --- /dev/null +++ b/tests/MyGame/Example/Color.lua @@ -0,0 +1,11 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local Color = { + Red = 1, + Green = 2, + Blue = 8, +} + +return Color -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Monster.lua b/tests/MyGame/Example/Monster.lua new file mode 100644 index 0000000..a656f9b --- /dev/null +++ b/tests/MyGame/Example/Monster.lua @@ -0,0 +1,542 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +-- /// an example documentation comment: monster object +local Monster = {} -- the module +local Monster_mt = {} -- the class metatable + +function Monster.New() + local o = {} + setmetatable(o, {__index = Monster_mt}) + return o +end +function Monster.GetRootAsMonster(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = Monster.New() + o:Init(buf, n + offset) + return o +end +function Monster_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Monster_mt:Pos() + local o = self.view:Offset(4) + if o ~= 0 then + local x = o + self.view.pos + local obj = require('MyGame.Example.Vec3').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:Mana() + local o = self.view:Offset(6) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int16, o + self.view.pos) + end + return 150 +end +function Monster_mt:Hp() + local o = self.view:Offset(8) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int16, o + self.view.pos) + end + return 100 +end +function Monster_mt:Name() + local o = self.view:Offset(10) + if o ~= 0 then + return self.view:String(o + self.view.pos) + end +end +function Monster_mt:Inventory(j) + local o = self.view:Offset(14) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1)) + end + return 0 +end +function Monster_mt:InventoryLength() + local o = self.view:Offset(14) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Color() + local o = self.view:Offset(16) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int8, o + self.view.pos) + end + return 8 +end +function Monster_mt:TestType() + local o = self.view:Offset(18) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos) + end + return 0 +end +function Monster_mt:Test() + local o = self.view:Offset(20) + if o ~= 0 then + local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0) + self.view:Union(obj, o) + return obj + end +end +function Monster_mt:Test4(j) + local o = self.view:Offset(22) + if o ~= 0 then + local x = self.view:Vector(o) + x = x + ((j-1) * 4) + local obj = require('MyGame.Example.Test').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:Test4Length() + local o = self.view:Offset(22) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Testarrayofstring(j) + local o = self.view:Offset(24) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:String(a + ((j-1) * 4)) + end + return '' +end +function Monster_mt:TestarrayofstringLength() + local o = self.view:Offset(24) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +-- /// an example documentation comment: this will end up in the generated code +-- /// multiline too +function Monster_mt:Testarrayoftables(j) + local o = self.view:Offset(26) + if o ~= 0 then + local x = self.view:Vector(o) + x = x + ((j-1) * 4) + x = self.view:Indirect(x) + local obj = require('MyGame.Example.Monster').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:TestarrayoftablesLength() + local o = self.view:Offset(26) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Enemy() + local o = self.view:Offset(28) + if o ~= 0 then + local x = self.view:Indirect(o + self.view.pos) + local obj = require('MyGame.Example.Monster').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:Testnestedflatbuffer(j) + local o = self.view:Offset(30) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1)) + end + return 0 +end +function Monster_mt:TestnestedflatbufferLength() + local o = self.view:Offset(30) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Testempty() + local o = self.view:Offset(32) + if o ~= 0 then + local x = self.view:Indirect(o + self.view.pos) + local obj = require('MyGame.Example.Stat').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:Testbool() + local o = self.view:Offset(34) + if o ~= 0 then + return (self.view:Get(flatbuffers.N.Bool, o + self.view.pos) ~= 0) + end + return false +end +function Monster_mt:Testhashs32Fnv1() + local o = self.view:Offset(36) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int32, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashu32Fnv1() + local o = self.view:Offset(38) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashs64Fnv1() + local o = self.view:Offset(40) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int64, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashu64Fnv1() + local o = self.view:Offset(42) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashs32Fnv1a() + local o = self.view:Offset(44) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int32, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashu32Fnv1a() + local o = self.view:Offset(46) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashs64Fnv1a() + local o = self.view:Offset(48) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int64, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testhashu64Fnv1a() + local o = self.view:Offset(50) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function Monster_mt:Testarrayofbools(j) + local o = self.view:Offset(52) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Bool, a + ((j-1) * 1)) + end + return 0 +end +function Monster_mt:TestarrayofboolsLength() + local o = self.view:Offset(52) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Testf() + local o = self.view:Offset(54) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Float32, o + self.view.pos) + end + return 3.14159 +end +function Monster_mt:Testf2() + local o = self.view:Offset(56) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Float32, o + self.view.pos) + end + return 3.0 +end +function Monster_mt:Testf3() + local o = self.view:Offset(58) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Float32, o + self.view.pos) + end + return 0.0 +end +function Monster_mt:Testarrayofstring2(j) + local o = self.view:Offset(60) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:String(a + ((j-1) * 4)) + end + return '' +end +function Monster_mt:Testarrayofstring2Length() + local o = self.view:Offset(60) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Testarrayofsortedstruct(j) + local o = self.view:Offset(62) + if o ~= 0 then + local x = self.view:Vector(o) + x = x + ((j-1) * 8) + local obj = require('MyGame.Example.Ability').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:TestarrayofsortedstructLength() + local o = self.view:Offset(62) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Flex(j) + local o = self.view:Offset(64) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1)) + end + return 0 +end +function Monster_mt:FlexLength() + local o = self.view:Offset(64) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:Test5(j) + local o = self.view:Offset(66) + if o ~= 0 then + local x = self.view:Vector(o) + x = x + ((j-1) * 4) + local obj = require('MyGame.Example.Test').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:Test5Length() + local o = self.view:Offset(66) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:VectorOfLongs(j) + local o = self.view:Offset(68) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Int64, a + ((j-1) * 8)) + end + return 0 +end +function Monster_mt:VectorOfLongsLength() + local o = self.view:Offset(68) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:VectorOfDoubles(j) + local o = self.view:Offset(70) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8)) + end + return 0 +end +function Monster_mt:VectorOfDoublesLength() + local o = self.view:Offset(70) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:ParentNamespaceTest() + local o = self.view:Offset(72) + if o ~= 0 then + local x = self.view:Indirect(o + self.view.pos) + local obj = require('MyGame.InParentNamespace').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:VectorOfReferrables(j) + local o = self.view:Offset(74) + if o ~= 0 then + local x = self.view:Vector(o) + x = x + ((j-1) * 4) + x = self.view:Indirect(x) + local obj = require('MyGame.Example.Referrable').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:VectorOfReferrablesLength() + local o = self.view:Offset(74) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:SingleWeakReference() + local o = self.view:Offset(76) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function Monster_mt:VectorOfWeakReferences(j) + local o = self.view:Offset(78) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8)) + end + return 0 +end +function Monster_mt:VectorOfWeakReferencesLength() + local o = self.view:Offset(78) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:VectorOfStrongReferrables(j) + local o = self.view:Offset(80) + if o ~= 0 then + local x = self.view:Vector(o) + x = x + ((j-1) * 4) + x = self.view:Indirect(x) + local obj = require('MyGame.Example.Referrable').New() + obj:Init(self.view.bytes, x) + return obj + end +end +function Monster_mt:VectorOfStrongReferrablesLength() + local o = self.view:Offset(80) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:CoOwningReference() + local o = self.view:Offset(82) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function Monster_mt:VectorOfCoOwningReferences(j) + local o = self.view:Offset(84) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8)) + end + return 0 +end +function Monster_mt:VectorOfCoOwningReferencesLength() + local o = self.view:Offset(84) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster_mt:NonOwningReference() + local o = self.view:Offset(86) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function Monster_mt:VectorOfNonOwningReferences(j) + local o = self.view:Offset(88) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8)) + end + return 0 +end +function Monster_mt:VectorOfNonOwningReferencesLength() + local o = self.view:Offset(88) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function Monster.Start(builder) builder:StartObject(43) end +function Monster.AddPos(builder, pos) builder:PrependStructSlot(0, pos, 0) end +function Monster.AddMana(builder, mana) builder:PrependInt16Slot(1, mana, 150) end +function Monster.AddHp(builder, hp) builder:PrependInt16Slot(2, hp, 100) end +function Monster.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(3, name, 0) end +function Monster.AddInventory(builder, inventory) builder:PrependUOffsetTRelativeSlot(5, inventory, 0) end +function Monster.StartInventoryVector(builder, numElems) return builder:StartVector(1, numElems, 1) end +function Monster.AddColor(builder, color) builder:PrependInt8Slot(6, color, 8) end +function Monster.AddTestType(builder, testType) builder:PrependUint8Slot(7, testType, 0) end +function Monster.AddTest(builder, test) builder:PrependUOffsetTRelativeSlot(8, test, 0) end +function Monster.AddTest4(builder, test4) builder:PrependUOffsetTRelativeSlot(9, test4, 0) end +function Monster.StartTest4Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end +function Monster.AddTestarrayofstring(builder, testarrayofstring) builder:PrependUOffsetTRelativeSlot(10, testarrayofstring, 0) end +function Monster.StartTestarrayofstringVector(builder, numElems) return builder:StartVector(4, numElems, 4) end +function Monster.AddTestarrayoftables(builder, testarrayoftables) builder:PrependUOffsetTRelativeSlot(11, testarrayoftables, 0) end +function Monster.StartTestarrayoftablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end +function Monster.AddEnemy(builder, enemy) builder:PrependUOffsetTRelativeSlot(12, enemy, 0) end +function Monster.AddTestnestedflatbuffer(builder, testnestedflatbuffer) builder:PrependUOffsetTRelativeSlot(13, testnestedflatbuffer, 0) end +function Monster.StartTestnestedflatbufferVector(builder, numElems) return builder:StartVector(1, numElems, 1) end +function Monster.AddTestempty(builder, testempty) builder:PrependUOffsetTRelativeSlot(14, testempty, 0) end +function Monster.AddTestbool(builder, testbool) builder:PrependBoolSlot(15, testbool, 0) end +function Monster.AddTesthashs32Fnv1(builder, testhashs32Fnv1) builder:PrependInt32Slot(16, testhashs32Fnv1, 0) end +function Monster.AddTesthashu32Fnv1(builder, testhashu32Fnv1) builder:PrependUint32Slot(17, testhashu32Fnv1, 0) end +function Monster.AddTesthashs64Fnv1(builder, testhashs64Fnv1) builder:PrependInt64Slot(18, testhashs64Fnv1, 0) end +function Monster.AddTesthashu64Fnv1(builder, testhashu64Fnv1) builder:PrependUint64Slot(19, testhashu64Fnv1, 0) end +function Monster.AddTesthashs32Fnv1a(builder, testhashs32Fnv1a) builder:PrependInt32Slot(20, testhashs32Fnv1a, 0) end +function Monster.AddTesthashu32Fnv1a(builder, testhashu32Fnv1a) builder:PrependUint32Slot(21, testhashu32Fnv1a, 0) end +function Monster.AddTesthashs64Fnv1a(builder, testhashs64Fnv1a) builder:PrependInt64Slot(22, testhashs64Fnv1a, 0) end +function Monster.AddTesthashu64Fnv1a(builder, testhashu64Fnv1a) builder:PrependUint64Slot(23, testhashu64Fnv1a, 0) end +function Monster.AddTestarrayofbools(builder, testarrayofbools) builder:PrependUOffsetTRelativeSlot(24, testarrayofbools, 0) end +function Monster.StartTestarrayofboolsVector(builder, numElems) return builder:StartVector(1, numElems, 1) end +function Monster.AddTestf(builder, testf) builder:PrependFloat32Slot(25, testf, 3.14159) end +function Monster.AddTestf2(builder, testf2) builder:PrependFloat32Slot(26, testf2, 3.0) end +function Monster.AddTestf3(builder, testf3) builder:PrependFloat32Slot(27, testf3, 0.0) end +function Monster.AddTestarrayofstring2(builder, testarrayofstring2) builder:PrependUOffsetTRelativeSlot(28, testarrayofstring2, 0) end +function Monster.StartTestarrayofstring2Vector(builder, numElems) return builder:StartVector(4, numElems, 4) end +function Monster.AddTestarrayofsortedstruct(builder, testarrayofsortedstruct) builder:PrependUOffsetTRelativeSlot(29, testarrayofsortedstruct, 0) end +function Monster.StartTestarrayofsortedstructVector(builder, numElems) return builder:StartVector(8, numElems, 4) end +function Monster.AddFlex(builder, flex) builder:PrependUOffsetTRelativeSlot(30, flex, 0) end +function Monster.StartFlexVector(builder, numElems) return builder:StartVector(1, numElems, 1) end +function Monster.AddTest5(builder, test5) builder:PrependUOffsetTRelativeSlot(31, test5, 0) end +function Monster.StartTest5Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end +function Monster.AddVectorOfLongs(builder, vectorOfLongs) builder:PrependUOffsetTRelativeSlot(32, vectorOfLongs, 0) end +function Monster.StartVectorOfLongsVector(builder, numElems) return builder:StartVector(8, numElems, 8) end +function Monster.AddVectorOfDoubles(builder, vectorOfDoubles) builder:PrependUOffsetTRelativeSlot(33, vectorOfDoubles, 0) end +function Monster.StartVectorOfDoublesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end +function Monster.AddParentNamespaceTest(builder, parentNamespaceTest) builder:PrependUOffsetTRelativeSlot(34, parentNamespaceTest, 0) end +function Monster.AddVectorOfReferrables(builder, vectorOfReferrables) builder:PrependUOffsetTRelativeSlot(35, vectorOfReferrables, 0) end +function Monster.StartVectorOfReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end +function Monster.AddSingleWeakReference(builder, singleWeakReference) builder:PrependUint64Slot(36, singleWeakReference, 0) end +function Monster.AddVectorOfWeakReferences(builder, vectorOfWeakReferences) builder:PrependUOffsetTRelativeSlot(37, vectorOfWeakReferences, 0) end +function Monster.StartVectorOfWeakReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end +function Monster.AddVectorOfStrongReferrables(builder, vectorOfStrongReferrables) builder:PrependUOffsetTRelativeSlot(38, vectorOfStrongReferrables, 0) end +function Monster.StartVectorOfStrongReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end +function Monster.AddCoOwningReference(builder, coOwningReference) builder:PrependUint64Slot(39, coOwningReference, 0) end +function Monster.AddVectorOfCoOwningReferences(builder, vectorOfCoOwningReferences) builder:PrependUOffsetTRelativeSlot(40, vectorOfCoOwningReferences, 0) end +function Monster.StartVectorOfCoOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end +function Monster.AddNonOwningReference(builder, nonOwningReference) builder:PrependUint64Slot(41, nonOwningReference, 0) end +function Monster.AddVectorOfNonOwningReferences(builder, vectorOfNonOwningReferences) builder:PrependUOffsetTRelativeSlot(42, vectorOfNonOwningReferences, 0) end +function Monster.StartVectorOfNonOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end +function Monster.End(builder) return builder:EndObject() end + +return Monster -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Referrable.lua b/tests/MyGame/Example/Referrable.lua new file mode 100644 index 0000000..9b0f5a1 --- /dev/null +++ b/tests/MyGame/Example/Referrable.lua @@ -0,0 +1,35 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local Referrable = {} -- the module +local Referrable_mt = {} -- the class metatable + +function Referrable.New() + local o = {} + setmetatable(o, {__index = Referrable_mt}) + return o +end +function Referrable.GetRootAsReferrable(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = Referrable.New() + o:Init(buf, n + offset) + return o +end +function Referrable_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Referrable_mt:Id() + local o = self.view:Offset(4) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function Referrable.Start(builder) builder:StartObject(1) end +function Referrable.AddId(builder, id) builder:PrependUint64Slot(0, id, 0) end +function Referrable.End(builder) return builder:EndObject() end + +return Referrable -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Stat.lua b/tests/MyGame/Example/Stat.lua new file mode 100644 index 0000000..6999184 --- /dev/null +++ b/tests/MyGame/Example/Stat.lua @@ -0,0 +1,50 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local Stat = {} -- the module +local Stat_mt = {} -- the class metatable + +function Stat.New() + local o = {} + setmetatable(o, {__index = Stat_mt}) + return o +end +function Stat.GetRootAsStat(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = Stat.New() + o:Init(buf, n + offset) + return o +end +function Stat_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Stat_mt:Id() + local o = self.view:Offset(4) + if o ~= 0 then + return self.view:String(o + self.view.pos) + end +end +function Stat_mt:Val() + local o = self.view:Offset(6) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int64, o + self.view.pos) + end + return 0 +end +function Stat_mt:Count() + local o = self.view:Offset(8) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos) + end + return 0 +end +function Stat.Start(builder) builder:StartObject(3) end +function Stat.AddId(builder, id) builder:PrependUOffsetTRelativeSlot(0, id, 0) end +function Stat.AddVal(builder, val) builder:PrependInt64Slot(1, val, 0) end +function Stat.AddCount(builder, count) builder:PrependUint16Slot(2, count, 0) end +function Stat.End(builder) return builder:EndObject() end + +return Stat -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Test.lua b/tests/MyGame/Example/Test.lua new file mode 100644 index 0000000..154067b --- /dev/null +++ b/tests/MyGame/Example/Test.lua @@ -0,0 +1,32 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local Test = {} -- the module +local Test_mt = {} -- the class metatable + +function Test.New() + local o = {} + setmetatable(o, {__index = Test_mt}) + return o +end +function Test_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Test_mt:A() + return self.view:Get(flatbuffers.N.Int16, self.view.pos + 0) +end +function Test_mt:B() + return self.view:Get(flatbuffers.N.Int8, self.view.pos + 2) +end +function Test.CreateTest(builder, a, b) + builder:Prep(2, 4) + builder:Pad(1) + builder:PrependInt8(b) + builder:PrependInt16(a) + return builder:Offset() +end + +return Test -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.lua b/tests/MyGame/Example/TestSimpleTableWithEnum.lua new file mode 100644 index 0000000..c17fb96 --- /dev/null +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.lua @@ -0,0 +1,35 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local TestSimpleTableWithEnum = {} -- the module +local TestSimpleTableWithEnum_mt = {} -- the class metatable + +function TestSimpleTableWithEnum.New() + local o = {} + setmetatable(o, {__index = TestSimpleTableWithEnum_mt}) + return o +end +function TestSimpleTableWithEnum.GetRootAsTestSimpleTableWithEnum(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = TestSimpleTableWithEnum.New() + o:Init(buf, n + offset) + return o +end +function TestSimpleTableWithEnum_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function TestSimpleTableWithEnum_mt:Color() + local o = self.view:Offset(4) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int8, o + self.view.pos) + end + return 2 +end +function TestSimpleTableWithEnum.Start(builder) builder:StartObject(1) end +function TestSimpleTableWithEnum.AddColor(builder, color) builder:PrependInt8Slot(0, color, 2) end +function TestSimpleTableWithEnum.End(builder) return builder:EndObject() end + +return TestSimpleTableWithEnum -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/TypeAliases.lua b/tests/MyGame/Example/TypeAliases.lua new file mode 100644 index 0000000..90f569c --- /dev/null +++ b/tests/MyGame/Example/TypeAliases.lua @@ -0,0 +1,141 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local TypeAliases = {} -- the module +local TypeAliases_mt = {} -- the class metatable + +function TypeAliases.New() + local o = {} + setmetatable(o, {__index = TypeAliases_mt}) + return o +end +function TypeAliases.GetRootAsTypeAliases(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = TypeAliases.New() + o:Init(buf, n + offset) + return o +end +function TypeAliases_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function TypeAliases_mt:I8() + local o = self.view:Offset(4) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int8, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:U8() + local o = self.view:Offset(6) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:I16() + local o = self.view:Offset(8) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int16, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:U16() + local o = self.view:Offset(10) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:I32() + local o = self.view:Offset(12) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int32, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:U32() + local o = self.view:Offset(14) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:I64() + local o = self.view:Offset(16) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Int64, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:U64() + local o = self.view:Offset(18) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos) + end + return 0 +end +function TypeAliases_mt:F32() + local o = self.view:Offset(20) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Float32, o + self.view.pos) + end + return 0.0 +end +function TypeAliases_mt:F64() + local o = self.view:Offset(22) + if o ~= 0 then + return self.view:Get(flatbuffers.N.Float64, o + self.view.pos) + end + return 0.0 +end +function TypeAliases_mt:V8(j) + local o = self.view:Offset(24) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Int8, a + ((j-1) * 1)) + end + return 0 +end +function TypeAliases_mt:V8Length() + local o = self.view:Offset(24) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function TypeAliases_mt:Vf64(j) + local o = self.view:Offset(26) + if o ~= 0 then + local a = self.view:Vector(o) + return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8)) + end + return 0 +end +function TypeAliases_mt:Vf64Length() + local o = self.view:Offset(26) + if o ~= 0 then + return self.view:VectorLen(o) + end + return 0 +end +function TypeAliases.Start(builder) builder:StartObject(12) end +function TypeAliases.AddI8(builder, i8) builder:PrependInt8Slot(0, i8, 0) end +function TypeAliases.AddU8(builder, u8) builder:PrependUint8Slot(1, u8, 0) end +function TypeAliases.AddI16(builder, i16) builder:PrependInt16Slot(2, i16, 0) end +function TypeAliases.AddU16(builder, u16) builder:PrependUint16Slot(3, u16, 0) end +function TypeAliases.AddI32(builder, i32) builder:PrependInt32Slot(4, i32, 0) end +function TypeAliases.AddU32(builder, u32) builder:PrependUint32Slot(5, u32, 0) end +function TypeAliases.AddI64(builder, i64) builder:PrependInt64Slot(6, i64, 0) end +function TypeAliases.AddU64(builder, u64) builder:PrependUint64Slot(7, u64, 0) end +function TypeAliases.AddF32(builder, f32) builder:PrependFloat32Slot(8, f32, 0.0) end +function TypeAliases.AddF64(builder, f64) builder:PrependFloat64Slot(9, f64, 0.0) end +function TypeAliases.AddV8(builder, v8) builder:PrependUOffsetTRelativeSlot(10, v8, 0) end +function TypeAliases.StartV8Vector(builder, numElems) return builder:StartVector(1, numElems, 1) end +function TypeAliases.AddVf64(builder, vf64) builder:PrependUOffsetTRelativeSlot(11, vf64, 0) end +function TypeAliases.StartVf64Vector(builder, numElems) return builder:StartVector(8, numElems, 8) end +function TypeAliases.End(builder) return builder:EndObject() end + +return TypeAliases -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example/Vec3.lua b/tests/MyGame/Example/Vec3.lua new file mode 100644 index 0000000..ff7d13c --- /dev/null +++ b/tests/MyGame/Example/Vec3.lua @@ -0,0 +1,54 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example + +local flatbuffers = require('flatbuffers') + +local Vec3 = {} -- the module +local Vec3_mt = {} -- the class metatable + +function Vec3.New() + local o = {} + setmetatable(o, {__index = Vec3_mt}) + return o +end +function Vec3_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Vec3_mt:X() + return self.view:Get(flatbuffers.N.Float32, self.view.pos + 0) +end +function Vec3_mt:Y() + return self.view:Get(flatbuffers.N.Float32, self.view.pos + 4) +end +function Vec3_mt:Z() + return self.view:Get(flatbuffers.N.Float32, self.view.pos + 8) +end +function Vec3_mt:Test1() + return self.view:Get(flatbuffers.N.Float64, self.view.pos + 16) +end +function Vec3_mt:Test2() + return self.view:Get(flatbuffers.N.Int8, self.view.pos + 24) +end +function Vec3_mt:Test3(obj) + obj:Init(self.view.bytes, self.view.pos + 26) + return obj +end +function Vec3.CreateVec3(builder, x, y, z, test1, test2, test3_a, test3_b) + builder:Prep(16, 32) + builder:Pad(2) + builder:Prep(2, 4) + builder:Pad(1) + builder:PrependInt8(test3_b) + builder:PrependInt16(test3_a) + builder:Pad(1) + builder:PrependInt8(test2) + builder:PrependFloat64(test1) + builder:Pad(4) + builder:PrependFloat32(z) + builder:PrependFloat32(y) + builder:PrependFloat32(x) + return builder:Offset() +end + +return Vec3 -- return the module \ No newline at end of file diff --git a/tests/MyGame/Example2/Monster.lua b/tests/MyGame/Example2/Monster.lua new file mode 100644 index 0000000..347b5db --- /dev/null +++ b/tests/MyGame/Example2/Monster.lua @@ -0,0 +1,27 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: Example2 + +local flatbuffers = require('flatbuffers') + +local Monster = {} -- the module +local Monster_mt = {} -- the class metatable + +function Monster.New() + local o = {} + setmetatable(o, {__index = Monster_mt}) + return o +end +function Monster.GetRootAsMonster(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = Monster.New() + o:Init(buf, n + offset) + return o +end +function Monster_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function Monster.Start(builder) builder:StartObject(0) end +function Monster.End(builder) return builder:EndObject() end + +return Monster -- return the module \ No newline at end of file diff --git a/tests/MyGame/InParentNamespace.lua b/tests/MyGame/InParentNamespace.lua new file mode 100644 index 0000000..b3fa0c8 --- /dev/null +++ b/tests/MyGame/InParentNamespace.lua @@ -0,0 +1,27 @@ +-- automatically generated by the FlatBuffers compiler, do not modify + +-- namespace: MyGame + +local flatbuffers = require('flatbuffers') + +local InParentNamespace = {} -- the module +local InParentNamespace_mt = {} -- the class metatable + +function InParentNamespace.New() + local o = {} + setmetatable(o, {__index = InParentNamespace_mt}) + return o +end +function InParentNamespace.GetRootAsInParentNamespace(buf, offset) + local n = flatbuffers.N.UOffsetT:Unpack(buf, offset) + local o = InParentNamespace.New() + o:Init(buf, n + offset) + return o +end +function InParentNamespace_mt:Init(buf, pos) + self.view = flatbuffers.view.New(buf, pos) +end +function InParentNamespace.Start(builder) builder:StartObject(0) end +function InParentNamespace.End(builder) return builder:EndObject() end + +return InParentNamespace -- return the module \ No newline at end of file diff --git a/tests/generate_code.bat b/tests/generate_code.bat index 0412576..2636225 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -15,8 +15,8 @@ set buildtype=Release if "%1"=="-b" set buildtype=%2 -..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json -..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs +..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lua --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json +..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lua --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs ..\%buildtype%\flatc.exe --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs ..\%buildtype%\flatc.exe -b --schema --bfbs-comments -I include_test monster_test.fbs ..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs diff --git a/tests/generate_code.sh b/tests/generate_code.sh index c5304b6..32a59e8 100755 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -14,8 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -../flatc --cpp --java --csharp --dart --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json -../flatc --cpp --java --csharp --dart --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs +../flatc --cpp --java --csharp --dart --go --binary --lua --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json +../flatc --cpp --java --csharp --dart --go --binary --lua --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs ../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs ../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs ../flatc --jsonschema --schema -I include_test monster_test.fbs diff --git a/tests/luatest.lua b/tests/luatest.lua new file mode 100644 index 0000000..23bc0f2 --- /dev/null +++ b/tests/luatest.lua @@ -0,0 +1,294 @@ +package.path = string.format("../lua/?.lua;./?.lua;%s",package.path) + +local function checkReadBuffer(buf, offset, sizePrefix) + offset = offset or 0 + + if type(buf) == "string" then + buf = flatbuffers.binaryArray.New(buf) + end + + if sizePrefix then + local size = flatbuffers.N.Int32:Unpack(buf, offset) + -- no longer matches python tests, but the latest 'monsterdata_test.mon' + -- is 448 bytes, minus 4 to arrive at the 444 + assert(size == 444) + offset = offset + flatbuffers.N.Int32.bytewidth + end + + local mon = monster.GetRootAsMonster(buf, offset) + assert(mon:Hp() == 80, "Monster Hp is not 80") + assert(mon:Mana() == 150, "Monster Mana is not 150") + assert(mon:Name() == "MyMonster", "Monster Name is not MyMonster") + + local vec = assert(mon:Pos(), "Monster Position is nil") + assert(vec:X() == 1.0) + assert(vec:Y() == 2.0) + assert(vec:Z() == 3.0) + assert(vec:Test1() == 3.0) + assert(vec:Test2() == 2) + + local t = require("MyGame.Example.Test").New() + t = assert(vec:Test3(t)) + + assert(t:A() == 5) + assert(t:B() == 6) + + local ut = require("MyGame.Example.Any") + assert(mon:TestType() == ut.Monster) + + local table2 = mon:Test() + assert(getmetatable(table2) == "flatbuffers.view.mt") + + local mon2 = monster.New() + mon2:Init(table2.bytes, table2.pos) + + assert(mon2:Name() == "Fred") + + assert(mon:InventoryLength() == 5) + local invsum = 0 + for i=1,mon:InventoryLength() do + local v = mon:Inventory(i) + invsum = invsum + v + end + assert(invsum == 10) + + for i=1,5 do + assert(mon:VectorOfLongs(i) == 10^((i-1)*2)) + end + + local dbls = { -1.7976931348623157e+308, 0, 1.7976931348623157e+308} + for i=1,mon:VectorOfDoublesLength() do + assert(mon:VectorOfDoubles(i) == dbls[i]) + end + + assert(mon:Test4Length() == 2) + + local test0 = mon:Test4(1) + local test1 = mon:Test4(2) + + local v0 = test0:A() + local v1 = test0:B() + local v2 = test1:A() + local v3 = test1:B() + + local sumtest12 = v0 + v1 + v2 + v3 + assert(sumtest12 == 100) + + assert(mon:TestarrayofstringLength() == 2) + assert(mon:Testarrayofstring(1) == "test1") + assert(mon:Testarrayofstring(2) == "test2") + + assert(mon:TestarrayoftablesLength() == 0) + assert(mon:TestnestedflatbufferLength() == 0) + assert(mon:Testempty() == nil) +end + +local function generateMonster(sizePrefix) + local b = flatbuffers.Builder(0) + local str = b:CreateString("MyMonster") + local test1 = b:CreateString("test1") + local test2 = b:CreateString("test2") + local fred = b:CreateString("Fred") + + monster.StartInventoryVector(b, 5) + b:PrependByte(4) + b:PrependByte(3) + b:PrependByte(2) + b:PrependByte(1) + b:PrependByte(0) + local inv = b:EndVector(5) + + monster.Start(b) + monster.AddName(b, fred) + local mon2 = monster.End(b) + + monster.StartTest4Vector(b, 2) + test.CreateTest(b, 10, 20) + test.CreateTest(b, 30, 40) + local test4 = b:EndVector(2) + + monster.StartTestarrayofstringVector(b, 2) + b:PrependUOffsetTRelative(test2) + b:PrependUOffsetTRelative(test1) + local testArrayOfString = b:EndVector(2) + + monster.StartVectorOfLongsVector(b, 5) + b:PrependInt64(100000000) + b:PrependInt64(1000000) + b:PrependInt64(10000) + b:PrependInt64(100) + b:PrependInt64(1) + local vectorOfLongs = b:EndVector(5) + + monster.StartVectorOfDoublesVector(b, 3) + b:PrependFloat64(1.7976931348623157e+308) + b:PrependFloat64(0) + b:PrependFloat64(-1.7976931348623157e+308) + local vectorOfDoubles = b:EndVector(3) + + monster.Start(b) + local pos = vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6) + monster.AddPos(b, pos) + + monster.AddHp(b, 80) + monster.AddName(b, str) + monster.AddInventory(b, inv) + monster.AddTestType(b, 1) + monster.AddTest(b, mon2) + monster.AddTest4(b, test4) + monster.AddTestarrayofstring(b, testArrayOfString) + monster.AddVectorOfLongs(b, vectorOfLongs) + monster.AddVectorOfDoubles(b, vectorOfDoubles) + local mon = monster.End(b) + + if sizePrefix then + b:FinishSizePrefixed(mon) + else + b:Finish(mon) + end + return b:Output(true), b:Head() +end + +local function sizePrefix(sizePrefix) + local buf,offset = generateMonster(sizePrefix) + checkReadBuffer(buf, offset, sizePrefix) +end + +local function testCanonicalData() + local f = assert(io.open('monsterdata_test.mon', 'rb')) + local wireData = f:read("*a") + f:close() + checkReadBuffer(wireData) +end + +local function benchmarkMakeMonster(count) + local length = #(generateMonster()) + + --require("flatbuffers.profiler") + --profiler = newProfiler("call") + --profiler:start() + + local s = os.clock() + for i=1,count do + generateMonster() + end + local e = os.clock() + + --profiler:stop() + + --local outfile = io.open( "profile.txt", "w+" ) + --profiler:report( outfile, true) + --outfile:close() + + + local dur = (e - s) + local rate = count / (dur * 1000) + local data = (length * count) / (1024 * 1024) + local dataRate = data / dur + + print(string.format('built %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec', + count, length, dur, rate, dataRate)) +end + +local function benchmarkReadBuffer(count) + local f = assert(io.open('monsterdata_test.mon', 'rb')) + local buf = f:read("*a") + f:close() + + local s = os.clock() + for i=1,count do + checkReadBuffer(buf) + end + local e = os.clock() + + local dur = (e - s) + local rate = count / (dur * 1000) + local data = (#buf * count) / (1024 * 1024) + local dataRate = data / dur + + print(string.format('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec', + count, #buf, dur, rate, dataRate)) +end + +local tests = +{ + { + f = sizePrefix, + d = "Test size prefix", + args = {{true}, {false}} + }, + { + f = testCanonicalData, + d = "Tests Canonical flatbuffer file included in repo" + }, + { + f = benchmarkMakeMonster, + d = "Benchmark making monsters", + args = { + {100}, + {1000}, + {10000}, + } + }, + { + f = benchmarkReadBuffer, + d = "Benchmark reading monsters", + args = { + {100}, + {1000}, + {10000}, + -- uncomment following to run 1 million to compare. + -- Took ~141 seconds on my machine + --{1000000}, + } + }, +} + +local result, err = xpcall(function() + flatbuffers = assert(require("flatbuffers")) + monster = assert(require("MyGame.Example.Monster")) + test = assert(require("MyGame.Example.Test")) + vec3 = assert(require("MyGame.Example.Vec3")) + + local function buildArgList(tbl) + local s = "" + for _,item in ipairs(tbl) do + s = s .. tostring(item) .. "," + end + return s:sub(1,-2) + end + + local testsPassed, testsFailed = 0,0 + for _,test in ipairs(tests) do + local allargs = test.args or {{}} + for _,args in ipairs(allargs) do + local results, err = xpcall(test.f,debug.traceback, table.unpack(args)) + if results then + testsPassed = testsPassed + 1 + else + testsFailed = testsFailed + 1 + print(string.format(" Test [%s](%s) failed: \n\t%s", + test.d or "", + buildArgList(args), + err)) + end + end + end + + local totalTests = testsPassed + testsFailed + print(string.format("# of test passed: %d / %d (%.2f%%)", + testsPassed, + totalTests, + totalTests ~= 0 + and 100 * (testsPassed / totalTests) + or 0) + ) + + return 0 +end, debug.traceback) + +if not result then + print("Unable to run tests due to test framework error: ",err) +end + +os.exit(result or -1)