Commit 32254b7a authored by iceboy's avatar iceboy Committed by Wouter van Oortmerssen

[Go] Object API support (#5339)

* start

* works for current usages!

* unpack: vector of struct

* optimize byte slice

* support nested struct

* support null table

* support struct

* support union

* update generated code

* grumble

* fix compiler warning

* update generated code

* wrap type in namespace

* bug

* wrap in namespace

* enum byte arrays

* generate struct for unions

* basic testing

* remove branching

* fix assert

* pack vector of fixed structs correctly

* omit null vectors

* Refactor Union Pack and UnPack methods

Remove append usage to increase code efficiency when dealing with large vectors

* generate goldens
parent 521e255a
This diff is collapsed.
......@@ -20,7 +20,7 @@ go_path=${test_dir}/go_gen
go_src=${go_path}/src
# Emit Go code for the example schema in the test dir:
../flatc -g -I include_test monster_test.fbs
../flatc -g --gen-object-api -I include_test monster_test.fbs
# Go requires a particular layout of files in order to link multiple packages.
# Copy flatbuffer Go files to their own package directories to compile the
......
......@@ -6,6 +6,23 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type AbilityT struct {
Id uint32
Distance uint32
}
func AbilityPack(builder *flatbuffers.Builder, t *AbilityT) flatbuffers.UOffsetT {
if t == nil { return 0 }
return CreateAbility(builder, t.Id, t.Distance)
}
func (rcv *Ability) UnPack() *AbilityT {
if rcv == nil { return nil }
t := &AbilityT{}
t.Id = rcv.Id()
t.Distance = rcv.Distance()
return t
}
type Ability struct {
_tab flatbuffers.Struct
}
......
......@@ -2,7 +2,48 @@
package Example
import "strconv"
import (
"strconv"
flatbuffers "github.com/google/flatbuffers/go"
MyGame__Example2 "MyGame/Example2"
)
type AnyT struct {
Type Any
Value interface{}
}
func AnyPack(builder *flatbuffers.Builder, t *AnyT) flatbuffers.UOffsetT {
if t == nil {
return 0
}
switch t.Type {
case AnyMonster:
return MonsterPack(builder, t.Value.(*MonsterT))
case AnyTestSimpleTableWithEnum:
return TestSimpleTableWithEnumPack(builder, t.Value.(*TestSimpleTableWithEnumT))
case AnyMyGame_Example2_Monster:
return MyGame__Example2.MonsterPack(builder, t.Value.(*MyGame__Example2.MonsterT))
}
return 0
}
func AnyUnPack(t Any, table flatbuffers.Table) *AnyT {
switch t {
case AnyMonster:
x := Monster{_tab: table}
return &AnyT{ Type: AnyMonster, Value: x.UnPack() }
case AnyTestSimpleTableWithEnum:
x := TestSimpleTableWithEnum{_tab: table}
return &AnyT{ Type: AnyTestSimpleTableWithEnum, Value: x.UnPack() }
case AnyMyGame_Example2_Monster:
x := Monster{_tab: table}
return &AnyT{ Type: AnyMyGame_Example2_Monster, Value: x.UnPack() }
}
return nil
}
type Any byte
......
......@@ -2,7 +2,46 @@
package Example
import "strconv"
import (
"strconv"
flatbuffers "github.com/google/flatbuffers/go"
)
type AnyAmbiguousAliasesT struct {
Type AnyAmbiguousAliases
Value interface{}
}
func AnyAmbiguousAliasesPack(builder *flatbuffers.Builder, t *AnyAmbiguousAliasesT) flatbuffers.UOffsetT {
if t == nil {
return 0
}
switch t.Type {
case AnyAmbiguousAliasesM1:
return MonsterPack(builder, t.Value.(*MonsterT))
case AnyAmbiguousAliasesM2:
return MonsterPack(builder, t.Value.(*MonsterT))
case AnyAmbiguousAliasesM3:
return MonsterPack(builder, t.Value.(*MonsterT))
}
return 0
}
func AnyAmbiguousAliasesUnPack(t AnyAmbiguousAliases, table flatbuffers.Table) *AnyAmbiguousAliasesT {
switch t {
case AnyAmbiguousAliasesM1:
x := Monster{_tab: table}
return &AnyAmbiguousAliasesT{ Type: AnyAmbiguousAliasesM1, Value: x.UnPack() }
case AnyAmbiguousAliasesM2:
x := Monster{_tab: table}
return &AnyAmbiguousAliasesT{ Type: AnyAmbiguousAliasesM2, Value: x.UnPack() }
case AnyAmbiguousAliasesM3:
x := Monster{_tab: table}
return &AnyAmbiguousAliasesT{ Type: AnyAmbiguousAliasesM3, Value: x.UnPack() }
}
return nil
}
type AnyAmbiguousAliases byte
......
......@@ -2,7 +2,48 @@
package Example
import "strconv"
import (
"strconv"
flatbuffers "github.com/google/flatbuffers/go"
MyGame__Example2 "MyGame/Example2"
)
type AnyUniqueAliasesT struct {
Type AnyUniqueAliases
Value interface{}
}
func AnyUniqueAliasesPack(builder *flatbuffers.Builder, t *AnyUniqueAliasesT) flatbuffers.UOffsetT {
if t == nil {
return 0
}
switch t.Type {
case AnyUniqueAliasesM:
return MonsterPack(builder, t.Value.(*MonsterT))
case AnyUniqueAliasesTS:
return TestSimpleTableWithEnumPack(builder, t.Value.(*TestSimpleTableWithEnumT))
case AnyUniqueAliasesM2:
return MyGame__Example2.MonsterPack(builder, t.Value.(*MyGame__Example2.MonsterT))
}
return 0
}
func AnyUniqueAliasesUnPack(t AnyUniqueAliases, table flatbuffers.Table) *AnyUniqueAliasesT {
switch t {
case AnyUniqueAliasesM:
x := Monster{_tab: table}
return &AnyUniqueAliasesT{ Type: AnyUniqueAliasesM, Value: x.UnPack() }
case AnyUniqueAliasesTS:
x := TestSimpleTableWithEnum{_tab: table}
return &AnyUniqueAliasesT{ Type: AnyUniqueAliasesTS, Value: x.UnPack() }
case AnyUniqueAliasesM2:
x := Monster{_tab: table}
return &AnyUniqueAliasesT{ Type: AnyUniqueAliasesM2, Value: x.UnPack() }
}
return nil
}
type AnyUniqueAliases byte
......
This diff is collapsed.
......@@ -6,6 +6,24 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type ReferrableT struct {
Id uint64
}
func ReferrablePack(builder *flatbuffers.Builder, t *ReferrableT) flatbuffers.UOffsetT {
if t == nil { return 0 }
ReferrableStart(builder)
ReferrableAddId(builder, t.Id)
return ReferrableEnd(builder)
}
func (rcv *Referrable) UnPack() *ReferrableT {
if rcv == nil { return nil }
t := &ReferrableT{}
t.Id = rcv.Id()
return t
}
type Referrable struct {
_tab flatbuffers.Table
}
......
......@@ -6,6 +6,31 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type StatT struct {
Id string
Val int64
Count uint16
}
func StatPack(builder *flatbuffers.Builder, t *StatT) flatbuffers.UOffsetT {
if t == nil { return 0 }
idOffset := builder.CreateString(t.Id)
StatStart(builder)
StatAddId(builder, idOffset)
StatAddVal(builder, t.Val)
StatAddCount(builder, t.Count)
return StatEnd(builder)
}
func (rcv *Stat) UnPack() *StatT {
if rcv == nil { return nil }
t := &StatT{}
t.Id = string(rcv.Id())
t.Val = rcv.Val()
t.Count = rcv.Count()
return t
}
type Stat struct {
_tab flatbuffers.Table
}
......
......@@ -6,6 +6,23 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type TestT struct {
A int16
B int8
}
func TestPack(builder *flatbuffers.Builder, t *TestT) flatbuffers.UOffsetT {
if t == nil { return 0 }
return CreateTest(builder, t.A, t.B)
}
func (rcv *Test) UnPack() *TestT {
if rcv == nil { return nil }
t := &TestT{}
t.A = rcv.A()
t.B = rcv.B()
return t
}
type Test struct {
_tab flatbuffers.Struct
}
......
......@@ -6,6 +6,24 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type TestSimpleTableWithEnumT struct {
Color Color
}
func TestSimpleTableWithEnumPack(builder *flatbuffers.Builder, t *TestSimpleTableWithEnumT) flatbuffers.UOffsetT {
if t == nil { return 0 }
TestSimpleTableWithEnumStart(builder)
TestSimpleTableWithEnumAddColor(builder, t.Color)
return TestSimpleTableWithEnumEnd(builder)
}
func (rcv *TestSimpleTableWithEnum) UnPack() *TestSimpleTableWithEnumT {
if rcv == nil { return nil }
t := &TestSimpleTableWithEnumT{}
t.Color = rcv.Color()
return t
}
type TestSimpleTableWithEnum struct {
_tab flatbuffers.Table
}
......
......@@ -6,6 +6,83 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type TypeAliasesT struct {
I8 int8
U8 byte
I16 int16
U16 uint16
I32 int32
U32 uint32
I64 int64
U64 uint64
F32 float32
F64 float64
V8 []int8
Vf64 []float64
}
func TypeAliasesPack(builder *flatbuffers.Builder, t *TypeAliasesT) flatbuffers.UOffsetT {
if t == nil { return 0 }
v8Offset := flatbuffers.UOffsetT(0)
if t.V8 != nil {
v8Length := len(t.V8)
TypeAliasesStartV8Vector(builder, v8Length)
for j := v8Length - 1; j >= 0; j-- {
builder.PrependInt8(t.V8[j])
}
v8Offset = builder.EndVector(v8Length)
}
vf64Offset := flatbuffers.UOffsetT(0)
if t.Vf64 != nil {
vf64Length := len(t.Vf64)
TypeAliasesStartVf64Vector(builder, vf64Length)
for j := vf64Length - 1; j >= 0; j-- {
builder.PrependFloat64(t.Vf64[j])
}
vf64Offset = builder.EndVector(vf64Length)
}
TypeAliasesStart(builder)
TypeAliasesAddI8(builder, t.I8)
TypeAliasesAddU8(builder, t.U8)
TypeAliasesAddI16(builder, t.I16)
TypeAliasesAddU16(builder, t.U16)
TypeAliasesAddI32(builder, t.I32)
TypeAliasesAddU32(builder, t.U32)
TypeAliasesAddI64(builder, t.I64)
TypeAliasesAddU64(builder, t.U64)
TypeAliasesAddF32(builder, t.F32)
TypeAliasesAddF64(builder, t.F64)
TypeAliasesAddV8(builder, v8Offset)
TypeAliasesAddVf64(builder, vf64Offset)
return TypeAliasesEnd(builder)
}
func (rcv *TypeAliases) UnPack() *TypeAliasesT {
if rcv == nil { return nil }
t := &TypeAliasesT{}
t.I8 = rcv.I8()
t.U8 = rcv.U8()
t.I16 = rcv.I16()
t.U16 = rcv.U16()
t.I32 = rcv.I32()
t.U32 = rcv.U32()
t.I64 = rcv.I64()
t.U64 = rcv.U64()
t.F32 = rcv.F32()
t.F64 = rcv.F64()
v8Length := rcv.V8Length()
t.V8 = make([]int8, v8Length)
for j := 0; j < v8Length; j++ {
t.V8[j] = rcv.V8(j)
}
vf64Length := rcv.Vf64Length()
t.Vf64 = make([]float64, vf64Length)
for j := 0; j < vf64Length; j++ {
t.Vf64[j] = rcv.Vf64(j)
}
return t
}
type TypeAliases struct {
_tab flatbuffers.Table
}
......
......@@ -6,6 +6,31 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type Vec3T struct {
X float32
Y float32
Z float32
Test1 float64
Test2 Color
Test3 *TestT
}
func Vec3Pack(builder *flatbuffers.Builder, t *Vec3T) flatbuffers.UOffsetT {
if t == nil { return 0 }
return CreateVec3(builder, t.X, t.Y, t.Z, t.Test1, t.Test2, t.Test3.A, t.Test3.B)
}
func (rcv *Vec3) UnPack() *Vec3T {
if rcv == nil { return nil }
t := &Vec3T{}
t.X = rcv.X()
t.Y = rcv.Y()
t.Z = rcv.Z()
t.Test1 = rcv.Test1()
t.Test2 = rcv.Test2()
t.Test3 = rcv.Test3(nil).UnPack()
return t
}
type Vec3 struct {
_tab flatbuffers.Struct
}
......
......@@ -6,6 +6,21 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type MonsterT struct {
}
func MonsterPack(builder *flatbuffers.Builder, t *MonsterT) flatbuffers.UOffsetT {
if t == nil { return 0 }
MonsterStart(builder)
return MonsterEnd(builder)
}
func (rcv *Monster) UnPack() *MonsterT {
if rcv == nil { return nil }
t := &MonsterT{}
return t
}
type Monster struct {
_tab flatbuffers.Table
}
......
......@@ -6,6 +6,21 @@ import (
flatbuffers "github.com/google/flatbuffers/go"
)
type InParentNamespaceT struct {
}
func InParentNamespacePack(builder *flatbuffers.Builder, t *InParentNamespaceT) flatbuffers.UOffsetT {
if t == nil { return 0 }
InParentNamespaceStart(builder)
return InParentNamespaceEnd(builder)
}
func (rcv *InParentNamespace) UnPack() *InParentNamespaceT {
if rcv == nil { return nil }
t := &InParentNamespaceT{}
return t
}
type InParentNamespace struct {
_tab flatbuffers.Table
}
......
......@@ -90,6 +90,7 @@ func TestAll(t *testing.T) {
// generated Go code:
CheckReadBuffer(generated, off, t.Fatalf)
CheckMutateBuffer(generated, off, t.Fatalf)
CheckObjectAPI(generated, off, t.Fatalf)
// Verify that the buffer generated by C++ code is readable by the
// generated Go code:
......@@ -99,6 +100,7 @@ func TestAll(t *testing.T) {
}
CheckReadBuffer(monsterDataCpp, 0, t.Fatalf)
CheckMutateBuffer(monsterDataCpp, 0, t.Fatalf)
CheckObjectAPI(monsterDataCpp, 0, t.Fatalf)
// Verify that vtables are deduplicated when written:
CheckVtableDeduplication(t.Fatalf)
......@@ -448,6 +450,26 @@ func CheckMutateBuffer(org []byte, offset flatbuffers.UOffsetT, fail func(string
}
}
func CheckObjectAPI(buf []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) {
monster := example.GetRootAsMonster(buf, offset).UnPack()
if got := monster.Hp; 80 != got {
fail(FailString("hp", 80, got))
}
// default
if got := monster.Mana; 150 != got {
fail(FailString("mana", 150, got))
}
builder := flatbuffers.NewBuilder(0)
builder.Finish(example.MonsterPack(builder, monster))
monster2 := example.GetRootAsMonster(builder.FinishedBytes(), 0).UnPack()
if !reflect.DeepEqual(monster, monster2) {
fail(FailString("Pack/Unpack()", monster, monster2))
}
}
// Low level stress/fuzz test: serialize/deserialize a variety of
// different kinds of data in different combinations
func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) {
......
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