Commit 4898809e authored by aardappel's avatar aardappel

FlatBuffers implementation for the Lobster programming language

Language, see: http://strlen.com/lobster/ and https://github.com/aardappel/lobster
parent ca5aaf62
......@@ -55,6 +55,7 @@ tests/monsterdata_java_wire.mon
tests/monsterdata_java_wire_sp.mon
tests/monsterdata_go_wire.mon
tests/monsterdata_javascript_wire.mon
tests/monsterdata_lobster_wire.mon
tests/unicode_test.mon
tests/ts/
tests/php/
......
......@@ -94,6 +94,7 @@ cc_binary(
"src/idl_gen_js.cpp",
"src/idl_gen_json_schema.cpp",
"src/idl_gen_lua.cpp",
"src/idl_gen_lobster.cpp",
"src/idl_gen_php.cpp",
"src/idl_gen_python.cpp",
"src/idl_gen_text.cpp",
......
......@@ -52,6 +52,7 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_js.cpp
src/idl_gen_php.cpp
src/idl_gen_python.cpp
src/idl_gen_lobster.cpp
src/idl_gen_lua.cpp
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
......
......@@ -31,12 +31,18 @@ For any schema input files, one or more generators can be specified:
- `--js`, `-s`: Generate JavaScript code.
- `--ts`: Generate TypeScript code.
- `--php`: Generate PHP code.
- `--grpc`: Generate RPC stub code for GRPC.
- `--dart`: Generate Dart code.
- `--lua`: Generate Lua code.
- `--lobster`: Generate Lobster code.
For any data input files:
- `--binary`, `-b` : If data is contained in this file, generate a
......
......@@ -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, Lua, TypeScript, PHP, and Python.
serialization library for C++, C#, C, Go, Java, JavaScript, Lobster, Lua, TypeScript, PHP, and Python.
It was originally created at Google for game development and other
performance-critical applications.
......@@ -142,6 +142,8 @@ sections provide a more in-depth usage guide.
own programs.
- How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your
own programs.
- How to [use the generated Lobster code](@ref flatbuffers_guide_use_lobster) in your
own programs.
- [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
using FlatBuffers.
......
Use in Lobster {#flatbuffers_guide_use_lobster}
==============
## Before you get started
Before diving into the FlatBuffers usage in Lobster, 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 Lobster). This
page is designed to cover the nuances of FlatBuffers usage, specific to
Lobster.
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 Lobster library code location
The code for the FlatBuffers Lobster library can be found at
`flatbuffers/lobster`. You can browse the library code on the
[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
lobster).
## Testing the FlatBuffers Lobster library
The code to test the Lobster library can be found at `flatbuffers/tests`.
The test code itself is located in [lobstertest.lobster](https://github.com/google/
flatbuffers/blob/master/tests/lobstertest.lobster).
To run the tests, run `lobster lobstertest.lobster`. To obtain Lobster itself,
go to the [Lobster homepage](http://strlen.com/lobster) or
[github](https://github.com/aardappel/lobster) to learn how to build it for your
platform.
## Using the FlatBuffers Lobster library
*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
example of how to use FlatBuffers in Lobster.*
There is support for both reading and writing FlatBuffers in Lobster.
To use FlatBuffers in your own code, first generate Lobster classes from your
schema with the `--lobster` 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 Lobster:
First, import the library and the generated code. Then read a FlatBuffer binary
file into a string, which you pass to the `GetRootAsMonster` function:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
include "monster_generated.lobster"
let fb = read_file("monsterdata_test.mon")
assert fb
let monster = MyGame_Example_GetRootAsMonster(fb)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now you can access values like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
let hp = monster.hp
let pos = monster.pos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As you can see, even though `hp` and `pos` are functions that access FlatBuffer
data in-place in the string buffer, they appear as field accesses.
## Speed
Using FlatBuffers in Lobster should be relatively fast, as the implementation
makes use of native support for writing binary values, and access of vtables.
Both generated code and the runtime library are therefore small and fast.
Actual speed will depend on wether you use Lobster as bytecode VM or compiled to
C++.
## Text Parsing
Lobster has full support for parsing JSON into FlatBuffers, or generating
JSON from FlatBuffers. See `samples/sample_test.lobster` for an example.
This uses the C++ parser and generator underneath, so should be both fast and
conformant.
<br>
......@@ -18,25 +18,25 @@ In general:
NOTE: this table is a start, it needs to be extended.
Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Ruby | Dart
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ---- | ----
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | WiP | Yes
JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | No
Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No
Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | ? | Yes
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | ? | No
Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | ?
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | ? | Yes
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | ? | Yes
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | ? | Yes
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | ? | Flutter
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | ?
Primary authors (github) | gwvo | gwvo | ev*/js*| rw | rw | evanw/ev* | kr | mik* | ch* | rw | dnfield
Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster
------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | -------
Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes
JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes
Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No
Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No
Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great
Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes
Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes
Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes
Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes
Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes
Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No
Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard*
* aard = aardappel (previously: gwvo)
* ev = evolutional
* js = jonsimantov
* mik = mikkelfj
......
This diff is collapsed.
......@@ -759,6 +759,7 @@ INPUT = "FlatBuffers.md" \
"PHPUsage.md" \
"PythonUsage.md" \
"LuaUsage.md" \
"LobsterUsage.md" \
"Support.md" \
"Benchmarks.md" \
"WhitePaper.md" \
......
......@@ -43,6 +43,8 @@
title="Use in Dart"/>
<tab type="user" url="@ref flatbuffers_guide_use_lua"
title="Use in Lua"/>
<tab type="user" url="@ref flatbuffers_guide_use_lobster"
title="Use in Lobster"/>
<tab type="user" url="@ref flexbuffers"
title="Schema-less version"/>
<tab type="usergroup" url="" title="gRPC">
......
......@@ -409,6 +409,7 @@ struct IDLOptions {
kJsonSchema = 1 << 10,
kDart = 1 << 11,
kLua = 1 << 12,
kLobster = 1 << 13,
kMAX
};
......@@ -820,6 +821,12 @@ extern bool GeneratePython(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate Lobster files from the definitions in the Parser object.
// See idl_gen_lobster.cpp.
extern bool GenerateLobster(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,
......
// Copyright 2018 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.
include "std.lobster"
namespace flatbuffers
struct handle:
buf_:string
pos_:int
enum + sz_8 = 1,
sz_16 = 2,
sz_32 = 4,
sz_64 = 8,
sz_voffset = 2,
sz_uoffset = 4,
sz_soffset = 4,
sz_metadata_fields = 2
struct builder:
buf:string = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
current_vtable:[int] = []
head:int = 0
minalign:int = 1
object_end:int = 0
vtables:[int] = []
nested:int = false
finished:int = false
// Optionally call this right after creating the builder for a larger initial buffer.
def Initial(initial_size:int):
buf = "\x00".repeat_string(initial_size)
def Start():
// Get the start of useful data in the underlying byte buffer.
return buf.length - head
def Offset():
// Offset relative to the end of the buffer.
return head
// Returns a copy of the part of the buffer containing only the finished FlatBuffer
def SizedCopy():
assert finished
return buf.substring(Start(), -1)
def StartNesting():
assert not nested
nested = true
def EndNesting():
assert nested
nested = false
def StartObject(numfields):
StartNesting()
current_vtable = map(numfields): 0
object_end = head
minalign = 1
def EndObject():
EndNesting()
// Prepend a zero scalar to the object. Later in this function we'll
// write an offset here that points to the object's vtable:
PrependInt32(0)
object_offset := head
// Write out new vtable speculatively.
vtable_size := (current_vtable.length + sz_metadata_fields) * sz_voffset
while current_vtable.length:
o := current_vtable.pop()
PrependVOffsetT(if o: object_offset - o else: 0)
// The two metadata fields are written last.
// First, store the object bytesize:
PrependVOffsetT(object_offset - object_end)
// Second, store the vtable bytesize:
PrependVOffsetT(vtable_size)
// Search backwards through existing vtables, because similar vtables
// are likely to have been recently appended. See
// BenchmarkVtableDeduplication for a case in which this heuristic
// saves about 30% of the time used in writing objects with duplicate
// tables.
existing_vtable := do():
reverse(vtables) vt2_offset:
// Find the other vtable:
vt2_start := buf.length - vt2_offset
vt2_len := buf.read_int16_le(vt2_start)
// Compare the other vtable to the one under consideration.
// If they are equal, return the offset:
if vtable_size == vt2_len and
not compare_substring(buf, Start(), buf, vt2_start, vtable_size):
return vt2_offset from do
0
if existing_vtable:
// Found a duplicate vtable, remove the one we wrote.
head = object_offset
// Write the offset to the found vtable in the
// already-allocated offset at the beginning of this object:
buf.write_int32_le(Start(), existing_vtable - object_offset)
else:
// Did not find a vtable, so keep the one we wrote.
// Next, write the offset to the new vtable in the
// already-allocated offset at the beginning of this object:
buf.write_int32_le(buf.length - object_offset, head - object_offset)
// Finally, store this vtable in memory for future
// deduplication:
vtables.push(head)
return object_offset
def Pad(n):
for(n): buf, head = buf.write_int8_le_back(head, 0)
def Prep(size, additional_bytes):
// Track the biggest thing we've ever aligned to.
if size > minalign:
minalign = size
// Find the amount of alignment needed such that `size` is properly
// aligned after `additionalBytes`:
align_size := ((~(head + additional_bytes)) + 1) & (size - 1)
Pad(align_size)
def PrependUOffsetTRelative(off):
// Prepends an unsigned offset into vector data, relative to where it will be written.
Prep(sz_uoffset, 0)
assert off <= head
PlaceUOffsetT(head - off + sz_uoffset)
def StartVector(elem_size, num_elems, alignment):
// Initializes bookkeeping for writing a new vector.
StartNesting()
Prep(sz_32, elem_size * num_elems)
Prep(alignment, elem_size * num_elems) // In case alignment > int.
return head
def EndVector(vector_num_elems):
EndNesting()
// we already made space for this, so write without PrependUint32
PlaceUOffsetT(vector_num_elems)
return head
def CreateString(s:string):
// writes a null-terminated byte string.
StartNesting()
Prep(sz_32, s.length + 1)
buf, head = buf.write_substring_back(head, s, true)
return EndVector(s.length)
def CreateByteVector(s:string):
// writes a non-null-terminated byte string.
StartNesting()
Prep(sz_32, s.length)
buf, head = buf.write_substring_back(head, s, false)
return EndVector(s.length)
def Slot(slotnum):
assert nested
while current_vtable.length <= slotnum: current_vtable.push(0)
current_vtable[slotnum] = head
def __Finish(root_table:int, size_prefix:int):
// Finish finalizes a buffer, pointing to the given root_table
assert not finished
assert not nested
prep_size := sz_32
if size_prefix:
prep_size += sz_32
Prep(minalign, prep_size)
PrependUOffsetTRelative(root_table)
if size_prefix:
PrependInt32(head)
finished = true
return Start()
def Finish(root_table:int):
return __Finish(root_table, false)
def FinishSizePrefixed(root_table:int):
return __Finish(root_table, true)
def PrependBool(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependByte(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependUint8(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependUint16(x):
Prep(sz_16, 0)
buf, head = buf.write_int16_le_back(head, x)
def PrependUint32(x):
Prep(sz_32, 0)
buf, head = buf.write_int32_le_back(head, x)
def PrependUint64(x):
Prep(sz_64, 0)
buf, head = buf.write_int64_le_back(head, x)
def PrependInt8(x):
buf, head = buf.write_int8_le_back(head, x)
def PrependInt16(x):
Prep(sz_16, 0)
buf, head = buf.write_int16_le_back(head, x)
def PrependInt32(x):
Prep(sz_32, 0)
buf, head = buf.write_int32_le_back(head, x)
def PrependInt64(x):
Prep(sz_64, 0)
buf, head = buf.write_int64_le_back(head, x)
def PrependFloat32(x):
Prep(sz_32, 0)
buf, head = buf.write_float32_le_back(head, x)
def PrependFloat64(x):
Prep(sz_64, 0)
buf, head = buf.write_float64_le_back(head, x)
def PrependVOffsetT(x):
Prep(sz_voffset, 0)
buf, head = buf.write_int16_le_back(head, x)
def PlaceVOffsetT(x):
buf, head = buf.write_int16_le_back(head, x)
def PlaceSOffsetT(x):
buf, head = buf.write_int32_le_back(head, x)
def PlaceUOffsetT(x):
buf, head = buf.write_int32_le_back(head, x)
def PrependSlot(o:int, x, d, f):
if x != d:
f(x)
Slot(o)
def PrependBoolSlot(o, x, d): PrependSlot(o, x, d): PrependBool(_)
def PrependByteSlot(o, x, d): PrependSlot(o, x, d): PrependByte(_)
def PrependUint8Slot(o, x, d): PrependSlot(o, x, d): PrependUint8(_)
def PrependUint16Slot(o, x, d): PrependSlot(o, x, d): PrependUint16(_)
def PrependUint32Slot(o, x, d): PrependSlot(o, x, d): PrependUint32(_)
def PrependUint64Slot(o, x, d): PrependSlot(o, x, d): PrependUint64(_)
def PrependInt8Slot(o, x, d): PrependSlot(o, x, d): PrependInt8(_)
def PrependInt16Slot(o, x, d): PrependSlot(o, x, d): PrependInt16(_)
def PrependInt32Slot(o, x, d): PrependSlot(o, x, d): PrependInt32(_)
def PrependInt64Slot(o, x, d): PrependSlot(o, x, d): PrependInt64(_)
def PrependFloat32Slot(o, x, d): PrependSlot(o, x, d): PrependFloat32(_)
def PrependFloat64Slot(o, x, d): PrependSlot(o, x, d): PrependFloat64(_)
def PrependUOffsetTRelativeSlot(o, x, d):
if x != d:
PrependUOffsetTRelative(x)
Slot(o)
def PrependStructSlot(v, x, d):
if x != d:
// Structs are always stored inline, so need to be created right
// where they are used. You'll get this error if you created it
//elsewhere.
assert x == head
Slot(v)
// automatically generated by the FlatBuffers compiler, do not modify
include "flatbuffers.lobster"
namespace MyGame_Sample
enum +
Color_Red = 0,
Color_Green = 1,
Color_Blue = 2
enum +
Equipment_NONE = 0,
Equipment_Weapon = 1
struct Vec3
struct Monster
struct Weapon
struct Vec3 : flatbuffers_handle
def x():
buf_.read_float32_le(pos_ + 0)
def y():
buf_.read_float32_le(pos_ + 4)
def z():
buf_.read_float32_le(pos_ + 8)
def CreateVec3(b_:flatbuffers_builder, x:float, y:float, z:float):
b_.Prep(4, 12)
b_.PrependFloat32(z)
b_.PrependFloat32(y)
b_.PrependFloat32(x)
return b_.Offset()
struct Monster : flatbuffers_handle
def pos():
o := buf_.flatbuffers_field_struct(pos_, 4)
if o: MyGame_Sample_Vec3 { buf_, o } else: nil
def mana():
buf_.flatbuffers_field_int16(pos_, 6, 150)
def hp():
buf_.flatbuffers_field_int16(pos_, 8, 100)
def name():
buf_.flatbuffers_field_string(pos_, 10)
def inventory(i:int):
buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 14) + i * 1)
def inventory_length():
buf_.flatbuffers_field_vector_len(pos_, 14)
def color():
buf_.flatbuffers_field_int8(pos_, 16, 2)
def weapons(i:int):
MyGame_Sample_Weapon { buf_, buf_.flatbuffers_indirect(buf_.flatbuffers_field_vector(pos_, 18) + i * 4) }
def weapons_length():
buf_.flatbuffers_field_vector_len(pos_, 18)
def equipped_type():
buf_.flatbuffers_field_int8(pos_, 20, 0)
def equipped_as_Weapon():
MyGame_Sample_Weapon { buf_, buf_.flatbuffers_field_table(pos_, 22) }
def GetRootAsMonster(buf:string): Monster { buf, buf.flatbuffers_indirect(0) }
def MonsterStart(b_:flatbuffers_builder):
b_.StartObject(10)
def MonsterAddPos(b_:flatbuffers_builder, pos:int):
b_.PrependStructSlot(0, pos, 0)
def MonsterAddMana(b_:flatbuffers_builder, mana:int):
b_.PrependInt16Slot(1, mana, 150)
def MonsterAddHp(b_:flatbuffers_builder, hp:int):
b_.PrependInt16Slot(2, hp, 100)
def MonsterAddName(b_:flatbuffers_builder, name:int):
b_.PrependUOffsetTRelativeSlot(3, name, 0)
def MonsterAddInventory(b_:flatbuffers_builder, inventory:int):
b_.PrependUOffsetTRelativeSlot(5, inventory, 0)
def MonsterStartInventoryVector(b_:flatbuffers_builder, n_:int):
b_.StartVector(1, n_, 1)
def MonsterCreateInventoryVector(b_:flatbuffers_builder, v_:[int]):
b_.StartVector(1, v_.length, 1)
reverse(v_) e_: b_.PrependUint8(e_)
b_.EndVector(v_.length)
def MonsterAddColor(b_:flatbuffers_builder, color:int):
b_.PrependInt8Slot(6, color, 2)
def MonsterAddWeapons(b_:flatbuffers_builder, weapons:int):
b_.PrependUOffsetTRelativeSlot(7, weapons, 0)
def MonsterStartWeaponsVector(b_:flatbuffers_builder, n_:int):
b_.StartVector(4, n_, 4)
def MonsterCreateWeaponsVector(b_:flatbuffers_builder, v_:[int]):
b_.StartVector(4, v_.length, 4)
reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
b_.EndVector(v_.length)
def MonsterAddEquippedType(b_:flatbuffers_builder, equipped_type:int):
b_.PrependUint8Slot(8, equipped_type, 0)
def MonsterAddEquipped(b_:flatbuffers_builder, equipped:int):
b_.PrependUOffsetTRelativeSlot(9, equipped, 0)
def MonsterEnd(b_:flatbuffers_builder):
b_.EndObject()
struct Weapon : flatbuffers_handle
def name():
buf_.flatbuffers_field_string(pos_, 4)
def damage():
buf_.flatbuffers_field_int16(pos_, 6, 0)
def GetRootAsWeapon(buf:string): Weapon { buf, buf.flatbuffers_indirect(0) }
def WeaponStart(b_:flatbuffers_builder):
b_.StartObject(2)
def WeaponAddName(b_:flatbuffers_builder, name:int):
b_.PrependUOffsetTRelativeSlot(0, name, 0)
def WeaponAddDamage(b_:flatbuffers_builder, damage:int):
b_.PrependInt16Slot(1, damage, 0)
def WeaponEnd(b_:flatbuffers_builder):
b_.EndObject()
{
pos: {
x: 1,
y: 2,
z: 3
x: 1.0,
y: 2.0,
z: 3.0
},
hp: 300,
name: "Orc",
weapons:[
weapons: [
{
name: "axe",
damage:100
damage: 100
},
{
name: "bow",
damage:90
damage: 90
}
],
equipped_type: "Weapon",
equipped:
{
name: "bow",
damage:90
}
equipped: {
name: "bow",
damage: 90
}
}
// Copyright 2018 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.
include from "../lobster/"
include "monster_generated.lobster"
// Example of how to use FlatBuffers to create and read binary buffers.
// Create a builder.
let b = flatbuffers_builder {}
// Create some weapons for our monster.
let weapon_names = [ "Sword", "Axe" ]
let weapon_damages = [ 3, 5 ]
weapon_offsets := map(weapon_names) name, i:
let ns = b.CreateString(name)
b.MyGame_Sample_WeaponStart()
b.MyGame_Sample_WeaponAddName(ns)
b.MyGame_Sample_WeaponAddDamage(weapon_damages[i])
b.MyGame_Sample_WeaponEnd()
let weapons = b.MyGame_Sample_MonsterCreateWeaponsVector(weapon_offsets)
// Name of the monster.
let name = b.CreateString("Orc")
// Inventory.
let inv = b.MyGame_Sample_MonsterCreateInventoryVector(map(10): _)
// Now pack it all together in our root monster object.
b.MyGame_Sample_MonsterStart()
b.MyGame_Sample_MonsterAddPos(b.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0))
b.MyGame_Sample_MonsterAddHp(300)
b.MyGame_Sample_MonsterAddName(name)
b.MyGame_Sample_MonsterAddInventory(inv)
b.MyGame_Sample_MonsterAddColor(MyGame_Sample_Color_Red)
b.MyGame_Sample_MonsterAddWeapons(weapons)
b.MyGame_Sample_MonsterAddEquippedType(MyGame_Sample_Equipment_Weapon)
b.MyGame_Sample_MonsterAddEquipped(weapon_offsets[1])
let orc = b.MyGame_Sample_MonsterEnd()
// Finish the buffer!
b.Finish(orc)
// We now have a FlatBuffer that we could store on disk or send over a network.
let buf = b.SizedCopy()
// ...Saving to file or sending over a network code goes here...
// Instead, we are going to access this buffer right away (as if we just
// received it).
// Get the root object accessor.
let monster = MyGame_Sample_GetRootAsMonster(buf)
// Note: We did not set the `mana` field explicitly, so we get a default value.
assert monster.mana == 150
assert monster.hp == 300
assert monster.name == "Orc"
assert monster.color == MyGame_Sample_Color_Red
let pos = monster.pos
assert pos
assert pos.x == 1.0
assert pos.y == 2.0
assert pos.z == 3.0
// Get and test the `inventory` FlatBuffer vector.
for(monster.inventory_length) e, i:
assert monster.inventory(i) == e
// Get and test the `weapons` FlatBuffer vector of tables.
for(monster.weapons_length) i:
assert monster.weapons(i).name == weapon_names[i]
assert monster.weapons(i).damage == weapon_damages[i]
// Get and test the `equipped` FlatBuffer union.
assert monster.equipped_type() == MyGame_Sample_Equipment_Weapon
// Now that we know the union value is a weapon, we can safely call as_Weapon:
let union_weapon = monster.equipped_as_Weapon
assert union_weapon.name == "Axe"
assert union_weapon.damage == 5
print "The FlatBuffer was successfully created and verified!"
// Copyright 2018 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.
include from "../lobster/"
include "monster_generated.lobster"
// Example how to interop with JSON.
// Test loading some JSON, converting it to a binary FlatBuffer and back again.
// First read the schema and JSON data.
schema := read_file("monster.fbs", true)
json := read_file("monsterdata.json", true)
assert schema and json
// Parse JSON to binary:
fb, err1 := flatbuffers_json_to_binary(schema, json, [])
assert not err1
// Access one field in it, just to check:
let monster = MyGame_Sample_GetRootAsMonster(fb)
assert monster.name == "Orc"
// Convert binary back to JSON:
json2, err2 := flatbuffers_binary_to_json(schema, fb, [])
assert not err2
// The generated JSON should be exactly equal to the original!
assert json == json2
// Print what we've been converting for good measure:
print json
......@@ -71,6 +71,10 @@ int main(int argc, const char *argv[]) {
flatbuffers::IDLOptions::kPython,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true, nullptr,
flatbuffers::IDLOptions::kLobster,
"Generate Lobster files for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
flatbuffers::IDLOptions::kLua,
"Generate Lua files for tables/structs",
......
This diff is collapsed.
......@@ -40,6 +40,11 @@ echo "************************ Dart:"
sh DartTest.sh
echo "************************ Lobster:"
# TODO: test if available.
# lobster lobstertest.lobster
echo "************************ C:"
echo "(in a different repo)"
......
......@@ -15,13 +15,13 @@
set buildtype=Release
if "%1"=="-b" set buildtype=%2
..\%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 --java --csharp --go --binary --python --lobster --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 --lobster --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
cd ../samples
..\%buildtype%\flatc.exe --cpp --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
..\%buildtype%\flatc.exe --cpp --lobster --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
cd ../reflection
cd ../tests
\ No newline at end of file
......@@ -14,11 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
../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 --java --csharp --dart --go --binary --lobster --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 --lobster --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
cd ../samples
../flatc --cpp --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
../flatc --cpp --lobster --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
cd ../reflection
// Copyright 2018 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.
include from "../lobster/"
include "monster_test_generated.lobster"
def check_read_buffer(buf):
// CheckReadBuffer checks that the given buffer is evaluated correctly as the example Monster.
let monster = MyGame_Example_GetRootAsMonster(buf)
assert monster.hp == 80
assert monster.mana == 150
assert monster.name == "MyMonster"
let vec = monster.pos
assert vec
assert vec.x == 1.0
assert vec.y == 2.0
assert vec.z == 3.0
assert vec.test1 == 3.0
assert vec.test2 == 2
let t = vec.test3
assert t
assert t.a == 5
assert t.b == 6
assert monster.test_type == MyGame_Example_Any_Monster
assert monster.test_as_Monster.name == "Fred"
assert monster.inventory_length == 5
assert sum(map(monster.inventory_length) i: monster.inventory(i)) == 10
for(5) i:
assert monster.vector_of_longs(i) == pow(10, i * 2)
assert equal([-1.7976931348623157e+308, 0, 1.7976931348623157e+308],
(map(monster.vector_of_doubles_length) i: monster.vector_of_doubles(i)))
assert monster.test4_length == 2
let test0 = monster.test4(0)
let test1 = monster.test4(1)
assert test0.a + test0.b + test1.a + test1.b == 100
assert monster.testarrayofstring_length == 2
assert monster.testarrayofstring(0) == "test1"
assert monster.testarrayofstring(1) == "test2"
assert monster.testarrayoftables_length == 0
assert monster.testnestedflatbuffer_length == 0
assert not monster.testempty()
def make_monster_from_generated_code():
// Use generated code to build the example Monster.
let b = flatbuffers_builder {}
let name = b.CreateString("MyMonster")
let fred = b.CreateString("Fred")
let inv = b.MyGame_Example_MonsterCreateInventoryVector([ 0, 1, 2, 3, 4 ])
b.MyGame_Example_MonsterStart()
b.MyGame_Example_MonsterAddName(fred)
let mon2 = b.MyGame_Example_MonsterEnd()
b.MyGame_Example_MonsterStartTest4Vector(2)
b.MyGame_Example_CreateTest(10, 20)
b.MyGame_Example_CreateTest(30, 40)
let test4 = b.EndVector(2)
let test_array_of_string = b.MyGame_Example_MonsterCreateTestarrayofstringVector(
[ b.CreateString("test1"), b.CreateString("test2") ])
let vector_of_longs = b.MyGame_Example_MonsterCreateVectorOfLongsVector(
[ 1, 100, 10000, 1000000, 100000000 ])
let vector_of_doubles = b.MyGame_Example_MonsterCreateVectorOfDoublesVector(
[ -1.7976931348623157e+308, 0, 1.7976931348623157e+308 ])
b.MyGame_Example_MonsterStart()
b.MyGame_Example_MonsterAddPos(b.MyGame_Example_CreateVec3(1.0, 2.0, 3.0, 3.0, 2, 5, 6))
b.MyGame_Example_MonsterAddHp(80)
b.MyGame_Example_MonsterAddName(name)
b.MyGame_Example_MonsterAddInventory(inv)
b.MyGame_Example_MonsterAddTestType(MyGame_Example_Any_Monster)
b.MyGame_Example_MonsterAddTest(mon2)
b.MyGame_Example_MonsterAddTest4(test4)
b.MyGame_Example_MonsterAddTestarrayofstring(test_array_of_string)
b.MyGame_Example_MonsterAddVectorOfLongs(vector_of_longs)
b.MyGame_Example_MonsterAddVectorOfDoubles(vector_of_doubles)
let mon = b.MyGame_Example_MonsterEnd()
b.Finish(mon)
return b.SizedCopy()
// Verify that the canonical flatbuffer file (produced by the C++ implementation)
// is readable by the generated Lobster code.
let fb2 = read_file("monsterdata_test.mon")
assert fb2
check_read_buffer(fb2)
// Verify that using the generated Lobster code builds a buffer without
// returning errors, and is interpreted correctly.
let fb1 = make_monster_from_generated_code()
check_read_buffer(fb1)
// Write the result to file for no good reason.
write_file("monsterdata_lobster_wire.mon", fb1)
// Test converting the buffer to JSON and parsing the JSON back again.
schema := read_file("monster_test.fbs")
assert schema
includedirs := [ "include_test" ]
// Convert binary to JSON:
json, err1 := flatbuffers_binary_to_json(schema, fb1, includedirs)
assert not err1
// Parse JSON back to binary:
fb3, err2 := flatbuffers_json_to_binary(schema, json, includedirs)
assert not err2
// Check the resulting binary again (full roundtrip test):
check_read_buffer(fb3)
print "Lobster test succesful!"
\ No newline at end of file
This diff is collapsed.
// automatically generated by the FlatBuffers compiler, do not modify
include "flatbuffers.lobster"
namespace NamespaceA_NamespaceB
enum +
EnumInNestedNS_A = 0,
EnumInNestedNS_B = 1,
EnumInNestedNS_C = 2
struct TableInNestedNS
struct StructInNestedNS
struct TableInNestedNS : flatbuffers_handle
def foo():
buf_.flatbuffers_field_int32(pos_, 4, 0)
def GetRootAsTableInNestedNS(buf:string): TableInNestedNS { buf, buf.flatbuffers_indirect(0) }
def TableInNestedNSStart(b_:flatbuffers_builder):
b_.StartObject(1)
def TableInNestedNSAddFoo(b_:flatbuffers_builder, foo:int):
b_.PrependInt32Slot(0, foo, 0)
def TableInNestedNSEnd(b_:flatbuffers_builder):
b_.EndObject()
struct StructInNestedNS : flatbuffers_handle
def a():
buf_.read_int32_le(pos_ + 0)
def b():
buf_.read_int32_le(pos_ + 4)
def CreateStructInNestedNS(b_:flatbuffers_builder, a:int, b:int):
b_.Prep(4, 8)
b_.PrependInt32(b)
b_.PrependInt32(a)
return b_.Offset()
// automatically generated by the FlatBuffers compiler, do not modify
include "flatbuffers.lobster"
namespace NamespaceA
struct TableInFirstNS
namespace NamespaceC
struct TableInC
namespace NamespaceA
struct SecondTableInA
struct TableInFirstNS : flatbuffers_handle
def foo_table():
o := buf_.flatbuffers_field_table(pos_, 4)
if o: NamespaceA_NamespaceB_TableInNestedNS { buf_, o } else: nil
def foo_enum():
buf_.flatbuffers_field_int8(pos_, 6, 0)
def foo_struct():
o := buf_.flatbuffers_field_struct(pos_, 8)
if o: NamespaceA_NamespaceB_StructInNestedNS { buf_, o } else: nil
def GetRootAsTableInFirstNS(buf:string): TableInFirstNS { buf, buf.flatbuffers_indirect(0) }
def TableInFirstNSStart(b_:flatbuffers_builder):
b_.StartObject(3)
def TableInFirstNSAddFooTable(b_:flatbuffers_builder, foo_table:int):
b_.PrependUOffsetTRelativeSlot(0, foo_table, 0)
def TableInFirstNSAddFooEnum(b_:flatbuffers_builder, foo_enum:int):
b_.PrependInt8Slot(1, foo_enum, 0)
def TableInFirstNSAddFooStruct(b_:flatbuffers_builder, foo_struct:int):
b_.PrependStructSlot(2, foo_struct, 0)
def TableInFirstNSEnd(b_:flatbuffers_builder):
b_.EndObject()
namespace NamespaceC
struct TableInC : flatbuffers_handle
def refer_to_a1():
o := buf_.flatbuffers_field_table(pos_, 4)
if o: NamespaceA_TableInFirstNS { buf_, o } else: nil
def refer_to_a2():
o := buf_.flatbuffers_field_table(pos_, 6)
if o: NamespaceA_SecondTableInA { buf_, o } else: nil
def GetRootAsTableInC(buf:string): TableInC { buf, buf.flatbuffers_indirect(0) }
def TableInCStart(b_:flatbuffers_builder):
b_.StartObject(2)
def TableInCAddReferToA1(b_:flatbuffers_builder, refer_to_a1:int):
b_.PrependUOffsetTRelativeSlot(0, refer_to_a1, 0)
def TableInCAddReferToA2(b_:flatbuffers_builder, refer_to_a2:int):
b_.PrependUOffsetTRelativeSlot(1, refer_to_a2, 0)
def TableInCEnd(b_:flatbuffers_builder):
b_.EndObject()
namespace NamespaceA
struct SecondTableInA : flatbuffers_handle
def refer_to_c():
o := buf_.flatbuffers_field_table(pos_, 4)
if o: NamespaceC_TableInC { buf_, o } else: nil
def GetRootAsSecondTableInA(buf:string): SecondTableInA { buf, buf.flatbuffers_indirect(0) }
def SecondTableInAStart(b_:flatbuffers_builder):
b_.StartObject(1)
def SecondTableInAAddReferToC(b_:flatbuffers_builder, refer_to_c:int):
b_.PrependUOffsetTRelativeSlot(0, refer_to_c, 0)
def SecondTableInAEnd(b_:flatbuffers_builder):
b_.EndObject()
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