Commit ba5eb3b5 authored by Derek Bailey's avatar Derek Bailey Committed by Wouter van Oortmerssen

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
parent 8ea293b9
......@@ -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
......
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,
......
local m = {}
m.Builder = require("flatbuffers.builder").New
m.N = require("flatbuffers.numTypes")
m.view = require("flatbuffers.view")
m.binaryArray = require("flatbuffers.binaryarray")
return m
\ No newline at end of file
local m = {} -- the module table
local mt = {} -- the module metatable
-- given a binary array, set a metamethod to return its length
-- (e.g., #binaryArray, calls this)
function mt:__len()
return self.size
end
-- Create a new binary array of an initial size
function m.New(sizeOrString)
-- the array storage itself
local o = {}
if type(sizeOrString) == "string" then
o.str = sizeOrString
o.size = #sizeOrString
elseif type(sizeOrString) == "number" then
o.data = {}
o.size = sizeOrString
else
error("Expect a integer size value or string to construct a binary array")
end
-- set the inheritance
setmetatable(o, {__index = mt, __len = mt.__len})
return o
end
-- Get a slice of the binary array from start to end position
function mt:Slice(startPos, endPos)
startPos = startPos or 0
endPos = endPos or self.size
local d = self.data
if d then
-- if the self.data is defined, we are building the buffer
-- in a Lua table
-- new table to store the slice components
local b = {}
-- starting with the startPos, put all
-- values into the new table to be concat later
-- updated the startPos based on the size of the
-- value
while startPos < endPos do
local v = d[startPos] or '/0'
table.insert(b, v)
startPos = startPos + #v
end
-- combine the table of strings into one string
-- this is faster than doing a bunch of concats by themselves
return table.concat(b)
else
-- n.b start/endPos are 0-based incoming, so need to convert
-- correctly. in python a slice includes start -> end - 1
return self.str:sub(startPos+1, endPos)
end
end
-- Grow the binary array to a new size, placing the exisiting data
-- at then end of the new array
function mt:Grow(newsize)
-- the new table to store the data
local newT = {}
-- the offset to be applied to existing entries
local offset = newsize - self.size
-- loop over all the current entries and
-- add them to the new table at the correct
-- offset location
local d = self.data
for i,data in pairs(d) do
newT[i + offset] = data
end
-- update this storage with the new table and size
self.data = newT
self.size = newsize
end
-- memorization for padding strings
local pads = {}
-- pad the binary with n \0 bytes at the starting position
function mt:Pad(n, startPos)
-- use memorization to avoid creating a bunch of strings
-- all the time
local s = pads[n]
if not s then
s = string.rep('\0', n)
pads[n] = s
end
-- store the padding string at the start position in the
-- Lua table
self.data[startPos] = s
end
-- Sets the binary array value at the specified position
function mt:Set(value, position)
self.data[position] = value
end
-- locals for slightly faster access
local sunpack = string.unpack
local spack = string.pack
-- Pack the data into a binary representation
function m.Pack(fmt, ...)
return spack(fmt, ...)
end
-- Unpack the data from a binary representation in
-- a Lua value
function m.Unpack(fmt, s, pos)
return sunpack(fmt, s.str, pos + 1)
end
-- Return the binary array module
return m
\ No newline at end of file
local N = require("flatbuffers.numTypes")
local ba = require("flatbuffers.binaryarray")
local compat = require("flatbuffers.compat")
local m = {}
local mt = {}
-- get locals for faster access
local VOffsetT = N.VOffsetT
local UOffsetT = N.UOffsetT
local SOffsetT = N.SOffsetT
local Bool = N.Bool
local Uint8 = N.Uint8
local Uint16 = N.Uint16
local Uint32 = N.Uint32
local Uint64 = N.Uint64
local Int8 = N.Int8
local Int16 = N.Int16
local Int32 = N.Int32
local Int64 = N.Int64
local Float32 = N.Float32
local Float64 = N.Float64
local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB
local VtableMetadataFields = 2
local getAlignSize = compat.GetAlignSize
local function vtableEqual(a, objectStart, b)
UOffsetT:EnforceNumber(objectStart)
if (#a * VOffsetT.bytewidth) ~= #b then
return false
end
for i, elem in ipairs(a) do
local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth)
if x ~= 0 or elem ~= 0 then
local y = objectStart - elem
if x ~= y then
return false
end
end
end
return true
end
function m.New(initialSize)
assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE)
local o =
{
finished = false,
bytes = ba.New(initialSize),
nested = false,
head = initialSize,
minalign = 1,
vtables = {}
}
setmetatable(o, {__index = mt})
return o
end
function mt:Output(full)
assert(self.finished, "Builder Not Finished")
if full then
return self.bytes:Slice()
else
return self.bytes:Slice(self.head)
end
end
function mt:StartObject(numFields)
assert(not self.nested)
local vtable = {}
for _=1,numFields do
table.insert(vtable, 0)
end
self.currentVTable = vtable
self.objectEnd = self:Offset()
self.minalign = 1
self.nested = true
end
function mt:WriteVtable()
self:PrependSOffsetTRelative(0)
local objectOffset = self:Offset()
local exisitingVTable
local i = #self.vtables
while i >= 1 do
if self.vtables[i] == 0 then
table.remove(self.vtables,i)
end
i = i - 1
end
while i >= 1 do
local vt2Offset = self.vtables[i]
local vt2Start = #self.bytes - vt2Offset
local vt2len = VOffsetT:Unpack(self.bytes, vt2Start)
local metadata = VtableMetadataFields * VOffsetT.bytewidth
local vt2End = vt2Start + vt2Len
local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End)
if vtableEqual(self.currentVTable, objectOffset, vt2) then
exisitingVTable = vt2Offset
break
end
i = i - 1
end
if not exisitingVTable then
i = #self.currentVTable
while i >= 1 do
local off = 0
local a = self.currentVTable[i]
if a and a ~= 0 then
off = objectOffset - a
end
self:PrependVOffsetT(off)
i = i - 1
end
local objectSize = objectOffset - self.objectEnd
self:PrependVOffsetT(objectSize)
local vBytes = #self.currentVTable + VtableMetadataFields
vBytes = vBytes * VOffsetT.bytewidth
self:PrependVOffsetT(vBytes)
local objectStart = #self.bytes - objectOffset
self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart)
table.insert(self.vtables, self:Offset())
else
local objectStart = #self.bytes - objectOffset
self.head = objectStart
self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head)
end
self.currentVTable = nil
return objectOffset
end
function mt:EndObject()
assert(self.nested)
self.nested = false
return self:WriteVtable()
end
local function growByteBuffer(self, desiredSize)
local s = #self.bytes
assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes")
local newsize = s
repeat
newsize = math.min(newsize * 2, MAX_BUFFER_SIZE)
if newsize == 0 then newsize = 1 end
until newsize > desiredSize
self.bytes:Grow(newsize)
end
function mt:Head()
return self.head
end
function mt:Offset()
return #self.bytes - self.head
end
function mt:Pad(n)
if n > 0 then
-- pads are 8-bit, so skip the bytewidth lookup
local h = self.head - n -- UInt8
self.head = h
self.bytes:Pad(n, h)
end
end
function mt:Prep(size, additionalBytes)
if size > self.minalign then
self.minalign = size
end
local h = self.head
local k = #self.bytes - h + additionalBytes
local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size)
local desiredSize = alignsize + size + additionalBytes
while self.head < desiredSize do
local oldBufSize = #self.bytes
growByteBuffer(self, desiredSize)
local updatedHead = self.head + #self.bytes - oldBufSize
self.head = updatedHead
end
self:Pad(alignsize)
end
function mt:PrependSOffsetTRelative(off)
self:Prep(SOffsetT.bytewidth, 0)
assert(off <= self:Offset(), "Offset arithmetic error")
local off2 = self:Offset() - off + SOffsetT.bytewidth
self:Place(off2, SOffsetT)
end
function mt:PrependUOffsetTRelative(off)
self:Prep(UOffsetT.bytewidth, 0)
local soffset = self:Offset()
if off <= soffset then
local off2 = soffset - off + UOffsetT.bytewidth
self:Place(off2, UOffsetT)
else
error("Offset arithmetic error")
end
end
function mt:StartVector(elemSize, numElements, alignment)
assert(not self.nested)
self.nested = true
self:Prep(Uint32.bytewidth, elemSize * numElements)
self:Prep(alignment, elemSize * numElements)
return self:Offset()
end
function mt:EndVector(vectorNumElements)
assert(self.nested)
self.nested = false
self:Place(vectorNumElements, UOffsetT)
return self:Offset()
end
function mt:CreateString(s)
assert(not self.nested)
self.nested = true
assert(type(s) == "string")
self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth)
self:Place(0, Uint8)
local l = #s
self.head = self.head - l
self.bytes:Set(s, self.head, self.head + l)
return self:EndVector(#s)
end
function mt:CreateByteVector(x)
assert(not self.nested)
self.nested = true
self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth)
local l = #x
self.head = self.head - l
self.bytes:Set(x, self.head, self.head + l)
return self:EndVector(#x)
end
function mt:Slot(slotnum)
assert(self.nested)
-- n.b. slot number is 0-based
self.currentVTable[slotnum + 1] = self:Offset()
end
local function finish(self, rootTable, sizePrefix)
UOffsetT:EnforceNumber(rootTable)
local prepSize = UOffsetT.bytewidth
if sizePrefix then
prepSize = prepSize + Int32.bytewidth
end
self:Prep(self.minalign, prepSize)
self:PrependUOffsetTRelative(rootTable)
if sizePrefix then
local size = #self.bytes - self.head
Int32:EnforceNumber(size)
self:PrependInt32(size)
end
self.finished = true
return self.head
end
function mt:Finish(rootTable)
return finish(self, rootTable, false)
end
function mt:FinishSizePrefixed(rootTable)
return finish(self, rootTable, true)
end
function mt:Prepend(flags, off)
self:Prep(flags.bytewidth, 0)
self:Place(off, flags)
end
function mt:PrependSlot(flags, o, x, d)
flags:EnforceNumber(x)
flags:EnforceNumber(d)
if x ~= d then
self:Prepend(flags, x)
self:Slot(o)
end
end
function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end
function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end
function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end
function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end
function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end
function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end
function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end
function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end
function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end
function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end
function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end
function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end
function mt:PrependUOffsetTRelativeSlot(o,x,d)
if x~=d then
self:PrependUOffsetTRelative(x)
self:Slot(o)
end
end
function mt:PrependStructSlot(v,x,d)
UOffsetT:EnforceNumber(d)
if x~=d then
UOffsetT:EnforceNumber(x)
assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.")
self:Slot(v)
end
end
function mt:PrependBool(x) self:Prepend(Bool, x) end
function mt:PrependByte(x) self:Prepend(Uint8, x) end
function mt:PrependUint8(x) self:Prepend(Uint8, x) end
function mt:PrependUint16(x) self:Prepend(Uint16, x) end
function mt:PrependUint32(x) self:Prepend(Uint32, x) end
function mt:PrependUint64(x) self:Prepend(Uint64, x) end
function mt:PrependInt8(x) self:Prepend(Int8, x) end
function mt:PrependInt16(x) self:Prepend(Int16, x) end
function mt:PrependInt32(x) self:Prepend(Int32, x) end
function mt:PrependInt64(x) self:Prepend(Int64, x) end
function mt:PrependFloat32(x) self:Prepend(Float32, x) end
function mt:PrependFloat64(x) self:Prepend(Float64, x) end
function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end
function mt:Place(x, flags)
local d = flags:EnforceNumberAndPack(x)
local h = self.head - flags.bytewidth
self.head = h
self.bytes:Set(d, h)
end
return m
\ No newline at end of file
local m = {}
local getAlignSize
if _VERSION == "Lua 5.3" then
getAlignSize = function(k, size)
return ((~k) + 1) & (size - 1)
end
else
getAlignSize = function(self, size, additionalBytes)
local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1
return bit32.band(alignsize,(size - 1))
end
end
m.GetAlignSize = getAlignSize
return m
\ No newline at end of file
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
\ No newline at end of file
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
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Sample
local Color = {
Red = 0,
Green = 1,
Blue = 2,
}
return Color -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Sample
local Equipment = {
NONE = 0,
Weapon = 1,
}
return Equipment -- return the module
\ No newline at end of file
-- 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
\ No newline at end of file
-- 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
\ No newline at end of file
-- 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
\ No newline at end of file
-- 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!")
\ No newline at end of file
......@@ -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 },
......
/*
* 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,
......
set buildtype=Release
if "%1"=="-b" set buildtype=%2
..\%buildtype%\flatc.exe --lua -I include_test monster_test.fbs
lua53.exe luatest.lua
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local Ability = {} -- the module
local Ability_mt = {} -- the class metatable
function Ability.New()
local o = {}
setmetatable(o, {__index = Ability_mt})
return o
end
function Ability_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Ability_mt:Id()
return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 0)
end
function Ability_mt:Distance()
return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 4)
end
function Ability.CreateAbility(builder, id, distance)
builder:Prep(4, 8)
builder:PrependUint32(distance)
builder:PrependUint32(id)
return builder:Offset()
end
return Ability -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local Any = {
NONE = 0,
Monster = 1,
TestSimpleTableWithEnum = 2,
MyGame_Example2_Monster = 3,
}
return Any -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local Color = {
Red = 1,
Green = 2,
Blue = 8,
}
return Color -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
-- /// an example documentation comment: monster object
local Monster = {} -- the module
local Monster_mt = {} -- the class metatable
function Monster.New()
local o = {}
setmetatable(o, {__index = Monster_mt})
return o
end
function Monster.GetRootAsMonster(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = Monster.New()
o:Init(buf, n + offset)
return o
end
function Monster_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Monster_mt:Pos()
local o = self.view:Offset(4)
if o ~= 0 then
local x = o + self.view.pos
local obj = require('MyGame.Example.Vec3').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:Mana()
local o = self.view:Offset(6)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
end
return 150
end
function Monster_mt:Hp()
local o = self.view:Offset(8)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
end
return 100
end
function Monster_mt:Name()
local o = self.view:Offset(10)
if o ~= 0 then
return self.view:String(o + self.view.pos)
end
end
function Monster_mt:Inventory(j)
local o = self.view:Offset(14)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
end
return 0
end
function Monster_mt:InventoryLength()
local o = self.view:Offset(14)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Color()
local o = self.view:Offset(16)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
end
return 8
end
function Monster_mt:TestType()
local o = self.view:Offset(18)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
end
return 0
end
function Monster_mt:Test()
local o = self.view:Offset(20)
if o ~= 0 then
local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
self.view:Union(obj, o)
return obj
end
end
function Monster_mt:Test4(j)
local o = self.view:Offset(22)
if o ~= 0 then
local x = self.view:Vector(o)
x = x + ((j-1) * 4)
local obj = require('MyGame.Example.Test').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:Test4Length()
local o = self.view:Offset(22)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Testarrayofstring(j)
local o = self.view:Offset(24)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:String(a + ((j-1) * 4))
end
return ''
end
function Monster_mt:TestarrayofstringLength()
local o = self.view:Offset(24)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
-- /// an example documentation comment: this will end up in the generated code
-- /// multiline too
function Monster_mt:Testarrayoftables(j)
local o = self.view:Offset(26)
if o ~= 0 then
local x = self.view:Vector(o)
x = x + ((j-1) * 4)
x = self.view:Indirect(x)
local obj = require('MyGame.Example.Monster').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:TestarrayoftablesLength()
local o = self.view:Offset(26)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Enemy()
local o = self.view:Offset(28)
if o ~= 0 then
local x = self.view:Indirect(o + self.view.pos)
local obj = require('MyGame.Example.Monster').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:Testnestedflatbuffer(j)
local o = self.view:Offset(30)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
end
return 0
end
function Monster_mt:TestnestedflatbufferLength()
local o = self.view:Offset(30)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Testempty()
local o = self.view:Offset(32)
if o ~= 0 then
local x = self.view:Indirect(o + self.view.pos)
local obj = require('MyGame.Example.Stat').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:Testbool()
local o = self.view:Offset(34)
if o ~= 0 then
return (self.view:Get(flatbuffers.N.Bool, o + self.view.pos) ~= 0)
end
return false
end
function Monster_mt:Testhashs32Fnv1()
local o = self.view:Offset(36)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashu32Fnv1()
local o = self.view:Offset(38)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashs64Fnv1()
local o = self.view:Offset(40)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashu64Fnv1()
local o = self.view:Offset(42)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashs32Fnv1a()
local o = self.view:Offset(44)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashu32Fnv1a()
local o = self.view:Offset(46)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashs64Fnv1a()
local o = self.view:Offset(48)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
end
return 0
end
function Monster_mt:Testhashu64Fnv1a()
local o = self.view:Offset(50)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function Monster_mt:Testarrayofbools(j)
local o = self.view:Offset(52)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Bool, a + ((j-1) * 1))
end
return 0
end
function Monster_mt:TestarrayofboolsLength()
local o = self.view:Offset(52)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Testf()
local o = self.view:Offset(54)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
end
return 3.14159
end
function Monster_mt:Testf2()
local o = self.view:Offset(56)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
end
return 3.0
end
function Monster_mt:Testf3()
local o = self.view:Offset(58)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
end
return 0.0
end
function Monster_mt:Testarrayofstring2(j)
local o = self.view:Offset(60)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:String(a + ((j-1) * 4))
end
return ''
end
function Monster_mt:Testarrayofstring2Length()
local o = self.view:Offset(60)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Testarrayofsortedstruct(j)
local o = self.view:Offset(62)
if o ~= 0 then
local x = self.view:Vector(o)
x = x + ((j-1) * 8)
local obj = require('MyGame.Example.Ability').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:TestarrayofsortedstructLength()
local o = self.view:Offset(62)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Flex(j)
local o = self.view:Offset(64)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
end
return 0
end
function Monster_mt:FlexLength()
local o = self.view:Offset(64)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:Test5(j)
local o = self.view:Offset(66)
if o ~= 0 then
local x = self.view:Vector(o)
x = x + ((j-1) * 4)
local obj = require('MyGame.Example.Test').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:Test5Length()
local o = self.view:Offset(66)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:VectorOfLongs(j)
local o = self.view:Offset(68)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Int64, a + ((j-1) * 8))
end
return 0
end
function Monster_mt:VectorOfLongsLength()
local o = self.view:Offset(68)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:VectorOfDoubles(j)
local o = self.view:Offset(70)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8))
end
return 0
end
function Monster_mt:VectorOfDoublesLength()
local o = self.view:Offset(70)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:ParentNamespaceTest()
local o = self.view:Offset(72)
if o ~= 0 then
local x = self.view:Indirect(o + self.view.pos)
local obj = require('MyGame.InParentNamespace').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:VectorOfReferrables(j)
local o = self.view:Offset(74)
if o ~= 0 then
local x = self.view:Vector(o)
x = x + ((j-1) * 4)
x = self.view:Indirect(x)
local obj = require('MyGame.Example.Referrable').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:VectorOfReferrablesLength()
local o = self.view:Offset(74)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:SingleWeakReference()
local o = self.view:Offset(76)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function Monster_mt:VectorOfWeakReferences(j)
local o = self.view:Offset(78)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
end
return 0
end
function Monster_mt:VectorOfWeakReferencesLength()
local o = self.view:Offset(78)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:VectorOfStrongReferrables(j)
local o = self.view:Offset(80)
if o ~= 0 then
local x = self.view:Vector(o)
x = x + ((j-1) * 4)
x = self.view:Indirect(x)
local obj = require('MyGame.Example.Referrable').New()
obj:Init(self.view.bytes, x)
return obj
end
end
function Monster_mt:VectorOfStrongReferrablesLength()
local o = self.view:Offset(80)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:CoOwningReference()
local o = self.view:Offset(82)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function Monster_mt:VectorOfCoOwningReferences(j)
local o = self.view:Offset(84)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
end
return 0
end
function Monster_mt:VectorOfCoOwningReferencesLength()
local o = self.view:Offset(84)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster_mt:NonOwningReference()
local o = self.view:Offset(86)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function Monster_mt:VectorOfNonOwningReferences(j)
local o = self.view:Offset(88)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
end
return 0
end
function Monster_mt:VectorOfNonOwningReferencesLength()
local o = self.view:Offset(88)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function Monster.Start(builder) builder:StartObject(43) end
function Monster.AddPos(builder, pos) builder:PrependStructSlot(0, pos, 0) end
function Monster.AddMana(builder, mana) builder:PrependInt16Slot(1, mana, 150) end
function Monster.AddHp(builder, hp) builder:PrependInt16Slot(2, hp, 100) end
function Monster.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(3, name, 0) end
function Monster.AddInventory(builder, inventory) builder:PrependUOffsetTRelativeSlot(5, inventory, 0) end
function Monster.StartInventoryVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
function Monster.AddColor(builder, color) builder:PrependInt8Slot(6, color, 8) end
function Monster.AddTestType(builder, testType) builder:PrependUint8Slot(7, testType, 0) end
function Monster.AddTest(builder, test) builder:PrependUOffsetTRelativeSlot(8, test, 0) end
function Monster.AddTest4(builder, test4) builder:PrependUOffsetTRelativeSlot(9, test4, 0) end
function Monster.StartTest4Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end
function Monster.AddTestarrayofstring(builder, testarrayofstring) builder:PrependUOffsetTRelativeSlot(10, testarrayofstring, 0) end
function Monster.StartTestarrayofstringVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
function Monster.AddTestarrayoftables(builder, testarrayoftables) builder:PrependUOffsetTRelativeSlot(11, testarrayoftables, 0) end
function Monster.StartTestarrayoftablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
function Monster.AddEnemy(builder, enemy) builder:PrependUOffsetTRelativeSlot(12, enemy, 0) end
function Monster.AddTestnestedflatbuffer(builder, testnestedflatbuffer) builder:PrependUOffsetTRelativeSlot(13, testnestedflatbuffer, 0) end
function Monster.StartTestnestedflatbufferVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
function Monster.AddTestempty(builder, testempty) builder:PrependUOffsetTRelativeSlot(14, testempty, 0) end
function Monster.AddTestbool(builder, testbool) builder:PrependBoolSlot(15, testbool, 0) end
function Monster.AddTesthashs32Fnv1(builder, testhashs32Fnv1) builder:PrependInt32Slot(16, testhashs32Fnv1, 0) end
function Monster.AddTesthashu32Fnv1(builder, testhashu32Fnv1) builder:PrependUint32Slot(17, testhashu32Fnv1, 0) end
function Monster.AddTesthashs64Fnv1(builder, testhashs64Fnv1) builder:PrependInt64Slot(18, testhashs64Fnv1, 0) end
function Monster.AddTesthashu64Fnv1(builder, testhashu64Fnv1) builder:PrependUint64Slot(19, testhashu64Fnv1, 0) end
function Monster.AddTesthashs32Fnv1a(builder, testhashs32Fnv1a) builder:PrependInt32Slot(20, testhashs32Fnv1a, 0) end
function Monster.AddTesthashu32Fnv1a(builder, testhashu32Fnv1a) builder:PrependUint32Slot(21, testhashu32Fnv1a, 0) end
function Monster.AddTesthashs64Fnv1a(builder, testhashs64Fnv1a) builder:PrependInt64Slot(22, testhashs64Fnv1a, 0) end
function Monster.AddTesthashu64Fnv1a(builder, testhashu64Fnv1a) builder:PrependUint64Slot(23, testhashu64Fnv1a, 0) end
function Monster.AddTestarrayofbools(builder, testarrayofbools) builder:PrependUOffsetTRelativeSlot(24, testarrayofbools, 0) end
function Monster.StartTestarrayofboolsVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
function Monster.AddTestf(builder, testf) builder:PrependFloat32Slot(25, testf, 3.14159) end
function Monster.AddTestf2(builder, testf2) builder:PrependFloat32Slot(26, testf2, 3.0) end
function Monster.AddTestf3(builder, testf3) builder:PrependFloat32Slot(27, testf3, 0.0) end
function Monster.AddTestarrayofstring2(builder, testarrayofstring2) builder:PrependUOffsetTRelativeSlot(28, testarrayofstring2, 0) end
function Monster.StartTestarrayofstring2Vector(builder, numElems) return builder:StartVector(4, numElems, 4) end
function Monster.AddTestarrayofsortedstruct(builder, testarrayofsortedstruct) builder:PrependUOffsetTRelativeSlot(29, testarrayofsortedstruct, 0) end
function Monster.StartTestarrayofsortedstructVector(builder, numElems) return builder:StartVector(8, numElems, 4) end
function Monster.AddFlex(builder, flex) builder:PrependUOffsetTRelativeSlot(30, flex, 0) end
function Monster.StartFlexVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
function Monster.AddTest5(builder, test5) builder:PrependUOffsetTRelativeSlot(31, test5, 0) end
function Monster.StartTest5Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end
function Monster.AddVectorOfLongs(builder, vectorOfLongs) builder:PrependUOffsetTRelativeSlot(32, vectorOfLongs, 0) end
function Monster.StartVectorOfLongsVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
function Monster.AddVectorOfDoubles(builder, vectorOfDoubles) builder:PrependUOffsetTRelativeSlot(33, vectorOfDoubles, 0) end
function Monster.StartVectorOfDoublesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
function Monster.AddParentNamespaceTest(builder, parentNamespaceTest) builder:PrependUOffsetTRelativeSlot(34, parentNamespaceTest, 0) end
function Monster.AddVectorOfReferrables(builder, vectorOfReferrables) builder:PrependUOffsetTRelativeSlot(35, vectorOfReferrables, 0) end
function Monster.StartVectorOfReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
function Monster.AddSingleWeakReference(builder, singleWeakReference) builder:PrependUint64Slot(36, singleWeakReference, 0) end
function Monster.AddVectorOfWeakReferences(builder, vectorOfWeakReferences) builder:PrependUOffsetTRelativeSlot(37, vectorOfWeakReferences, 0) end
function Monster.StartVectorOfWeakReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
function Monster.AddVectorOfStrongReferrables(builder, vectorOfStrongReferrables) builder:PrependUOffsetTRelativeSlot(38, vectorOfStrongReferrables, 0) end
function Monster.StartVectorOfStrongReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
function Monster.AddCoOwningReference(builder, coOwningReference) builder:PrependUint64Slot(39, coOwningReference, 0) end
function Monster.AddVectorOfCoOwningReferences(builder, vectorOfCoOwningReferences) builder:PrependUOffsetTRelativeSlot(40, vectorOfCoOwningReferences, 0) end
function Monster.StartVectorOfCoOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
function Monster.AddNonOwningReference(builder, nonOwningReference) builder:PrependUint64Slot(41, nonOwningReference, 0) end
function Monster.AddVectorOfNonOwningReferences(builder, vectorOfNonOwningReferences) builder:PrependUOffsetTRelativeSlot(42, vectorOfNonOwningReferences, 0) end
function Monster.StartVectorOfNonOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
function Monster.End(builder) return builder:EndObject() end
return Monster -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local Referrable = {} -- the module
local Referrable_mt = {} -- the class metatable
function Referrable.New()
local o = {}
setmetatable(o, {__index = Referrable_mt})
return o
end
function Referrable.GetRootAsReferrable(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = Referrable.New()
o:Init(buf, n + offset)
return o
end
function Referrable_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Referrable_mt:Id()
local o = self.view:Offset(4)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function Referrable.Start(builder) builder:StartObject(1) end
function Referrable.AddId(builder, id) builder:PrependUint64Slot(0, id, 0) end
function Referrable.End(builder) return builder:EndObject() end
return Referrable -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local Stat = {} -- the module
local Stat_mt = {} -- the class metatable
function Stat.New()
local o = {}
setmetatable(o, {__index = Stat_mt})
return o
end
function Stat.GetRootAsStat(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = Stat.New()
o:Init(buf, n + offset)
return o
end
function Stat_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Stat_mt:Id()
local o = self.view:Offset(4)
if o ~= 0 then
return self.view:String(o + self.view.pos)
end
end
function Stat_mt:Val()
local o = self.view:Offset(6)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
end
return 0
end
function Stat_mt:Count()
local o = self.view:Offset(8)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos)
end
return 0
end
function Stat.Start(builder) builder:StartObject(3) end
function Stat.AddId(builder, id) builder:PrependUOffsetTRelativeSlot(0, id, 0) end
function Stat.AddVal(builder, val) builder:PrependInt64Slot(1, val, 0) end
function Stat.AddCount(builder, count) builder:PrependUint16Slot(2, count, 0) end
function Stat.End(builder) return builder:EndObject() end
return Stat -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local Test = {} -- the module
local Test_mt = {} -- the class metatable
function Test.New()
local o = {}
setmetatable(o, {__index = Test_mt})
return o
end
function Test_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Test_mt:A()
return self.view:Get(flatbuffers.N.Int16, self.view.pos + 0)
end
function Test_mt:B()
return self.view:Get(flatbuffers.N.Int8, self.view.pos + 2)
end
function Test.CreateTest(builder, a, b)
builder:Prep(2, 4)
builder:Pad(1)
builder:PrependInt8(b)
builder:PrependInt16(a)
return builder:Offset()
end
return Test -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local TestSimpleTableWithEnum = {} -- the module
local TestSimpleTableWithEnum_mt = {} -- the class metatable
function TestSimpleTableWithEnum.New()
local o = {}
setmetatable(o, {__index = TestSimpleTableWithEnum_mt})
return o
end
function TestSimpleTableWithEnum.GetRootAsTestSimpleTableWithEnum(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = TestSimpleTableWithEnum.New()
o:Init(buf, n + offset)
return o
end
function TestSimpleTableWithEnum_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function TestSimpleTableWithEnum_mt:Color()
local o = self.view:Offset(4)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
end
return 2
end
function TestSimpleTableWithEnum.Start(builder) builder:StartObject(1) end
function TestSimpleTableWithEnum.AddColor(builder, color) builder:PrependInt8Slot(0, color, 2) end
function TestSimpleTableWithEnum.End(builder) return builder:EndObject() end
return TestSimpleTableWithEnum -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local TypeAliases = {} -- the module
local TypeAliases_mt = {} -- the class metatable
function TypeAliases.New()
local o = {}
setmetatable(o, {__index = TypeAliases_mt})
return o
end
function TypeAliases.GetRootAsTypeAliases(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = TypeAliases.New()
o:Init(buf, n + offset)
return o
end
function TypeAliases_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function TypeAliases_mt:I8()
local o = self.view:Offset(4)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:U8()
local o = self.view:Offset(6)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:I16()
local o = self.view:Offset(8)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:U16()
local o = self.view:Offset(10)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:I32()
local o = self.view:Offset(12)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:U32()
local o = self.view:Offset(14)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:I64()
local o = self.view:Offset(16)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:U64()
local o = self.view:Offset(18)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
end
return 0
end
function TypeAliases_mt:F32()
local o = self.view:Offset(20)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
end
return 0.0
end
function TypeAliases_mt:F64()
local o = self.view:Offset(22)
if o ~= 0 then
return self.view:Get(flatbuffers.N.Float64, o + self.view.pos)
end
return 0.0
end
function TypeAliases_mt:V8(j)
local o = self.view:Offset(24)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Int8, a + ((j-1) * 1))
end
return 0
end
function TypeAliases_mt:V8Length()
local o = self.view:Offset(24)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function TypeAliases_mt:Vf64(j)
local o = self.view:Offset(26)
if o ~= 0 then
local a = self.view:Vector(o)
return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8))
end
return 0
end
function TypeAliases_mt:Vf64Length()
local o = self.view:Offset(26)
if o ~= 0 then
return self.view:VectorLen(o)
end
return 0
end
function TypeAliases.Start(builder) builder:StartObject(12) end
function TypeAliases.AddI8(builder, i8) builder:PrependInt8Slot(0, i8, 0) end
function TypeAliases.AddU8(builder, u8) builder:PrependUint8Slot(1, u8, 0) end
function TypeAliases.AddI16(builder, i16) builder:PrependInt16Slot(2, i16, 0) end
function TypeAliases.AddU16(builder, u16) builder:PrependUint16Slot(3, u16, 0) end
function TypeAliases.AddI32(builder, i32) builder:PrependInt32Slot(4, i32, 0) end
function TypeAliases.AddU32(builder, u32) builder:PrependUint32Slot(5, u32, 0) end
function TypeAliases.AddI64(builder, i64) builder:PrependInt64Slot(6, i64, 0) end
function TypeAliases.AddU64(builder, u64) builder:PrependUint64Slot(7, u64, 0) end
function TypeAliases.AddF32(builder, f32) builder:PrependFloat32Slot(8, f32, 0.0) end
function TypeAliases.AddF64(builder, f64) builder:PrependFloat64Slot(9, f64, 0.0) end
function TypeAliases.AddV8(builder, v8) builder:PrependUOffsetTRelativeSlot(10, v8, 0) end
function TypeAliases.StartV8Vector(builder, numElems) return builder:StartVector(1, numElems, 1) end
function TypeAliases.AddVf64(builder, vf64) builder:PrependUOffsetTRelativeSlot(11, vf64, 0) end
function TypeAliases.StartVf64Vector(builder, numElems) return builder:StartVector(8, numElems, 8) end
function TypeAliases.End(builder) return builder:EndObject() end
return TypeAliases -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example
local flatbuffers = require('flatbuffers')
local Vec3 = {} -- the module
local Vec3_mt = {} -- the class metatable
function Vec3.New()
local o = {}
setmetatable(o, {__index = Vec3_mt})
return o
end
function Vec3_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Vec3_mt:X()
return self.view:Get(flatbuffers.N.Float32, self.view.pos + 0)
end
function Vec3_mt:Y()
return self.view:Get(flatbuffers.N.Float32, self.view.pos + 4)
end
function Vec3_mt:Z()
return self.view:Get(flatbuffers.N.Float32, self.view.pos + 8)
end
function Vec3_mt:Test1()
return self.view:Get(flatbuffers.N.Float64, self.view.pos + 16)
end
function Vec3_mt:Test2()
return self.view:Get(flatbuffers.N.Int8, self.view.pos + 24)
end
function Vec3_mt:Test3(obj)
obj:Init(self.view.bytes, self.view.pos + 26)
return obj
end
function Vec3.CreateVec3(builder, x, y, z, test1, test2, test3_a, test3_b)
builder:Prep(16, 32)
builder:Pad(2)
builder:Prep(2, 4)
builder:Pad(1)
builder:PrependInt8(test3_b)
builder:PrependInt16(test3_a)
builder:Pad(1)
builder:PrependInt8(test2)
builder:PrependFloat64(test1)
builder:Pad(4)
builder:PrependFloat32(z)
builder:PrependFloat32(y)
builder:PrependFloat32(x)
return builder:Offset()
end
return Vec3 -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: Example2
local flatbuffers = require('flatbuffers')
local Monster = {} -- the module
local Monster_mt = {} -- the class metatable
function Monster.New()
local o = {}
setmetatable(o, {__index = Monster_mt})
return o
end
function Monster.GetRootAsMonster(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = Monster.New()
o:Init(buf, n + offset)
return o
end
function Monster_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function Monster.Start(builder) builder:StartObject(0) end
function Monster.End(builder) return builder:EndObject() end
return Monster -- return the module
\ No newline at end of file
-- automatically generated by the FlatBuffers compiler, do not modify
-- namespace: MyGame
local flatbuffers = require('flatbuffers')
local InParentNamespace = {} -- the module
local InParentNamespace_mt = {} -- the class metatable
function InParentNamespace.New()
local o = {}
setmetatable(o, {__index = InParentNamespace_mt})
return o
end
function InParentNamespace.GetRootAsInParentNamespace(buf, offset)
local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
local o = InParentNamespace.New()
o:Init(buf, n + offset)
return o
end
function InParentNamespace_mt:Init(buf, pos)
self.view = flatbuffers.view.New(buf, pos)
end
function InParentNamespace.Start(builder) builder:StartObject(0) end
function InParentNamespace.End(builder) return builder:EndObject() end
return InParentNamespace -- return the module
\ No newline at end of file
......@@ -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
......
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment