mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-03 12:44:13 +00:00
Add a generic way to deserialize a flatbuffer in Go.
Similar to what protobufs does with its `Message` interface, introduce here such interface and create a generic `GetRootAs` method to deserialize a flatbuffer.
This commit is contained in:
13
go/lib.go
Normal file
13
go/lib.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package flatbuffers
|
||||||
|
|
||||||
|
// FlatBuffer is the interface that represents a flatbuffer.
|
||||||
|
type FlatBuffer interface {
|
||||||
|
Table() Table
|
||||||
|
Init(buf []byte, i UOffsetT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootAs is a generic helper to initialize a FlatBuffer with the provided buffer bytes and its data offset.
|
||||||
|
func GetRootAs(buf []byte, offset UOffsetT, fb FlatBuffer) {
|
||||||
|
n := GetUOffsetT(buf[offset:])
|
||||||
|
fb.Init(buf, n+offset)
|
||||||
|
}
|
||||||
@@ -144,6 +144,23 @@ static void InitializeExisting(const StructDef &struct_def,
|
|||||||
code += "}\n\n";
|
code += "}\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implement the table accessor
|
||||||
|
static void GenTableAccessor(const StructDef &struct_def,
|
||||||
|
std::string *code_ptr) {
|
||||||
|
std::string &code = *code_ptr;
|
||||||
|
|
||||||
|
GenReceiver(struct_def, code_ptr);
|
||||||
|
code += " Table() flatbuffers.Table ";
|
||||||
|
code += "{\n";
|
||||||
|
|
||||||
|
if (struct_def.fixed) {
|
||||||
|
code += "\treturn rcv._tab.Table\n";
|
||||||
|
} else {
|
||||||
|
code += "\treturn rcv._tab\n";
|
||||||
|
}
|
||||||
|
code += "}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Get the length of a vector.
|
// Get the length of a vector.
|
||||||
static void GetVectorLen(const StructDef &struct_def,
|
static void GetVectorLen(const StructDef &struct_def,
|
||||||
const FieldDef &field,
|
const FieldDef &field,
|
||||||
@@ -594,6 +611,10 @@ static void GenStruct(const StructDef &struct_def,
|
|||||||
// Generate the Init method that sets the field in a pre-existing
|
// Generate the Init method that sets the field in a pre-existing
|
||||||
// accessor object. This is to allow object reuse.
|
// accessor object. This is to allow object reuse.
|
||||||
InitializeExisting(struct_def, code_ptr);
|
InitializeExisting(struct_def, code_ptr);
|
||||||
|
// Generate _tab accessor
|
||||||
|
GenTableAccessor(struct_def, code_ptr);
|
||||||
|
|
||||||
|
// Generate struct fields accessors
|
||||||
for (auto it = struct_def.fields.vec.begin();
|
for (auto it = struct_def.fields.vec.begin();
|
||||||
it != struct_def.fields.vec.end();
|
it != struct_def.fields.vec.end();
|
||||||
++it) {
|
++it) {
|
||||||
@@ -604,6 +625,7 @@ static void GenStruct(const StructDef &struct_def,
|
|||||||
GenStructMutator(struct_def, field, code_ptr);
|
GenStructMutator(struct_def, field, code_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate builders
|
||||||
if (struct_def.fixed) {
|
if (struct_def.fixed) {
|
||||||
// create a struct constructor function
|
// create a struct constructor function
|
||||||
GenStructBuilder(struct_def, code_ptr);
|
GenStructBuilder(struct_def, code_ptr);
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
|
|||||||
rcv._tab.Pos = i
|
rcv._tab.Pos = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *Monster) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab
|
||||||
|
}
|
||||||
|
|
||||||
func (rcv *Monster) Pos(obj *Vec3) *Vec3 {
|
func (rcv *Monster) Pos(obj *Vec3) *Vec3 {
|
||||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||||
if o != 0 {
|
if o != 0 {
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ func (rcv *Stat) Init(buf []byte, i flatbuffers.UOffsetT) {
|
|||||||
rcv._tab.Pos = i
|
rcv._tab.Pos = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *Stat) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab
|
||||||
|
}
|
||||||
|
|
||||||
func (rcv *Stat) Id() []byte {
|
func (rcv *Stat) Id() []byte {
|
||||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||||
if o != 0 {
|
if o != 0 {
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ func (rcv *Test) Init(buf []byte, i flatbuffers.UOffsetT) {
|
|||||||
rcv._tab.Pos = i
|
rcv._tab.Pos = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *Test) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab.Table
|
||||||
|
}
|
||||||
|
|
||||||
func (rcv *Test) A() int16 {
|
func (rcv *Test) A() int16 {
|
||||||
return rcv._tab.GetInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0))
|
return rcv._tab.GetInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ func (rcv *TestSimpleTableWithEnum) Init(buf []byte, i flatbuffers.UOffsetT) {
|
|||||||
rcv._tab.Pos = i
|
rcv._tab.Pos = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *TestSimpleTableWithEnum) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab
|
||||||
|
}
|
||||||
|
|
||||||
func (rcv *TestSimpleTableWithEnum) Color() int8 {
|
func (rcv *TestSimpleTableWithEnum) Color() int8 {
|
||||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
|
||||||
if o != 0 {
|
if o != 0 {
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ func (rcv *Vec3) Init(buf []byte, i flatbuffers.UOffsetT) {
|
|||||||
rcv._tab.Pos = i
|
rcv._tab.Pos = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *Vec3) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab.Table
|
||||||
|
}
|
||||||
|
|
||||||
func (rcv *Vec3) X() float32 {
|
func (rcv *Vec3) X() float32 {
|
||||||
return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
|
return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
|
|||||||
rcv._tab.Pos = i
|
rcv._tab.Pos = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rcv *Monster) Table() flatbuffers.Table {
|
||||||
|
return rcv._tab
|
||||||
|
}
|
||||||
|
|
||||||
func MonsterStart(builder *flatbuffers.Builder) {
|
func MonsterStart(builder *flatbuffers.Builder) {
|
||||||
builder.StartObject(0)
|
builder.StartObject(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ func TestAll(t *testing.T) {
|
|||||||
|
|
||||||
// Verify that GetRootAs works for non-root tables
|
// Verify that GetRootAs works for non-root tables
|
||||||
CheckGetRootAsForNonRootTable(t.Fatalf)
|
CheckGetRootAsForNonRootTable(t.Fatalf)
|
||||||
|
CheckTableAccessors(t.Fatalf)
|
||||||
|
|
||||||
// Verify that using the generated Go code builds a buffer without
|
// Verify that using the generated Go code builds a buffer without
|
||||||
// returning errors:
|
// returning errors:
|
||||||
@@ -137,8 +138,11 @@ func TestAll(t *testing.T) {
|
|||||||
// CheckReadBuffer checks that the given buffer is evaluated correctly
|
// CheckReadBuffer checks that the given buffer is evaluated correctly
|
||||||
// as the example Monster.
|
// as the example Monster.
|
||||||
func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) {
|
func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) {
|
||||||
monster := example.GetRootAsMonster(buf, offset)
|
// try the two ways of generating a monster
|
||||||
|
monster1 := example.GetRootAsMonster(buf, offset)
|
||||||
|
monster2 := &example.Monster{}
|
||||||
|
flatbuffers.GetRootAs(buf, offset, monster2)
|
||||||
|
for _, monster := range []*example.Monster{monster1, monster2} {
|
||||||
if got := monster.Hp(); 80 != got {
|
if got := monster.Hp(); 80 != got {
|
||||||
fail(FailString("hp", 80, got))
|
fail(FailString("hp", 80, got))
|
||||||
}
|
}
|
||||||
@@ -288,6 +292,7 @@ func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string,
|
|||||||
fail(FailString("Testarrayofstring(1)", "test2", got))
|
fail(FailString("Testarrayofstring(1)", "test2", got))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckMutateBuffer checks that the given buffer can be mutated correctly
|
// CheckMutateBuffer checks that the given buffer can be mutated correctly
|
||||||
// as the example Monster. Only available scalar values are mutated.
|
// as the example Monster. Only available scalar values are mutated.
|
||||||
@@ -1161,6 +1166,38 @@ func CheckGeneratedBuild(fail func(string, ...interface{})) ([]byte, flatbuffers
|
|||||||
return b.Bytes, b.Head()
|
return b.Bytes, b.Head()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckTableAccessors checks that the table accessors work as expected.
|
||||||
|
func CheckTableAccessors(fail func(string, ...interface{})) {
|
||||||
|
// test struct accessor
|
||||||
|
b := flatbuffers.NewBuilder(0)
|
||||||
|
pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 4, 5, 6)
|
||||||
|
b.Finish(pos)
|
||||||
|
vec3Bytes := b.FinishedBytes()
|
||||||
|
vec3 := &example.Vec3{}
|
||||||
|
flatbuffers.GetRootAs(vec3Bytes, 0, vec3)
|
||||||
|
|
||||||
|
if bytes.Compare(vec3Bytes, vec3.Table().Bytes) != 0 {
|
||||||
|
fail("invalid vec3 table")
|
||||||
|
}
|
||||||
|
|
||||||
|
// test table accessor
|
||||||
|
b = flatbuffers.NewBuilder(0)
|
||||||
|
str := b.CreateString("MyStat")
|
||||||
|
example.StatStart(b)
|
||||||
|
example.StatAddId(b, str)
|
||||||
|
example.StatAddVal(b, 12345678)
|
||||||
|
example.StatAddCount(b, 12345)
|
||||||
|
pos = example.StatEnd(b)
|
||||||
|
b.Finish(pos)
|
||||||
|
statBytes := b.FinishedBytes()
|
||||||
|
stat := &example.Stat{}
|
||||||
|
flatbuffers.GetRootAs(statBytes, 0, stat)
|
||||||
|
|
||||||
|
if bytes.Compare(statBytes, stat.Table().Bytes) != 0 {
|
||||||
|
fail("invalid stat table")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckVtableDeduplication verifies that vtables are deduplicated.
|
// CheckVtableDeduplication verifies that vtables are deduplicated.
|
||||||
func CheckVtableDeduplication(fail func(string, ...interface{})) {
|
func CheckVtableDeduplication(fail func(string, ...interface{})) {
|
||||||
b := flatbuffers.NewBuilder(0)
|
b := flatbuffers.NewBuilder(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user