xref: /aosp_15_r20/external/flatbuffers/samples/sample_binary.go (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker/*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2015 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker *     http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker// To run, use the `go_sample.sh` script.
18*890232f2SAndroid Build Coastguard Worker
19*890232f2SAndroid Build Coastguard Workerpackage main
20*890232f2SAndroid Build Coastguard Worker
21*890232f2SAndroid Build Coastguard Workerimport (
22*890232f2SAndroid Build Coastguard Worker	sample "MyGame/Sample"
23*890232f2SAndroid Build Coastguard Worker	"fmt"
24*890232f2SAndroid Build Coastguard Worker	flatbuffers "github.com/google/flatbuffers/go"
25*890232f2SAndroid Build Coastguard Worker	"strconv"
26*890232f2SAndroid Build Coastguard Worker)
27*890232f2SAndroid Build Coastguard Worker
28*890232f2SAndroid Build Coastguard Worker// Example how to use Flatbuffers to create and read binary buffers.
29*890232f2SAndroid Build Coastguard Workerfunc main() {
30*890232f2SAndroid Build Coastguard Worker	builder := flatbuffers.NewBuilder(0)
31*890232f2SAndroid Build Coastguard Worker
32*890232f2SAndroid Build Coastguard Worker	// Create some weapons for our Monster ("Sword" and "Axe").
33*890232f2SAndroid Build Coastguard Worker	weaponOne := builder.CreateString("Sword")
34*890232f2SAndroid Build Coastguard Worker	weaponTwo := builder.CreateString("Axe")
35*890232f2SAndroid Build Coastguard Worker
36*890232f2SAndroid Build Coastguard Worker	sample.WeaponStart(builder)
37*890232f2SAndroid Build Coastguard Worker	sample.WeaponAddName(builder, weaponOne)
38*890232f2SAndroid Build Coastguard Worker	sample.WeaponAddDamage(builder, 3)
39*890232f2SAndroid Build Coastguard Worker	sword := sample.WeaponEnd(builder)
40*890232f2SAndroid Build Coastguard Worker
41*890232f2SAndroid Build Coastguard Worker	sample.WeaponStart(builder)
42*890232f2SAndroid Build Coastguard Worker	sample.WeaponAddName(builder, weaponTwo)
43*890232f2SAndroid Build Coastguard Worker	sample.WeaponAddDamage(builder, 5)
44*890232f2SAndroid Build Coastguard Worker	axe := sample.WeaponEnd(builder)
45*890232f2SAndroid Build Coastguard Worker
46*890232f2SAndroid Build Coastguard Worker	// Serialize the FlatBuffer data.
47*890232f2SAndroid Build Coastguard Worker	name := builder.CreateString("Orc")
48*890232f2SAndroid Build Coastguard Worker
49*890232f2SAndroid Build Coastguard Worker	sample.MonsterStartInventoryVector(builder, 10)
50*890232f2SAndroid Build Coastguard Worker	// Note: Since we prepend the bytes, this loop iterates in reverse.
51*890232f2SAndroid Build Coastguard Worker	for i := 9; i >= 0; i-- {
52*890232f2SAndroid Build Coastguard Worker		builder.PrependByte(byte(i))
53*890232f2SAndroid Build Coastguard Worker	}
54*890232f2SAndroid Build Coastguard Worker	inv := builder.EndVector(10)
55*890232f2SAndroid Build Coastguard Worker
56*890232f2SAndroid Build Coastguard Worker	sample.MonsterStartWeaponsVector(builder, 2)
57*890232f2SAndroid Build Coastguard Worker	// Note: Since we prepend the weapons, prepend in reverse order.
58*890232f2SAndroid Build Coastguard Worker	builder.PrependUOffsetT(axe)
59*890232f2SAndroid Build Coastguard Worker	builder.PrependUOffsetT(sword)
60*890232f2SAndroid Build Coastguard Worker	weapons := builder.EndVector(2)
61*890232f2SAndroid Build Coastguard Worker
62*890232f2SAndroid Build Coastguard Worker	pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
63*890232f2SAndroid Build Coastguard Worker
64*890232f2SAndroid Build Coastguard Worker	sample.MonsterStart(builder)
65*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddPos(builder, pos)
66*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddHp(builder, 300)
67*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddName(builder, name)
68*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddInventory(builder, inv)
69*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddColor(builder, sample.ColorRed)
70*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddWeapons(builder, weapons)
71*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
72*890232f2SAndroid Build Coastguard Worker	sample.MonsterAddEquipped(builder, axe)
73*890232f2SAndroid Build Coastguard Worker	orc := sample.MonsterEnd(builder)
74*890232f2SAndroid Build Coastguard Worker
75*890232f2SAndroid Build Coastguard Worker	builder.Finish(orc)
76*890232f2SAndroid Build Coastguard Worker
77*890232f2SAndroid Build Coastguard Worker	// We now have a FlatBuffer that we could store on disk or send over a network.
78*890232f2SAndroid Build Coastguard Worker
79*890232f2SAndroid Build Coastguard Worker	// ...Saving to file or sending over a network code goes here...
80*890232f2SAndroid Build Coastguard Worker
81*890232f2SAndroid Build Coastguard Worker	// Instead, we are going to access this buffer right away (as if we just received it).
82*890232f2SAndroid Build Coastguard Worker
83*890232f2SAndroid Build Coastguard Worker	buf := builder.FinishedBytes()
84*890232f2SAndroid Build Coastguard Worker
85*890232f2SAndroid Build Coastguard Worker	// Note: We use `0` for the offset here, since we got the data using the
86*890232f2SAndroid Build Coastguard Worker	// `builder.FinishedBytes()` method. This simulates the data you would store/receive in your
87*890232f2SAndroid Build Coastguard Worker	// FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to
88*890232f2SAndroid Build Coastguard Worker	// pass in the offset of `builder.Head()`, as the builder actually constructs the buffer
89*890232f2SAndroid Build Coastguard Worker	// backwards.
90*890232f2SAndroid Build Coastguard Worker	monster := sample.GetRootAsMonster(buf, 0)
91*890232f2SAndroid Build Coastguard Worker
92*890232f2SAndroid Build Coastguard Worker	// Note: We did not set the `mana` field explicitly, so we get the
93*890232f2SAndroid Build Coastguard Worker	// default value.
94*890232f2SAndroid Build Coastguard Worker	assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150")
95*890232f2SAndroid Build Coastguard Worker	assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300")
96*890232f2SAndroid Build Coastguard Worker	assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()),
97*890232f2SAndroid Build Coastguard Worker		"\"Orc\"")
98*890232f2SAndroid Build Coastguard Worker	assert(monster.Color() == sample.ColorRed, "`monster.Color()`",
99*890232f2SAndroid Build Coastguard Worker		strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed)))
100*890232f2SAndroid Build Coastguard Worker
101*890232f2SAndroid Build Coastguard Worker	// Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object
102*890232f2SAndroid Build Coastguard Worker	// gets created. If your code is very performance sensitive, you can pass in a pointer to an
103*890232f2SAndroid Build Coastguard Worker	// existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce
104*890232f2SAndroid Build Coastguard Worker	// the amount of object allocation/garbage collection.
105*890232f2SAndroid Build Coastguard Worker	assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`",
106*890232f2SAndroid Build Coastguard Worker		strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0")
107*890232f2SAndroid Build Coastguard Worker	assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`",
108*890232f2SAndroid Build Coastguard Worker		strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0")
109*890232f2SAndroid Build Coastguard Worker	assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`",
110*890232f2SAndroid Build Coastguard Worker		strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0")
111*890232f2SAndroid Build Coastguard Worker
112*890232f2SAndroid Build Coastguard Worker	// For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used
113*890232f2SAndroid Build Coastguard Worker	// to query the length of the vector. You can index the vector by passing an index value
114*890232f2SAndroid Build Coastguard Worker	// into the accessor.
115*890232f2SAndroid Build Coastguard Worker	for i := 0; i < monster.InventoryLength(); i++ {
116*890232f2SAndroid Build Coastguard Worker		assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`",
117*890232f2SAndroid Build Coastguard Worker			strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i))))
118*890232f2SAndroid Build Coastguard Worker	}
119*890232f2SAndroid Build Coastguard Worker
120*890232f2SAndroid Build Coastguard Worker	expectedWeaponNames := []string{"Sword", "Axe"}
121*890232f2SAndroid Build Coastguard Worker	expectedWeaponDamages := []int{3, 5}
122*890232f2SAndroid Build Coastguard Worker	weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
123*890232f2SAndroid Build Coastguard Worker	// to capture the output of that function.
124*890232f2SAndroid Build Coastguard Worker	for i := 0; i < monster.WeaponsLength(); i++ {
125*890232f2SAndroid Build Coastguard Worker		if monster.Weapons(weapon, i) {
126*890232f2SAndroid Build Coastguard Worker			assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`",
127*890232f2SAndroid Build Coastguard Worker				string(weapon.Name()), expectedWeaponNames[i])
128*890232f2SAndroid Build Coastguard Worker			assert(int(weapon.Damage()) == expectedWeaponDamages[i],
129*890232f2SAndroid Build Coastguard Worker				"`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())),
130*890232f2SAndroid Build Coastguard Worker				strconv.Itoa(expectedWeaponDamages[i]))
131*890232f2SAndroid Build Coastguard Worker		}
132*890232f2SAndroid Build Coastguard Worker	}
133*890232f2SAndroid Build Coastguard Worker
134*890232f2SAndroid Build Coastguard Worker	// For FlatBuffer `union`s, you can get the type of the union, as well as the union
135*890232f2SAndroid Build Coastguard Worker	// data itself.
136*890232f2SAndroid Build Coastguard Worker	assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`",
137*890232f2SAndroid Build Coastguard Worker		strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon)))
138*890232f2SAndroid Build Coastguard Worker
139*890232f2SAndroid Build Coastguard Worker	unionTable := new(flatbuffers.Table)
140*890232f2SAndroid Build Coastguard Worker	if monster.Equipped(unionTable) {
141*890232f2SAndroid Build Coastguard Worker		// An example of how you can appropriately convert the table depending on the
142*890232f2SAndroid Build Coastguard Worker		// FlatBuffer `union` type. You could add `else if` and `else` clauses to handle
143*890232f2SAndroid Build Coastguard Worker		// other FlatBuffer `union` types for this field. (Similarly, this could be
144*890232f2SAndroid Build Coastguard Worker		// done in a switch statement.)
145*890232f2SAndroid Build Coastguard Worker		if monster.EquippedType() == sample.EquipmentWeapon {
146*890232f2SAndroid Build Coastguard Worker			unionWeapon := new(sample.Weapon)
147*890232f2SAndroid Build Coastguard Worker			unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
148*890232f2SAndroid Build Coastguard Worker
149*890232f2SAndroid Build Coastguard Worker			assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`",
150*890232f2SAndroid Build Coastguard Worker				string(unionWeapon.Name()), "Axe")
151*890232f2SAndroid Build Coastguard Worker			assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`",
152*890232f2SAndroid Build Coastguard Worker				strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5))
153*890232f2SAndroid Build Coastguard Worker		}
154*890232f2SAndroid Build Coastguard Worker	}
155*890232f2SAndroid Build Coastguard Worker
156*890232f2SAndroid Build Coastguard Worker	fmt.Printf("The FlatBuffer was successfully created and verified!\n")
157*890232f2SAndroid Build Coastguard Worker}
158*890232f2SAndroid Build Coastguard Worker
159*890232f2SAndroid Build Coastguard Worker// A helper function to print out if an assertion failed.
160*890232f2SAndroid Build Coastguard Workerfunc assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) {
161*890232f2SAndroid Build Coastguard Worker	if assertPassed == false {
162*890232f2SAndroid Build Coastguard Worker		panic("Assert failed! " + codeExecuted + " (" + actualValue +
163*890232f2SAndroid Build Coastguard Worker			") was not equal to " + expectedValue + ".")
164*890232f2SAndroid Build Coastguard Worker	}
165*890232f2SAndroid Build Coastguard Worker}
166