forked from BigfootDev/flatbuffers
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
This commit is contained in:
committed by
Wouter van Oortmerssen
parent
8ea293b988
commit
ba5eb3b5cf
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
81
docs/source/LuaUsage.md
Normal file
81
docs/source/LuaUsage.md
Normal file
@@ -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.
|
||||
|
||||
<br>
|
||||
@@ -31,6 +31,7 @@ Please select your desired language for our quest:
|
||||
<input type="radio" name="language" value="php">PHP</input>
|
||||
<input type="radio" name="language" value="c">C</input>
|
||||
<input type="radio" name="language" value="dart">Dart</input>
|
||||
<input type="radio" name="language" value="lua">Lua</input>
|
||||
</form>
|
||||
\endhtmlonly
|
||||
|
||||
@@ -136,6 +137,10 @@ For your chosen language, please cross-reference with:
|
||||
<div class="language-dart">
|
||||
[example.dart](https://github.com/google/flatbuffers/blob/master/dart/example/example.dart)
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
[sample_binary.lua](https://github.com/google/flatbuffers/blob/master/dart/example/sample_binary.lua)
|
||||
</div>
|
||||
|
||||
|
||||
## Writing the Monsters' FlatBuffer Schema
|
||||
|
||||
@@ -322,6 +327,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
|
||||
./../flatc --dart monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.sh}
|
||||
cd flatbuffers/sample
|
||||
./../flatc --lua monster.fbs
|
||||
~~~
|
||||
</div>
|
||||
|
||||
For a more complete guide to using the `flatc` compiler, please read the
|
||||
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
|
||||
@@ -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;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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")
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Now we are ready to start building some buffers. In order to start, we need
|
||||
to create an instance of the `FlatBufferBuilder`, which will contain the buffer
|
||||
@@ -518,6 +542,12 @@ which will grow automatically if needed:
|
||||
var builder = new fb.Builder(initialSize: 1024);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
-- get access to the builder, providing an array of size 1024
|
||||
local builder = flatbuffers.Builder(1024)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
After creating the `builder`, we can start serializing our data. Before we make
|
||||
our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
|
||||
@@ -705,6 +735,24 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
|
||||
);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Now let's create our monster, the `orc`. For this `orc`, lets make him
|
||||
`red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him
|
||||
@@ -852,6 +900,21 @@ traversal. This is generally easy to do on any tree structures.
|
||||
final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
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<myGame.WeaponBuilder> weaps = [sword, axe];
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
<div class="language-cpp">
|
||||
<br>
|
||||
@@ -1063,6 +1136,16 @@ for the `path` field above:
|
||||
];
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
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);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
|
||||
are simple combinations of scalars that are always stored inline, just like
|
||||
@@ -1409,6 +1508,12 @@ Here is a repetition these lines, to help highlight them more clearly:
|
||||
equipped: axe, // Union data
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
monster.AddEquippedType(builder, equipment.Weapon) -- Union type
|
||||
monster.AddEquipped(builder, axe) -- Union data
|
||||
~~~
|
||||
</div>
|
||||
|
||||
After you have created your buffer, you will have the offset to the root of the
|
||||
data in the `orc` variable, so you can finish the buffer by calling the
|
||||
@@ -1480,6 +1585,13 @@ appropriate `finish` method.
|
||||
// See the next code section, as in Dart `finish` will also return the byte array.
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
-- Call 'Finish()' to instruct the builder that this monster is complete.
|
||||
builder:Finish(orc)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
|
||||
The buffer is now ready to be stored somewhere, sent over the network, be
|
||||
compressed, or whatever you'd like to do with it. You can access the buffer
|
||||
@@ -1577,6 +1689,13 @@ like so:
|
||||
final Uint8List buf = builder.finish(orc);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
-- Get the flatbuffer as a string containing the binary data
|
||||
local bufAsString = builder:Output()
|
||||
~~~
|
||||
</div>
|
||||
|
||||
|
||||
Now you can write the bytes to a file, send them over the network..
|
||||
**Make sure your file mode (or tranfer protocol) is set to BINARY, not text.**
|
||||
@@ -1690,6 +1809,19 @@ import 'package:flat_buffers/flat_buffers.dart' as fb;
|
||||
import './monster_my_game.sample_generated.dart' as myGame;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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")
|
||||
~~~
|
||||
</div>
|
||||
|
||||
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<int> data = ... // the data, e.g. from file or network
|
||||
myGame.Monster monster = new myGame.Monster(data);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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)
|
||||
~~~
|
||||
</div>
|
||||
|
||||
If you look in the generated files from the schema compiler, you will see it generated
|
||||
accessors for all non-`deprecated` fields. For example:
|
||||
@@ -1876,6 +2019,13 @@ accessors for all non-`deprecated` fields. For example:
|
||||
var name = monster.name;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
local hp = mon:Hp()
|
||||
local mana = mon:Mana()
|
||||
local name = mon:Name()
|
||||
~~~
|
||||
</div>
|
||||
|
||||
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;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
local pos = mon:Pos()
|
||||
local x = pos:X()
|
||||
local y = pos:Y()
|
||||
local z = pos:Z()
|
||||
~~~
|
||||
</div>
|
||||
|
||||
|
||||
`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];
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
local invLength = mon:InventoryLength()
|
||||
local thirdItem = mon:Inventory(3) -- Lua is 1-based
|
||||
~~~
|
||||
</div>
|
||||
|
||||
For `vector`s of `table`s, you can access the elements like any other vector,
|
||||
except your need to handle the result as a FlatBuffer `table`:
|
||||
@@ -2122,6 +2287,13 @@ except your need to handle the result as a FlatBuffer `table`:
|
||||
var secondWeaponDamage = monster.Weapons[1].damage;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
local weaponsLength = mon:WeaponsLength()
|
||||
local secondWeaponName = mon:Weapon(2):Name()
|
||||
local secondWeaponDamage = mon:Weapon(2):Damage()
|
||||
~~~
|
||||
</div>
|
||||
|
||||
Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created
|
||||
the `union`, we need to get both parts of the `union`: the type and the data.
|
||||
@@ -2257,6 +2429,19 @@ We can access the type to dynamically cast the data as needed (since the
|
||||
}
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.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
|
||||
~~~
|
||||
</div>
|
||||
|
||||
## Mutating FlatBuffers
|
||||
|
||||
@@ -2337,6 +2522,11 @@ mutators like so:
|
||||
<API for mutating FlatBuffers not yet available in Dart.>
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
~~~{.lua}
|
||||
<API for mutating FlatBuffers is not yet available in Lua.>
|
||||
~~~
|
||||
</div>
|
||||
|
||||
We use the somewhat verbose term `mutate` instead of `set` to indicate that this
|
||||
is a special use case, not to be confused with the default way of constructing
|
||||
@@ -2449,5 +2639,9 @@ For your chosen language, see:
|
||||
<div class="language-dart">
|
||||
[Use in Dart](@ref flatbuffers_guide_use_dart)
|
||||
</div>
|
||||
<div class="language-lua">
|
||||
[Use in Lua](@ref flatbuffers_guide_use_lua)
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
@@ -758,6 +758,7 @@ INPUT = "FlatBuffers.md" \
|
||||
"TypeScriptUsage.md" \
|
||||
"PHPUsage.md" \
|
||||
"PythonUsage.md" \
|
||||
"LuaUsage.md" \
|
||||
"Support.md" \
|
||||
"Benchmarks.md" \
|
||||
"WhitePaper.md" \
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
title="Use in Python"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_dart"
|
||||
title="Use in Dart"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_lua"
|
||||
title="Use in Lua"/>
|
||||
<tab type="user" url="@ref flexbuffers"
|
||||
title="Schema-less version"/>
|
||||
<tab type="usergroup" url="" title="gRPC">
|
||||
|
||||
@@ -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,
|
||||
|
||||
8
lua/flatbuffers.lua
Normal file
8
lua/flatbuffers.lua
Normal file
@@ -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
|
||||
123
lua/flatbuffers/binaryarray.lua
Normal file
123
lua/flatbuffers/binaryarray.lua
Normal file
@@ -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
|
||||
368
lua/flatbuffers/builder.lua
Normal file
368
lua/flatbuffers/builder.lua
Normal file
@@ -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
|
||||
17
lua/flatbuffers/compat.lua
Normal file
17
lua/flatbuffers/compat.lua
Normal file
@@ -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
|
||||
198
lua/flatbuffers/numTypes.lua
Normal file
198
lua/flatbuffers/numTypes.lua
Normal file
@@ -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 = "<b"
|
||||
}
|
||||
|
||||
local uint8_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = 0,
|
||||
max_value = 2^8-1,
|
||||
lua_type = type(1),
|
||||
name = "uint8",
|
||||
packFmt = "<I1"
|
||||
}
|
||||
|
||||
local uint16_mt =
|
||||
{
|
||||
bytewidth = 2,
|
||||
min_value = 0,
|
||||
max_value = 2^16-1,
|
||||
lua_type = type(1),
|
||||
name = "uint16",
|
||||
packFmt = "<I2"
|
||||
}
|
||||
|
||||
local uint32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = 0,
|
||||
max_value = 2^32-1,
|
||||
lua_type = type(1),
|
||||
name = "uint32",
|
||||
packFmt = "<I4"
|
||||
}
|
||||
|
||||
local uint64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = 0,
|
||||
max_value = 2^64-1,
|
||||
lua_type = type(1),
|
||||
name = "uint64",
|
||||
packFmt = "<I8"
|
||||
}
|
||||
|
||||
local int8_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = -2^7,
|
||||
max_value = 2^7-1,
|
||||
lua_type = type(1),
|
||||
name = "int8",
|
||||
packFmt = "<i1"
|
||||
}
|
||||
|
||||
local int16_mt =
|
||||
{
|
||||
bytewidth = 2,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
lua_type = type(1),
|
||||
name = "int16",
|
||||
packFmt = "<i2"
|
||||
}
|
||||
|
||||
local int32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
lua_type = type(1),
|
||||
name = "int32",
|
||||
packFmt = "<i4"
|
||||
}
|
||||
|
||||
local int64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = -2^63,
|
||||
max_value = 2^63-1,
|
||||
lua_type = type(1),
|
||||
name = "int64",
|
||||
packFmt = "<i8"
|
||||
}
|
||||
|
||||
local float32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = nil,
|
||||
max_value = nil,
|
||||
lua_type = type(1.0),
|
||||
name = "float32",
|
||||
packFmt = "<f"
|
||||
}
|
||||
|
||||
local float64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = nil,
|
||||
max_value = nil,
|
||||
lua_type = type(1.0),
|
||||
name = "float64",
|
||||
packFmt = "<d"
|
||||
}
|
||||
|
||||
-- register the base class
|
||||
setmetatable(bool_mt, {__index = type_mt})
|
||||
setmetatable(uint8_mt, {__index = type_mt})
|
||||
setmetatable(uint16_mt, {__index = type_mt})
|
||||
setmetatable(uint32_mt, {__index = type_mt})
|
||||
setmetatable(uint64_mt, {__index = type_mt})
|
||||
setmetatable(int8_mt, {__index = type_mt})
|
||||
setmetatable(int16_mt, {__index = type_mt})
|
||||
setmetatable(int32_mt, {__index = type_mt})
|
||||
setmetatable(int64_mt, {__index = type_mt})
|
||||
setmetatable(float32_mt, {__index = type_mt})
|
||||
setmetatable(float64_mt, {__index = type_mt})
|
||||
|
||||
|
||||
m.Bool = bool_mt
|
||||
m.Uint8 = uint8_mt
|
||||
m.Uint16 = uint16_mt
|
||||
m.Uint32 = uint32_mt
|
||||
m.Uint64 = uint64_mt
|
||||
m.Int8 = int8_mt
|
||||
m.Int16 = int16_mt
|
||||
m.Int32 = int32_mt
|
||||
m.Int64 = int64_mt
|
||||
m.Float32 = float32_mt
|
||||
m.Float64 = float64_mt
|
||||
|
||||
m.UOffsetT = uint32_mt
|
||||
m.VOffsetT = uint16_mt
|
||||
m.SOffsetT = int32_mt
|
||||
|
||||
function GenerateTypes(listOfTypes)
|
||||
for _,t in pairs(listOfTypes) do
|
||||
t.Pack = function(self, value) return bpack(self.packFmt, value) end
|
||||
t.Unpack = function(self, buf, pos) return bunpack(self.packFmt, buf, pos) end
|
||||
end
|
||||
end
|
||||
|
||||
GenerateTypes(m)
|
||||
|
||||
return m
|
||||
97
lua/flatbuffers/view.lua
Normal file
97
lua/flatbuffers/view.lua
Normal file
@@ -0,0 +1,97 @@
|
||||
local m = {}
|
||||
local mt = {}
|
||||
|
||||
local mt_name = "flatbuffers.view.mt"
|
||||
|
||||
local N = require("flatbuffers.numTypes")
|
||||
local binaryarray = require("flatbuffers.binaryarray")
|
||||
|
||||
function m.New(buf, pos)
|
||||
N.UOffsetT:EnforceNumber(pos)
|
||||
|
||||
-- need to convert from a string buffer into
|
||||
-- a binary array
|
||||
|
||||
local o = {
|
||||
bytes = type(buf) == "string" and binaryarray.New(buf) or buf,
|
||||
pos = pos
|
||||
}
|
||||
setmetatable(o, {__index = mt, __metatable = mt_name})
|
||||
return o
|
||||
end
|
||||
|
||||
function mt:Offset(vtableOffset)
|
||||
local vtable = self.pos - self:Get(N.SOffsetT, self.pos)
|
||||
local vtableEnd = self:Get(N.VOffsetT, vtable)
|
||||
if vtableOffset < vtableEnd then
|
||||
return self:Get(N.VOffsetT, vtable + vtableOffset)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function mt:Indirect(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
return off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:String(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
off = off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
local start = off + N.UOffsetT.bytewidth
|
||||
local length = N.UOffsetT:Unpack(self.bytes, off)
|
||||
return self.bytes:Slice(start, start+length)
|
||||
end
|
||||
|
||||
function mt:VectorLen(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
off = off + self.pos
|
||||
off = off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
return N.UOffsetT:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:Vector(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
|
||||
off = off + self.pos
|
||||
local x = off + self:Get(N.UOffsetT, off)
|
||||
x = x + N.UOffsetT.bytewidth
|
||||
return x
|
||||
end
|
||||
|
||||
function mt:Union(t2, off)
|
||||
assert(getmetatable(t2) == mt_name)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
|
||||
off = off + self.pos
|
||||
t2.pos = off + self:Get(N.UOffsetT, off)
|
||||
t2.bytes = self.bytes
|
||||
end
|
||||
|
||||
function mt:Get(flags, off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
return flags:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:GetSlot(slot, d, validatorFlags)
|
||||
N.VOffsetT:EnforceNumber(slot)
|
||||
if validatorFlags then
|
||||
validatorFlags:EnforceNumber(d)
|
||||
end
|
||||
local off = self:Offset(slot)
|
||||
if off == 0 then
|
||||
return d
|
||||
end
|
||||
return self:Get(validatorFlags, self.pos + off)
|
||||
end
|
||||
|
||||
function mt:GetVOffsetTSlot(slot, d)
|
||||
N.VOffsetT:EnforceNumber(slot)
|
||||
N.VOffsetT:EnforceNumber(d)
|
||||
local off = self:Offset(slot)
|
||||
if off == 0 then
|
||||
return d
|
||||
end
|
||||
return off
|
||||
end
|
||||
|
||||
return m
|
||||
11
samples/lua/MyGame/Sample/Color.lua
Normal file
11
samples/lua/MyGame/Sample/Color.lua
Normal file
@@ -0,0 +1,11 @@
|
||||
-- automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
-- namespace: Sample
|
||||
|
||||
local Color = {
|
||||
Red = 0,
|
||||
Green = 1,
|
||||
Blue = 2,
|
||||
}
|
||||
|
||||
return Color -- return the module
|
||||
10
samples/lua/MyGame/Sample/Equipment.lua
Normal file
10
samples/lua/MyGame/Sample/Equipment.lua
Normal file
@@ -0,0 +1,10 @@
|
||||
-- automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
-- namespace: Sample
|
||||
|
||||
local Equipment = {
|
||||
NONE = 0,
|
||||
Weapon = 1,
|
||||
}
|
||||
|
||||
return Equipment -- return the module
|
||||
122
samples/lua/MyGame/Sample/Monster.lua
Normal file
122
samples/lua/MyGame/Sample/Monster.lua
Normal file
@@ -0,0 +1,122 @@
|
||||
-- automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
-- namespace: Sample
|
||||
|
||||
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_mt:Pos()
|
||||
local o = self.view:Offset(4)
|
||||
if o ~= 0 then
|
||||
local x = o + self.view.pos
|
||||
local obj = require('MyGame.Sample.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 2
|
||||
end
|
||||
function Monster_mt:Weapons(j)
|
||||
local o = self.view:Offset(18)
|
||||
if o ~= 0 then
|
||||
local x = self.view:Vector(o)
|
||||
x = x + ((j-1) * 4)
|
||||
x = self.view:Indirect(x)
|
||||
local obj = require('MyGame.Sample.Weapon').New()
|
||||
obj:Init(self.view.bytes, x)
|
||||
return obj
|
||||
end
|
||||
end
|
||||
function Monster_mt:WeaponsLength()
|
||||
local o = self.view:Offset(18)
|
||||
if o ~= 0 then
|
||||
return self.view:VectorLen(o)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
function Monster_mt:EquippedType()
|
||||
local o = self.view:Offset(20)
|
||||
if o ~= 0 then
|
||||
return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
function Monster_mt:Equipped()
|
||||
local o = self.view:Offset(22)
|
||||
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.Start(builder) builder:StartObject(10) 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, 2) end
|
||||
function Monster.AddWeapons(builder, weapons) builder:PrependUOffsetTRelativeSlot(7, weapons, 0) end
|
||||
function Monster.StartWeaponsVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
|
||||
function Monster.AddEquippedType(builder, equippedType) builder:PrependUint8Slot(8, equippedType, 0) end
|
||||
function Monster.AddEquipped(builder, equipped) builder:PrependUOffsetTRelativeSlot(9, equipped, 0) end
|
||||
function Monster.End(builder) return builder:EndObject() end
|
||||
|
||||
return Monster -- return the module
|
||||
35
samples/lua/MyGame/Sample/Vec3.lua
Normal file
35
samples/lua/MyGame/Sample/Vec3.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
-- automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
-- namespace: Sample
|
||||
|
||||
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.CreateVec3(builder, x, y, z)
|
||||
builder:Prep(4, 12)
|
||||
builder:PrependFloat32(z)
|
||||
builder:PrependFloat32(y)
|
||||
builder:PrependFloat32(x)
|
||||
return builder:Offset()
|
||||
end
|
||||
|
||||
return Vec3 -- return the module
|
||||
42
samples/lua/MyGame/Sample/Weapon.lua
Normal file
42
samples/lua/MyGame/Sample/Weapon.lua
Normal file
@@ -0,0 +1,42 @@
|
||||
-- automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
-- namespace: Sample
|
||||
|
||||
local flatbuffers = require('flatbuffers')
|
||||
|
||||
local Weapon = {} -- the module
|
||||
local Weapon_mt = {} -- the class metatable
|
||||
|
||||
function Weapon.New()
|
||||
local o = {}
|
||||
setmetatable(o, {__index = Weapon_mt})
|
||||
return o
|
||||
end
|
||||
function Weapon.GetRootAsWeapon(buf, offset)
|
||||
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
|
||||
local o = Weapon.New()
|
||||
o:Init(buf, n + offset)
|
||||
return o
|
||||
end
|
||||
function Weapon_mt:Init(buf, pos)
|
||||
self.view = flatbuffers.view.New(buf, pos)
|
||||
end
|
||||
function Weapon_mt:Name()
|
||||
local o = self.view:Offset(4)
|
||||
if o ~= 0 then
|
||||
return self.view:String(o + self.view.pos)
|
||||
end
|
||||
end
|
||||
function Weapon_mt:Damage()
|
||||
local o = self.view:Offset(6)
|
||||
if o ~= 0 then
|
||||
return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
function Weapon.Start(builder) builder:StartObject(2) end
|
||||
function Weapon.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(0, name, 0) end
|
||||
function Weapon.AddDamage(builder, damage) builder:PrependInt16Slot(1, damage, 0) end
|
||||
function Weapon.End(builder) return builder:EndObject() end
|
||||
|
||||
return Weapon -- return the module
|
||||
107
samples/sample_binary.lua
Normal file
107
samples/sample_binary.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
-- need to update the Lua path to point to the local flatbuffers implementation
|
||||
package.path = string.format("../lua/?.lua;%s",package.path)
|
||||
package.path = string.format("./lua/?.lua;%s",package.path)
|
||||
|
||||
-- require the library
|
||||
local flatbuffers = require("flatbuffers")
|
||||
|
||||
local binaryArray = flatbuffers.binaryArray-- for hex dump utility
|
||||
|
||||
-- require the files generated from the schema
|
||||
local weapon = require("MyGame.Sample.Weapon")
|
||||
local monster = require("MyGame.Sample.Monster")
|
||||
local vec3 = require("MyGame.Sample.Vec3")
|
||||
local color = require("MyGame.Sample.Color")
|
||||
local equipment = require("MyGame.Sample.Equipment")
|
||||
|
||||
-- get access to the builder, providing an array of size 1024
|
||||
local builder = flatbuffers.Builder(1024)
|
||||
|
||||
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)
|
||||
|
||||
-- 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)
|
||||
|
||||
-- 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)
|
||||
|
||||
-- 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)
|
||||
local orc = monster.End(builder)
|
||||
|
||||
-- Call 'Finish()' to instruct the builder that this monster is complete.
|
||||
builder:Finish(orc)
|
||||
|
||||
-- Get the flatbuffer as a string containing the binary data
|
||||
local bufAsString = builder:Output()
|
||||
|
||||
-- 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)
|
||||
|
||||
assert(mon:Mana() == 150)
|
||||
assert(mon:Hp() == 300)
|
||||
assert(mon:Name() == "Orc")
|
||||
assert(mon:Color() == color.Red)
|
||||
assert(mon:Pos():X() == 1.0)
|
||||
assert(mon:Pos():Y() == 2.0)
|
||||
assert(mon:Pos():Z() == 3.0)
|
||||
|
||||
for i=1,mon:InventoryLength() do
|
||||
assert(mon:Inventory(i) == i)
|
||||
end
|
||||
|
||||
local expected = {
|
||||
{w = 'Sword', d = 3},
|
||||
{w = 'Axe', d = 5}
|
||||
}
|
||||
|
||||
for i=1,mon:WeaponsLength() do
|
||||
assert(mon:Weapons(i):Name() == expected[i].w)
|
||||
assert(mon:Weapons(i):Damage() == expected[i].d)
|
||||
end
|
||||
|
||||
assert(mon:EquippedType() == equipment.Weapon)
|
||||
|
||||
local unionWeapon = weapon.New()
|
||||
unionWeapon:Init(mon:Equipped().bytes,mon:Equipped().pos)
|
||||
assert(unionWeapon:Name() == "Axe")
|
||||
assert(unionWeapon:Damage() == 5)
|
||||
|
||||
print("The Lua FlatBuffer example was successfully created and verified!")
|
||||
@@ -71,6 +71,10 @@ int main(int argc, const char *argv[]) {
|
||||
flatbuffers::IDLOptions::kPython,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
|
||||
flatbuffers::IDLOptions::kLua,
|
||||
"Generate Lua files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr,
|
||||
flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
|
||||
729
src/idl_gen_lua.cpp
Normal file
729
src/idl_gen_lua.cpp
Normal file
@@ -0,0 +1,729 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "flatbuffers/code_generators.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
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<std::string> 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
|
||||
@@ -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,
|
||||
|
||||
6
tests/LuaTest.bat
Normal file
6
tests/LuaTest.bat
Normal file
@@ -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
|
||||
31
tests/MyGame/Example/Ability.lua
Normal file
31
tests/MyGame/Example/Ability.lua
Normal file
@@ -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
|
||||
12
tests/MyGame/Example/Any.lua
Normal file
12
tests/MyGame/Example/Any.lua
Normal file
@@ -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
|
||||
11
tests/MyGame/Example/Color.lua
Normal file
11
tests/MyGame/Example/Color.lua
Normal file
@@ -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
|
||||
542
tests/MyGame/Example/Monster.lua
Normal file
542
tests/MyGame/Example/Monster.lua
Normal file
@@ -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
|
||||
35
tests/MyGame/Example/Referrable.lua
Normal file
35
tests/MyGame/Example/Referrable.lua
Normal file
@@ -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
|
||||
50
tests/MyGame/Example/Stat.lua
Normal file
50
tests/MyGame/Example/Stat.lua
Normal file
@@ -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
|
||||
32
tests/MyGame/Example/Test.lua
Normal file
32
tests/MyGame/Example/Test.lua
Normal file
@@ -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
|
||||
35
tests/MyGame/Example/TestSimpleTableWithEnum.lua
Normal file
35
tests/MyGame/Example/TestSimpleTableWithEnum.lua
Normal file
@@ -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
|
||||
141
tests/MyGame/Example/TypeAliases.lua
Normal file
141
tests/MyGame/Example/TypeAliases.lua
Normal file
@@ -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
|
||||
54
tests/MyGame/Example/Vec3.lua
Normal file
54
tests/MyGame/Example/Vec3.lua
Normal file
@@ -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
|
||||
27
tests/MyGame/Example2/Monster.lua
Normal file
27
tests/MyGame/Example2/Monster.lua
Normal file
@@ -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
|
||||
27
tests/MyGame/InParentNamespace.lua
Normal file
27
tests/MyGame/InParentNamespace.lua
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
294
tests/luatest.lua
Normal file
294
tests/luatest.lua
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user