blob: 33917ff77686c25af0dbf1a130a7ece8f3f8545f [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// independent from idl_parser, since this code is not needed for most clients
18
James Kuszmaul3b15b0c2022-11-08 14:03:16 -080019#include <algorithm>
20#include <cmath>
Austin Schuhe89fa2d2019-08-14 20:24:23 -070021#include <sstream>
22#include <string>
23
24#include "flatbuffers/code_generators.h"
25#include "flatbuffers/flatbuffers.h"
26#include "flatbuffers/idl.h"
27#include "flatbuffers/util.h"
Austin Schuh2dd86a92022-09-14 21:19:23 -070028#include "idl_namer.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070029
30#ifdef _WIN32
31# include <direct.h>
32# define PATH_SEPARATOR "\\"
33# define mkdir(n, m) _mkdir(n)
34#else
35# include <sys/stat.h>
36# define PATH_SEPARATOR "/"
37#endif
38
39namespace flatbuffers {
40
Austin Schuhe89fa2d2019-08-14 20:24:23 -070041namespace go {
42
Austin Schuh2dd86a92022-09-14 21:19:23 -070043namespace {
44
Austin Schuhe89fa2d2019-08-14 20:24:23 -070045// see https://golang.org/ref/spec#Keywords
Austin Schuh2dd86a92022-09-14 21:19:23 -070046static std::set<std::string> GoKeywords() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070047 return {
48 "break", "default", "func", "interface", "select",
49 "case", "defer", "go", "map", "struct",
50 "chan", "else", "goto", "package", "switch",
51 "const", "fallthrough", "if", "range", "type",
52 "continue", "for", "import", "return", "var",
53 };
54}
Austin Schuhe89fa2d2019-08-14 20:24:23 -070055
Austin Schuh2dd86a92022-09-14 21:19:23 -070056static Namer::Config GoDefaultConfig() {
James Kuszmaul8e62b022022-03-22 09:33:25 -070057 // Note that the functions with user defined types in the name use
58 // upper camel case for all but the user defined type itself, which is keep
59 // cased. Despite being a function, we interpret it as a Type.
60 return { /*types=*/Case::kKeep,
61 /*constants=*/Case::kUnknown,
62 /*methods=*/Case::kUpperCamel,
63 /*functions=*/Case::kUpperCamel,
64 /*fields=*/Case::kUpperCamel,
65 /*variables=*/Case::kLowerCamel,
66 /*variants=*/Case::kKeep,
67 /*enum_variant_seperator=*/"", // I.e. Concatenate.
Austin Schuh2dd86a92022-09-14 21:19:23 -070068 /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
James Kuszmaul8e62b022022-03-22 09:33:25 -070069 /*namespaces=*/Case::kKeep,
70 /*namespace_seperator=*/"__",
71 /*object_prefix=*/"",
72 /*object_suffix=*/"T",
73 /*keyword_prefix=*/"",
74 /*keyword_suffix=*/"_",
75 /*filenames=*/Case::kKeep,
76 /*directories=*/Case::kKeep,
77 /*output_path=*/"",
78 /*filename_suffix=*/"",
79 /*filename_extension=*/".go" };
Austin Schuhe89fa2d2019-08-14 20:24:23 -070080}
81
Austin Schuh2dd86a92022-09-14 21:19:23 -070082} // namespace
83
Austin Schuhe89fa2d2019-08-14 20:24:23 -070084class GoGenerator : public BaseGenerator {
85 public:
86 GoGenerator(const Parser &parser, const std::string &path,
87 const std::string &file_name, const std::string &go_namespace)
88 : BaseGenerator(parser, path, file_name, "" /* not used*/,
Austin Schuh272c6132020-11-14 16:37:52 -080089 "" /* not used */, "go"),
James Kuszmaul8e62b022022-03-22 09:33:25 -070090 cur_name_space_(nullptr),
Austin Schuh2dd86a92022-09-14 21:19:23 -070091 namer_(WithFlagOptions(GoDefaultConfig(), parser.opts, path),
92 GoKeywords()) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070093 std::istringstream iss(go_namespace);
94 std::string component;
95 while (std::getline(iss, component, '.')) {
96 go_namespace_.components.push_back(component);
97 }
98 }
99
100 bool generate() {
101 std::string one_file_code;
Austin Schuh272c6132020-11-14 16:37:52 -0800102 bool needs_imports = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700103 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
104 ++it) {
105 tracked_imported_namespaces_.clear();
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800106 needs_math_import_ = false;
Austin Schuh272c6132020-11-14 16:37:52 -0800107 needs_imports = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700108 std::string enumcode;
109 GenEnum(**it, &enumcode);
Austin Schuh272c6132020-11-14 16:37:52 -0800110 if ((*it)->is_union && parser_.opts.generate_object_based_api) {
111 GenNativeUnion(**it, &enumcode);
112 GenNativeUnionPack(**it, &enumcode);
113 GenNativeUnionUnPack(**it, &enumcode);
114 needs_imports = true;
115 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700116 if (parser_.opts.one_file) {
117 one_file_code += enumcode;
118 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800119 if (!SaveType(**it, enumcode, needs_imports, true)) return false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700120 }
121 }
122
123 for (auto it = parser_.structs_.vec.begin();
124 it != parser_.structs_.vec.end(); ++it) {
125 tracked_imported_namespaces_.clear();
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800126 needs_math_import_ = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700127 std::string declcode;
128 GenStruct(**it, &declcode);
129 if (parser_.opts.one_file) {
130 one_file_code += declcode;
131 } else {
132 if (!SaveType(**it, declcode, true, false)) return false;
133 }
134 }
135
136 if (parser_.opts.one_file) {
137 std::string code = "";
138 const bool is_enum = !parser_.enums_.vec.empty();
139 BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
140 code += one_file_code;
Austin Schuh272c6132020-11-14 16:37:52 -0800141 const std::string filename =
142 GeneratedFileName(path_, file_name_, parser_.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700143 return SaveFile(filename.c_str(), code, false);
144 }
145
146 return true;
147 }
148
149 private:
150 Namespace go_namespace_;
151 Namespace *cur_name_space_;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700152 const IdlNamer namer_;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700153
154 struct NamespacePtrLess {
155 bool operator()(const Namespace *a, const Namespace *b) const {
156 return *a < *b;
157 }
158 };
159 std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800160 bool needs_math_import_ = false;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700161
162 // Most field accessors need to retrieve and test the field offset first,
163 // this is the prefix code for that.
164 std::string OffsetPrefix(const FieldDef &field) {
165 return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
166 NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
167 }
168
169 // Begin a class declaration.
170 void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
171 std::string &code = *code_ptr;
172
Austin Schuh2dd86a92022-09-14 21:19:23 -0700173 code += "type " + namer_.Type(struct_def) + " struct {\n\t";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700174
175 // _ is reserved in flatbuffers field names, so no chance of name conflict:
176 code += "_tab ";
177 code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
178 code += "\n}\n\n";
179 }
180
181 // Construct the name of the type for this enum.
182 std::string GetEnumTypeName(const EnumDef &enum_def) {
Austin Schuh272c6132020-11-14 16:37:52 -0800183 return WrapInNameSpaceAndTrack(enum_def.defined_namespace,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700184 namer_.Type(enum_def));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700185 }
186
187 // Create a type for the enum values.
188 void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
189 std::string &code = *code_ptr;
190 code += "type " + GetEnumTypeName(enum_def) + " ";
191 code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
192 }
193
194 // Begin enum code with a class declaration.
195 void BeginEnum(std::string *code_ptr) {
196 std::string &code = *code_ptr;
197 code += "const (\n";
198 }
199
200 // A single enum member.
201 void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
202 size_t max_name_length, std::string *code_ptr) {
203 std::string &code = *code_ptr;
204 code += "\t";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700205 code += namer_.EnumVariant(enum_def, ev);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700206 code += " ";
207 code += std::string(max_name_length - ev.name.length(), ' ');
208 code += GetEnumTypeName(enum_def);
209 code += " = ";
210 code += enum_def.ToString(ev) + "\n";
211 }
212
213 // End enum code.
214 void EndEnum(std::string *code_ptr) {
215 std::string &code = *code_ptr;
216 code += ")\n\n";
217 }
218
219 // Begin enum name map.
220 void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
221 std::string &code = *code_ptr;
222 code += "var EnumNames";
223 code += enum_def.name;
224 code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
225 }
226
227 // A single enum name member.
228 void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
229 size_t max_name_length, std::string *code_ptr) {
230 std::string &code = *code_ptr;
231 code += "\t";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700232 code += namer_.EnumVariant(enum_def, ev);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700233 code += ": ";
234 code += std::string(max_name_length - ev.name.length(), ' ');
235 code += "\"";
236 code += ev.name;
237 code += "\",\n";
238 }
239
240 // End enum name map.
241 void EndEnumNames(std::string *code_ptr) {
242 std::string &code = *code_ptr;
243 code += "}\n\n";
244 }
245
246 // Generate String() method on enum type.
247 void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
248 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700249 const std::string enum_type = namer_.Type(enum_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700250 code += "func (v " + enum_type + ") String() string {\n";
251 code += "\tif s, ok := EnumNames" + enum_type + "[v]; ok {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700252 code += "\t\treturn s\n";
253 code += "\t}\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800254 code += "\treturn \"" + enum_def.name;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700255 code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
256 code += "}\n\n";
257 }
258
259 // Begin enum value map.
260 void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
261 std::string &code = *code_ptr;
262 code += "var EnumValues";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700263 code += namer_.Type(enum_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700264 code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
265 }
266
267 // A single enum value member.
268 void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
269 size_t max_name_length, std::string *code_ptr) {
270 std::string &code = *code_ptr;
271 code += "\t\"";
272 code += ev.name;
273 code += "\": ";
274 code += std::string(max_name_length - ev.name.length(), ' ');
Austin Schuh2dd86a92022-09-14 21:19:23 -0700275 code += namer_.EnumVariant(enum_def, ev);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700276 code += ",\n";
277 }
278
279 // End enum value map.
280 void EndEnumValues(std::string *code_ptr) {
281 std::string &code = *code_ptr;
282 code += "}\n\n";
283 }
284
285 // Initialize a new struct or table from existing data.
286 void NewRootTypeFromBuffer(const StructDef &struct_def,
287 std::string *code_ptr) {
288 std::string &code = *code_ptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700289 const std::string size_prefix[] = { "", "SizePrefixed" };
Austin Schuh2dd86a92022-09-14 21:19:23 -0700290 const std::string struct_type = namer_.Type(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700291
Austin Schuh272c6132020-11-14 16:37:52 -0800292 for (int i = 0; i < 2; i++) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700293 code += "func Get" + size_prefix[i] + "RootAs" + struct_type;
Austin Schuh272c6132020-11-14 16:37:52 -0800294 code += "(buf []byte, offset flatbuffers.UOffsetT) ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700295 code += "*" + struct_type + "";
Austin Schuh272c6132020-11-14 16:37:52 -0800296 code += " {\n";
297 if (i == 0) {
298 code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
299 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700300 code +=
301 "\tn := "
302 "flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800303 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700304 code += "\tx := &" + struct_type + "{}\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800305 if (i == 0) {
306 code += "\tx.Init(buf, n+offset)\n";
307 } else {
308 code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n";
309 }
310 code += "\treturn x\n";
311 code += "}\n\n";
312 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700313 }
314
315 // Initialize an existing object with other data, to avoid an allocation.
316 void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
317 std::string &code = *code_ptr;
318
319 GenReceiver(struct_def, code_ptr);
320 code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
321 code += "{\n";
322 code += "\trcv._tab.Bytes = buf\n";
323 code += "\trcv._tab.Pos = i\n";
324 code += "}\n\n";
325 }
326
327 // Implement the table accessor
328 void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
329 std::string &code = *code_ptr;
330
331 GenReceiver(struct_def, code_ptr);
332 code += " Table() flatbuffers.Table ";
333 code += "{\n";
334
335 if (struct_def.fixed) {
336 code += "\treturn rcv._tab.Table\n";
337 } else {
338 code += "\treturn rcv._tab\n";
339 }
340 code += "}\n\n";
341 }
342
343 // Get the length of a vector.
344 void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
345 std::string *code_ptr) {
346 std::string &code = *code_ptr;
347
348 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700349 code += " " + namer_.Function(field) + "Length(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700350 code += ") int " + OffsetPrefix(field);
351 code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
352 code += "\treturn 0\n}\n\n";
353 }
354
355 // Get a [ubyte] vector as a byte slice.
356 void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
357 std::string *code_ptr) {
358 std::string &code = *code_ptr;
359
360 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700361 code += " " + namer_.Function(field) + "Bytes(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700362 code += ") []byte " + OffsetPrefix(field);
363 code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
364 code += "\treturn nil\n}\n\n";
365 }
366
367 // Get the value of a struct's scalar.
368 void GetScalarFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800369 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700370 std::string &code = *code_ptr;
371 std::string getter = GenGetter(field.value.type);
372 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700373 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700374 code += "() " + TypeName(field) + " {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800375 code += "\treturn " +
376 CastToEnum(field.value.type,
377 getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
378 NumToString(field.value.offset) + "))");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700379 code += "\n}\n";
380 }
381
382 // Get the value of a table's scalar.
Austin Schuh272c6132020-11-14 16:37:52 -0800383 void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700384 std::string *code_ptr) {
385 std::string &code = *code_ptr;
386 std::string getter = GenGetter(field.value.type);
387 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700388 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700389 code += "() " + TypeName(field) + " ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700390 code += OffsetPrefix(field);
391 if (field.IsScalarOptional()) {
392 code += "\t\tv := ";
393 } else {
394 code += "\t\treturn ";
395 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700396 code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
Austin Schuh2dd86a92022-09-14 21:19:23 -0700397 if (field.IsScalarOptional()) { code += "\n\t\treturn &v"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700398 code += "\n\t}\n";
399 code += "\treturn " + GenConstant(field) + "\n";
400 code += "}\n\n";
401 }
402
403 // Get a struct by initializing an existing struct.
404 // Specific to Struct.
405 void GetStructFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800406 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700407 std::string &code = *code_ptr;
408 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700409 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700410 code += "(obj *" + TypeName(field);
411 code += ") *" + TypeName(field);
412 code += " {\n";
413 code += "\tif obj == nil {\n";
414 code += "\t\tobj = new(" + TypeName(field) + ")\n";
415 code += "\t}\n";
416 code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
417 code += NumToString(field.value.offset) + ")";
418 code += "\n\treturn obj\n";
419 code += "}\n";
420 }
421
422 // Get a struct by initializing an existing struct.
423 // Specific to Table.
Austin Schuh272c6132020-11-14 16:37:52 -0800424 void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700425 std::string *code_ptr) {
426 std::string &code = *code_ptr;
427 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700428 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700429 code += "(obj *";
430 code += TypeName(field);
431 code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
432 if (field.value.type.struct_def->fixed) {
433 code += "\t\tx := o + rcv._tab.Pos\n";
434 } else {
435 code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
436 }
437 code += "\t\tif obj == nil {\n";
438 code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
439 code += "\t\t}\n";
440 code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
441 code += "\t\treturn obj\n\t}\n\treturn nil\n";
442 code += "}\n\n";
443 }
444
445 // Get the value of a string.
Austin Schuh272c6132020-11-14 16:37:52 -0800446 void GetStringField(const StructDef &struct_def, const FieldDef &field,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700447 std::string *code_ptr) {
448 std::string &code = *code_ptr;
449 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700450 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700451 code += "() " + TypeName(field) + " ";
452 code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
453 code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
454 code += "}\n\n";
455 }
456
457 // Get the value of a union from an object.
458 void GetUnionField(const StructDef &struct_def, const FieldDef &field,
459 std::string *code_ptr) {
460 std::string &code = *code_ptr;
461 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700462 code += " " + namer_.Function(field) + "(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700463 code += "obj " + GenTypePointer(field.value.type) + ") bool ";
464 code += OffsetPrefix(field);
465 code += "\t\t" + GenGetter(field.value.type);
466 code += "(obj, o)\n\t\treturn true\n\t}\n";
467 code += "\treturn false\n";
468 code += "}\n\n";
469 }
470
471 // Get the value of a vector's struct member.
472 void GetMemberOfVectorOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800473 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700474 std::string &code = *code_ptr;
475 auto vectortype = field.value.type.VectorType();
476
477 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700478 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700479 code += "(obj *" + TypeName(field);
480 code += ", j int) bool " + OffsetPrefix(field);
481 code += "\t\tx := rcv._tab.Vector(o)\n";
482 code += "\t\tx += flatbuffers.UOffsetT(j) * ";
483 code += NumToString(InlineSize(vectortype)) + "\n";
484 if (!(vectortype.struct_def->fixed)) {
485 code += "\t\tx = rcv._tab.Indirect(x)\n";
486 }
487 code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
488 code += "\t\treturn true\n\t}\n";
489 code += "\treturn false\n";
490 code += "}\n\n";
491 }
492
493 // Get the value of a vector's non-struct member.
494 void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
495 const FieldDef &field,
496 std::string *code_ptr) {
497 std::string &code = *code_ptr;
498 auto vectortype = field.value.type.VectorType();
499
500 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700501 code += " " + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700502 code += "(j int) " + TypeName(field) + " ";
503 code += OffsetPrefix(field);
504 code += "\t\ta := rcv._tab.Vector(o)\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800505 code += "\t\treturn " +
506 CastToEnum(field.value.type,
507 GenGetter(field.value.type) +
508 "(a + flatbuffers.UOffsetT(j*" +
509 NumToString(InlineSize(vectortype)) + "))");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700510 code += "\n\t}\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800511 if (IsString(vectortype)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700512 code += "\treturn nil\n";
513 } else if (vectortype.base_type == BASE_TYPE_BOOL) {
514 code += "\treturn false\n";
515 } else {
516 code += "\treturn 0\n";
517 }
518 code += "}\n\n";
519 }
520
521 // Begin the creator function signature.
522 void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
523 std::string &code = *code_ptr;
524
525 if (code.substr(code.length() - 2) != "\n\n") {
526 // a previous mutate has not put an extra new line
527 code += "\n";
528 }
529 code += "func Create" + struct_def.name;
530 code += "(builder *flatbuffers.Builder";
531 }
532
533 // Recursively generate arguments for a constructor, to deal with nested
534 // structs.
535 void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
536 std::string *code_ptr) {
537 for (auto it = struct_def.fields.vec.begin();
538 it != struct_def.fields.vec.end(); ++it) {
539 auto &field = **it;
540 if (IsStruct(field.value.type)) {
541 // Generate arguments for a struct inside a struct. To ensure names
542 // don't clash, and to make it obvious these arguments are constructing
543 // a nested struct, prefix the name with the field name.
544 StructBuilderArgs(*field.value.type.struct_def,
545 (nameprefix + (field.name + "_")).c_str(), code_ptr);
546 } else {
547 std::string &code = *code_ptr;
548 code += std::string(", ") + nameprefix;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700549 code += namer_.Variable(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700550 code += " " + TypeName(field);
551 }
552 }
553 }
554
555 // End the creator function signature.
556 void EndBuilderArgs(std::string *code_ptr) {
557 std::string &code = *code_ptr;
558 code += ") flatbuffers.UOffsetT {\n";
559 }
560
561 // Recursively generate struct construction statements and instert manual
562 // padding.
Austin Schuh272c6132020-11-14 16:37:52 -0800563 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
564 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700565 std::string &code = *code_ptr;
566 code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
567 code += NumToString(struct_def.bytesize) + ")\n";
568 for (auto it = struct_def.fields.vec.rbegin();
569 it != struct_def.fields.vec.rend(); ++it) {
570 auto &field = **it;
571 if (field.padding)
572 code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
573 if (IsStruct(field.value.type)) {
574 StructBuilderBody(*field.value.type.struct_def,
575 (nameprefix + (field.name + "_")).c_str(), code_ptr);
576 } else {
577 code += "\tbuilder.Prepend" + GenMethod(field) + "(";
Austin Schuh272c6132020-11-14 16:37:52 -0800578 code += CastToBaseType(field.value.type,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700579 nameprefix + namer_.Variable(field)) +
Austin Schuh272c6132020-11-14 16:37:52 -0800580 ")\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700581 }
582 }
583 }
584
585 void EndBuilderBody(std::string *code_ptr) {
586 std::string &code = *code_ptr;
587 code += "\treturn builder.Offset()\n";
588 code += "}\n";
589 }
590
591 // Get the value of a table's starting offset.
592 void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
593 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700594 code += "func " + namer_.Type(struct_def) + "Start";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700595 code += "(builder *flatbuffers.Builder) {\n";
596 code += "\tbuilder.StartObject(";
597 code += NumToString(struct_def.fields.vec.size());
598 code += ")\n}\n";
599 }
600
601 // Set the value of a table's field.
602 void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
603 const size_t offset, std::string *code_ptr) {
604 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700605 const std::string field_var = namer_.Variable(field);
606 code += "func " + namer_.Type(struct_def) + "Add" + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700607 code += "(builder *flatbuffers.Builder, ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700608 code += field_var + " ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700609 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
610 code += "flatbuffers.UOffsetT";
611 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700612 code += GenTypeGet(field.value.type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700613 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700614 code += ") {\n\t";
615 code += "builder.Prepend";
616 code += GenMethod(field);
617 if (field.IsScalarOptional()) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700618 code += "(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700619 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700620 code += "Slot(" + NumToString(offset) + ", ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700621 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700622 if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
623 code += "flatbuffers.UOffsetT";
624 code += "(" + field_var + ")";
625 } else {
626 code += CastToBaseType(field.value.type, field_var);
627 }
628 if (field.IsScalarOptional()) {
629 code += ")\n";
630 code += "\tbuilder.Slot(" + NumToString(offset);
631 } else {
632 code += ", " + GenConstant(field);
633 }
634 code += ")\n";
635 code += "}\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700636 }
637
638 // Set the value of one of the members of a table's vector.
Austin Schuh272c6132020-11-14 16:37:52 -0800639 void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
640 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700641 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700642 code += "func " + namer_.Type(struct_def) + "Start";
643 code += namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700644 code += "Vector(builder *flatbuffers.Builder, numElems int) ";
645 code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
646 auto vector_type = field.value.type.VectorType();
647 auto alignment = InlineAlignment(vector_type);
648 auto elem_size = InlineSize(vector_type);
649 code += NumToString(elem_size);
650 code += ", numElems, " + NumToString(alignment);
651 code += ")\n}\n";
652 }
653
654 // Get the offset of the end of a table.
655 void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
656 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700657 code += "func " + namer_.Type(struct_def) + "End";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700658 code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
659 code += "{\n\treturn builder.EndObject()\n}\n";
660 }
661
662 // Generate the receiver for function signatures.
663 void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
664 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700665 code += "func (rcv *" + namer_.Type(struct_def) + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700666 }
667
668 // Generate a struct field getter, conditioned on its child type(s).
Austin Schuh272c6132020-11-14 16:37:52 -0800669 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
670 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700671 GenComment(field.doc_comment, code_ptr, nullptr, "");
672 if (IsScalar(field.value.type.base_type)) {
673 if (struct_def.fixed) {
674 GetScalarFieldOfStruct(struct_def, field, code_ptr);
675 } else {
676 GetScalarFieldOfTable(struct_def, field, code_ptr);
677 }
678 } else {
679 switch (field.value.type.base_type) {
680 case BASE_TYPE_STRUCT:
681 if (struct_def.fixed) {
682 GetStructFieldOfStruct(struct_def, field, code_ptr);
683 } else {
684 GetStructFieldOfTable(struct_def, field, code_ptr);
685 }
686 break;
Austin Schuh272c6132020-11-14 16:37:52 -0800687 case BASE_TYPE_STRING:
688 GetStringField(struct_def, field, code_ptr);
689 break;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700690 case BASE_TYPE_VECTOR: {
691 auto vectortype = field.value.type.VectorType();
692 if (vectortype.base_type == BASE_TYPE_STRUCT) {
693 GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
694 } else {
695 GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
696 }
697 break;
698 }
699 case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
700 default: FLATBUFFERS_ASSERT(0);
701 }
702 }
Austin Schuh272c6132020-11-14 16:37:52 -0800703 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700704 GetVectorLen(struct_def, field, code_ptr);
705 if (field.value.type.element == BASE_TYPE_UCHAR) {
706 GetUByteSlice(struct_def, field, code_ptr);
707 }
708 }
709 }
710
711 // Mutate the value of a struct's scalar.
712 void MutateScalarFieldOfStruct(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800713 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700714 std::string &code = *code_ptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700715 std::string setter =
716 "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(field.value.type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700717 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700718 code += " Mutate" + namer_.Function(field);
719 code +=
720 "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn " + setter;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700721 code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
722 code += NumToString(field.value.offset) + "), ";
723 code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
724 }
725
726 // Mutate the value of a table's scalar.
727 void MutateScalarFieldOfTable(const StructDef &struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800728 const FieldDef &field, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700729 std::string &code = *code_ptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700730 std::string setter = "rcv._tab.Mutate" +
731 namer_.Method(GenTypeBasic(field.value.type)) + "Slot";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700732 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700733 code += " Mutate" + namer_.Function(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700734 code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700735 code += setter + "(" + NumToString(field.value.offset) + ", ";
736 code += CastToBaseType(field.value.type, "n") + ")\n";
737 code += "}\n\n";
738 }
739
740 // Mutate an element of a vector of scalars.
741 void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
742 const FieldDef &field,
743 std::string *code_ptr) {
744 std::string &code = *code_ptr;
745 auto vectortype = field.value.type.VectorType();
James Kuszmaul8e62b022022-03-22 09:33:25 -0700746 std::string setter =
747 "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(vectortype));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700748 GenReceiver(struct_def, code_ptr);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700749 code += " Mutate" + namer_.Function(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700750 code += "(j int, n " + TypeName(field) + ") bool ";
751 code += OffsetPrefix(field);
752 code += "\t\ta := rcv._tab.Vector(o)\n";
753 code += "\t\treturn " + setter + "(";
754 code += "a+flatbuffers.UOffsetT(j*";
755 code += NumToString(InlineSize(vectortype)) + "), ";
756 code += CastToBaseType(vectortype, "n") + ")\n";
757 code += "\t}\n";
758 code += "\treturn false\n";
759 code += "}\n\n";
760 }
761
762 // Generate a struct field setter, conditioned on its child type(s).
763 void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
764 std::string *code_ptr) {
765 GenComment(field.doc_comment, code_ptr, nullptr, "");
766 if (IsScalar(field.value.type.base_type)) {
767 if (struct_def.fixed) {
768 MutateScalarFieldOfStruct(struct_def, field, code_ptr);
769 } else {
770 MutateScalarFieldOfTable(struct_def, field, code_ptr);
771 }
Austin Schuh272c6132020-11-14 16:37:52 -0800772 } else if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700773 if (IsScalar(field.value.type.element)) {
774 MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
775 }
776 }
777 }
778
779 // Generate table constructors, conditioned on its members' types.
780 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
781 GetStartOfTable(struct_def, code_ptr);
782
783 for (auto it = struct_def.fields.vec.begin();
784 it != struct_def.fields.vec.end(); ++it) {
785 auto &field = **it;
786 if (field.deprecated) continue;
787
788 auto offset = it - struct_def.fields.vec.begin();
789 BuildFieldOfTable(struct_def, field, offset, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800790 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700791 BuildVectorOfTable(struct_def, field, code_ptr);
792 }
793 }
794
795 GetEndOffsetOnTable(struct_def, code_ptr);
796 }
797
798 // Generate struct or table methods.
799 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
800 if (struct_def.generated) return;
801
802 cur_name_space_ = struct_def.defined_namespace;
803
804 GenComment(struct_def.doc_comment, code_ptr, nullptr);
Austin Schuh272c6132020-11-14 16:37:52 -0800805 if (parser_.opts.generate_object_based_api) {
806 GenNativeStruct(struct_def, code_ptr);
807 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700808 BeginClass(struct_def, code_ptr);
809 if (!struct_def.fixed) {
810 // Generate a special accessor for the table that has been declared as
811 // the root type.
812 NewRootTypeFromBuffer(struct_def, code_ptr);
813 }
814 // Generate the Init method that sets the field in a pre-existing
815 // accessor object. This is to allow object reuse.
816 InitializeExisting(struct_def, code_ptr);
817 // Generate _tab accessor
818 GenTableAccessor(struct_def, code_ptr);
819
820 // Generate struct fields accessors
821 for (auto it = struct_def.fields.vec.begin();
822 it != struct_def.fields.vec.end(); ++it) {
823 auto &field = **it;
824 if (field.deprecated) continue;
825
826 GenStructAccessor(struct_def, field, code_ptr);
827 GenStructMutator(struct_def, field, code_ptr);
828 }
829
830 // Generate builders
831 if (struct_def.fixed) {
832 // create a struct constructor function
833 GenStructBuilder(struct_def, code_ptr);
834 } else {
835 // Create a set of functions that allow table construction.
836 GenTableBuilders(struct_def, code_ptr);
837 }
838 }
839
Austin Schuh272c6132020-11-14 16:37:52 -0800840 void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) {
841 std::string &code = *code_ptr;
842
843 code += "type " + NativeName(struct_def) + " struct {\n";
844 for (auto it = struct_def.fields.vec.begin();
845 it != struct_def.fields.vec.end(); ++it) {
846 const FieldDef &field = **it;
847 if (field.deprecated) continue;
848 if (IsScalar(field.value.type.base_type) &&
849 field.value.type.enum_def != nullptr &&
850 field.value.type.enum_def->is_union)
851 continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700852 code += "\t" + namer_.Field(field) + " ";
853 if (field.IsScalarOptional()) { code += "*"; }
854 code += NativeType(field.value.type) + " `json:\"" + field.name + "\"`" +
855 "\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800856 }
857 code += "}\n\n";
858
859 if (!struct_def.fixed) {
860 GenNativeTablePack(struct_def, code_ptr);
861 GenNativeTableUnPack(struct_def, code_ptr);
862 } else {
863 GenNativeStructPack(struct_def, code_ptr);
864 GenNativeStructUnPack(struct_def, code_ptr);
865 }
866 }
867
868 void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) {
869 std::string &code = *code_ptr;
870 code += "type " + NativeName(enum_def) + " struct {\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700871 code += "\tType " + namer_.Type(enum_def) + "\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800872 code += "\tValue interface{}\n";
873 code += "}\n\n";
874 }
875
876 void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) {
877 std::string &code = *code_ptr;
878 code += "func (t *" + NativeName(enum_def) +
879 ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
880 code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
881
882 code += "\tswitch t.Type {\n";
883 for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
884 ++it2) {
885 const EnumVal &ev = **it2;
886 if (ev.IsZero()) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700887 code += "\tcase " + namer_.EnumVariant(enum_def, ev) + ":\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800888 code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
889 ").Pack(builder)\n";
890 }
891 code += "\t}\n";
892 code += "\treturn 0\n";
893 code += "}\n\n";
894 }
895
896 void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) {
897 std::string &code = *code_ptr;
898
Austin Schuh2dd86a92022-09-14 21:19:23 -0700899 code += "func (rcv " + namer_.Type(enum_def) +
Austin Schuh272c6132020-11-14 16:37:52 -0800900 ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
901 " {\n";
902 code += "\tswitch rcv {\n";
903
904 for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
905 ++it2) {
906 const EnumVal &ev = **it2;
907 if (ev.IsZero()) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700908 code += "\tcase " + namer_.EnumVariant(enum_def, ev) + ":\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800909 code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n";
910
911 code += "\t\treturn &" +
912 WrapInNameSpaceAndTrack(enum_def.defined_namespace,
913 NativeName(enum_def)) +
Austin Schuh2dd86a92022-09-14 21:19:23 -0700914 "{ Type: " + namer_.EnumVariant(enum_def, ev) +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700915 ", Value: x.UnPack() }\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800916 }
917 code += "\t}\n";
918 code += "\treturn nil\n";
919 code += "}\n\n";
920 }
921
922 void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) {
923 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700924 const std::string struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800925
926 code += "func (t *" + NativeName(struct_def) +
927 ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
928 code += "\tif t == nil { return 0 }\n";
929 for (auto it = struct_def.fields.vec.begin();
930 it != struct_def.fields.vec.end(); ++it) {
931 const FieldDef &field = **it;
932 if (field.deprecated) continue;
933 if (IsScalar(field.value.type.base_type)) continue;
934
Austin Schuh2dd86a92022-09-14 21:19:23 -0700935 const std::string field_field = namer_.Field(field);
936 const std::string field_var = namer_.Variable(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700937 const std::string offset = field_var + "Offset";
Austin Schuh272c6132020-11-14 16:37:52 -0800938
939 if (IsString(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700940 code +=
941 "\t" + offset + " := builder.CreateString(t." + field_field + ")\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800942 } else if (IsVector(field.value.type) &&
943 field.value.type.element == BASE_TYPE_UCHAR &&
944 field.value.type.enum_def == nullptr) {
945 code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700946 code += "\tif t." + field_field + " != nil {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800947 code += "\t\t" + offset + " = builder.CreateByteString(t." +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700948 field_field + ")\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800949 code += "\t}\n";
950 } else if (IsVector(field.value.type)) {
951 code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700952 code += "\tif t." + field_field + " != nil {\n";
953 std::string length = field_var + "Length";
954 std::string offsets = field_var + "Offsets";
955 code += "\t\t" + length + " := len(t." + field_field + ")\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800956 if (field.value.type.element == BASE_TYPE_STRING) {
957 code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
958 length + ")\n";
959 code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
960 code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700961 field_field + "[j])\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800962 code += "\t\t}\n";
963 } else if (field.value.type.element == BASE_TYPE_STRUCT &&
964 !field.value.type.struct_def->fixed) {
965 code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
966 length + ")\n";
967 code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700968 code += "\t\t\t" + offsets + "[j] = t." + field_field +
Austin Schuh272c6132020-11-14 16:37:52 -0800969 "[j].Pack(builder)\n";
970 code += "\t\t}\n";
971 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700972 code += "\t\t" + struct_type + "Start" + namer_.Function(field) +
Austin Schuh272c6132020-11-14 16:37:52 -0800973 "Vector(builder, " + length + ")\n";
974 code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
975 if (IsScalar(field.value.type.element)) {
976 code += "\t\t\tbuilder.Prepend" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700977 namer_.Method(GenTypeBasic(field.value.type.VectorType())) +
978 "(" +
Austin Schuh272c6132020-11-14 16:37:52 -0800979 CastToBaseType(field.value.type.VectorType(),
James Kuszmaul8e62b022022-03-22 09:33:25 -0700980 "t." + field_field + "[j]") +
Austin Schuh272c6132020-11-14 16:37:52 -0800981 ")\n";
982 } else if (field.value.type.element == BASE_TYPE_STRUCT &&
983 field.value.type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700984 code += "\t\t\tt." + field_field + "[j].Pack(builder)\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800985 } else {
986 code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
987 }
988 code += "\t\t}\n";
989 code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
990 code += "\t}\n";
991 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
992 if (field.value.type.struct_def->fixed) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700993 code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800994 } else if (field.value.type.base_type == BASE_TYPE_UNION) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700995 code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800996 code += "\t\n";
997 } else {
998 FLATBUFFERS_ASSERT(0);
999 }
1000 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001001 code += "\t" + struct_type + "Start(builder)\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001002 for (auto it = struct_def.fields.vec.begin();
1003 it != struct_def.fields.vec.end(); ++it) {
1004 const FieldDef &field = **it;
1005 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001006 const std::string field_field = namer_.Field(field);
1007 const std::string field_fn = namer_.Function(field);
1008 const std::string offset = namer_.Variable(field) + "Offset";
Austin Schuh272c6132020-11-14 16:37:52 -08001009
Austin Schuh272c6132020-11-14 16:37:52 -08001010 if (IsScalar(field.value.type.base_type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001011 std::string prefix;
1012 if (field.IsScalarOptional()) {
1013 code += "\tif t." + field_field + " != nil {\n\t";
1014 prefix = "*";
1015 }
Austin Schuh272c6132020-11-14 16:37:52 -08001016 if (field.value.type.enum_def == nullptr ||
1017 !field.value.type.enum_def->is_union) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001018 code += "\t" + struct_type + "Add" + field_fn + "(builder, " +
1019 prefix + "t." + field_field + ")\n";
1020 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001021 if (field.IsScalarOptional()) { code += "\t}\n"; }
Austin Schuh272c6132020-11-14 16:37:52 -08001022 } else {
1023 if (field.value.type.base_type == BASE_TYPE_STRUCT &&
1024 field.value.type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001025 code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001026 } else if (field.value.type.enum_def != nullptr &&
1027 field.value.type.enum_def->is_union) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001028 code += "\tif t." + field_field + " != nil {\n";
1029 code += "\t\t" + struct_type + "Add" +
1030 namer_.Method(field.name + UnionTypeFieldSuffix()) +
1031 "(builder, t." + field_field + ".Type)\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001032 code += "\t}\n";
1033 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001034 code += "\t" + struct_type + "Add" + field_fn + "(builder, " + offset +
1035 ")\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001036 }
1037 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001038 code += "\treturn " + struct_type + "End(builder)\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001039 code += "}\n\n";
1040 }
1041
1042 void GenNativeTableUnPack(const StructDef &struct_def,
1043 std::string *code_ptr) {
1044 std::string &code = *code_ptr;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001045 const std::string struct_type = namer_.Type(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001046
James Kuszmaul8e62b022022-03-22 09:33:25 -07001047 code += "func (rcv *" + struct_type + ") UnPackTo(t *" +
Austin Schuh272c6132020-11-14 16:37:52 -08001048 NativeName(struct_def) + ") {\n";
1049 for (auto it = struct_def.fields.vec.begin();
1050 it != struct_def.fields.vec.end(); ++it) {
1051 const FieldDef &field = **it;
1052 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001053 const std::string field_field = namer_.Field(field);
1054 const std::string field_var = namer_.Variable(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001055 const std::string length = field_var + "Length";
Austin Schuh272c6132020-11-14 16:37:52 -08001056 if (IsScalar(field.value.type.base_type)) {
1057 if (field.value.type.enum_def != nullptr &&
1058 field.value.type.enum_def->is_union)
1059 continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001060 code += "\tt." + field_field + " = rcv." + field_field + "()\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001061 } else if (IsString(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001062 code += "\tt." + field_field + " = string(rcv." + field_field + "())\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001063 } else if (IsVector(field.value.type) &&
1064 field.value.type.element == BASE_TYPE_UCHAR &&
1065 field.value.type.enum_def == nullptr) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001066 code += "\tt." + field_field + " = rcv." + field_field + "Bytes()\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001067 } else if (IsVector(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001068 code += "\t" + length + " := rcv." + field_field + "Length()\n";
1069 code += "\tt." + field_field + " = make(" +
Austin Schuh272c6132020-11-14 16:37:52 -08001070 NativeType(field.value.type) + ", " + length + ")\n";
1071 code += "\tfor j := 0; j < " + length + "; j++ {\n";
1072 if (field.value.type.element == BASE_TYPE_STRUCT) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001073 code += "\t\tx := " +
1074 WrapInNameSpaceAndTrack(*field.value.type.struct_def) +
1075 "{}\n";
1076 code += "\t\trcv." + field_field + "(&x, j)\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001077 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001078 code += "\t\tt." + field_field + "[j] = ";
Austin Schuh272c6132020-11-14 16:37:52 -08001079 if (IsScalar(field.value.type.element)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001080 code += "rcv." + field_field + "(j)";
Austin Schuh272c6132020-11-14 16:37:52 -08001081 } else if (field.value.type.element == BASE_TYPE_STRING) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001082 code += "string(rcv." + field_field + "(j))";
Austin Schuh272c6132020-11-14 16:37:52 -08001083 } else if (field.value.type.element == BASE_TYPE_STRUCT) {
1084 code += "x.UnPack()";
1085 } else {
1086 // TODO(iceboy): Support vector of unions.
1087 FLATBUFFERS_ASSERT(0);
1088 }
1089 code += "\n";
1090 code += "\t}\n";
1091 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
Austin Schuh272c6132020-11-14 16:37:52 -08001092 code +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07001093 "\tt." + field_field + " = rcv." + field_field + "(nil).UnPack()\n";
1094 } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1095 const std::string field_table = field_var + "Table";
1096 code += "\t" + field_table + " := flatbuffers.Table{}\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001097 code +=
1098 "\tif rcv." + namer_.Method(field) + "(&" + field_table + ") {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001099 code += "\t\tt." + field_field + " = rcv." +
1100 namer_.Method(field.name + UnionTypeFieldSuffix()) +
1101 "().UnPack(" + field_table + ")\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001102 code += "\t}\n";
1103 } else {
1104 FLATBUFFERS_ASSERT(0);
1105 }
1106 }
1107 code += "}\n\n";
1108
James Kuszmaul8e62b022022-03-22 09:33:25 -07001109 code += "func (rcv *" + struct_type + ") UnPack() *" +
Austin Schuh272c6132020-11-14 16:37:52 -08001110 NativeName(struct_def) + " {\n";
1111 code += "\tif rcv == nil { return nil }\n";
1112 code += "\tt := &" + NativeName(struct_def) + "{}\n";
1113 code += "\trcv.UnPackTo(t)\n";
1114 code += "\treturn t\n";
1115 code += "}\n\n";
1116 }
1117
1118 void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) {
1119 std::string &code = *code_ptr;
1120
1121 code += "func (t *" + NativeName(struct_def) +
1122 ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1123 code += "\tif t == nil { return 0 }\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001124 code += "\treturn Create" + namer_.Type(struct_def) + "(builder";
Austin Schuh272c6132020-11-14 16:37:52 -08001125 StructPackArgs(struct_def, "", code_ptr);
1126 code += ")\n";
1127 code += "}\n";
1128 }
1129
1130 void StructPackArgs(const StructDef &struct_def, const char *nameprefix,
1131 std::string *code_ptr) {
1132 std::string &code = *code_ptr;
1133 for (auto it = struct_def.fields.vec.begin();
1134 it != struct_def.fields.vec.end(); ++it) {
1135 const FieldDef &field = **it;
1136 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1137 StructPackArgs(*field.value.type.struct_def,
Austin Schuh2dd86a92022-09-14 21:19:23 -07001138 (nameprefix + namer_.Field(field) + ".").c_str(),
Austin Schuh272c6132020-11-14 16:37:52 -08001139 code_ptr);
1140 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001141 code += std::string(", t.") + nameprefix + namer_.Field(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001142 }
1143 }
1144 }
1145
1146 void GenNativeStructUnPack(const StructDef &struct_def,
1147 std::string *code_ptr) {
1148 std::string &code = *code_ptr;
1149
Austin Schuh2dd86a92022-09-14 21:19:23 -07001150 code += "func (rcv *" + namer_.Type(struct_def) + ") UnPackTo(t *" +
Austin Schuh272c6132020-11-14 16:37:52 -08001151 NativeName(struct_def) + ") {\n";
1152 for (auto it = struct_def.fields.vec.begin();
1153 it != struct_def.fields.vec.end(); ++it) {
1154 const FieldDef &field = **it;
1155 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001156 code += "\tt." + namer_.Field(field) + " = rcv." +
1157 namer_.Method(field) + "(nil).UnPack()\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001158 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001159 code += "\tt." + namer_.Field(field) + " = rcv." +
1160 namer_.Method(field) + "()\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001161 }
1162 }
1163 code += "}\n\n";
1164
Austin Schuh2dd86a92022-09-14 21:19:23 -07001165 code += "func (rcv *" + namer_.Type(struct_def) + ") UnPack() *" +
Austin Schuh272c6132020-11-14 16:37:52 -08001166 NativeName(struct_def) + " {\n";
1167 code += "\tif rcv == nil { return nil }\n";
1168 code += "\tt := &" + NativeName(struct_def) + "{}\n";
1169 code += "\trcv.UnPackTo(t)\n";
1170 code += "\treturn t\n";
1171 code += "}\n\n";
1172 }
1173
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001174 // Generate enum declarations.
1175 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1176 if (enum_def.generated) return;
1177
1178 auto max_name_length = MaxNameLength(enum_def);
1179 cur_name_space_ = enum_def.defined_namespace;
1180
1181 GenComment(enum_def.doc_comment, code_ptr, nullptr);
1182 GenEnumType(enum_def, code_ptr);
1183 BeginEnum(code_ptr);
1184 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuh272c6132020-11-14 16:37:52 -08001185 const EnumVal &ev = **it;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001186 GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
1187 EnumMember(enum_def, ev, max_name_length, code_ptr);
1188 }
1189 EndEnum(code_ptr);
1190
1191 BeginEnumNames(enum_def, code_ptr);
1192 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuh272c6132020-11-14 16:37:52 -08001193 const EnumVal &ev = **it;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001194 EnumNameMember(enum_def, ev, max_name_length, code_ptr);
1195 }
1196 EndEnumNames(code_ptr);
1197
1198 BeginEnumValues(enum_def, code_ptr);
Austin Schuh272c6132020-11-14 16:37:52 -08001199 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001200 auto &ev = **it;
1201 EnumValueMember(enum_def, ev, max_name_length, code_ptr);
1202 }
1203 EndEnumValues(code_ptr);
1204
1205 EnumStringer(enum_def, code_ptr);
1206 }
1207
1208 // Returns the function name that is able to read a value of the given type.
1209 std::string GenGetter(const Type &type) {
1210 switch (type.base_type) {
1211 case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
1212 case BASE_TYPE_UNION: return "rcv._tab.Union";
1213 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -07001214 default: return "rcv._tab.Get" + namer_.Function(GenTypeBasic(type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001215 }
1216 }
1217
1218 // Returns the method name for use with add/put calls.
1219 std::string GenMethod(const FieldDef &field) {
1220 return IsScalar(field.value.type.base_type)
James Kuszmaul8e62b022022-03-22 09:33:25 -07001221 ? namer_.Method(GenTypeBasic(field.value.type))
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001222 : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
1223 }
1224
1225 std::string GenTypeBasic(const Type &type) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001226 // clang-format off
Austin Schuh272c6132020-11-14 16:37:52 -08001227 static const char *ctypename[] = {
1228 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001229 #GTYPE,
1230 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1231 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001232 };
Austin Schuh272c6132020-11-14 16:37:52 -08001233 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001234 return ctypename[type.base_type];
1235 }
1236
1237 std::string GenTypePointer(const Type &type) {
1238 switch (type.base_type) {
1239 case BASE_TYPE_STRING: return "[]byte";
1240 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1241 case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def);
1242 case BASE_TYPE_UNION:
1243 // fall through
1244 default: return "*flatbuffers.Table";
1245 }
1246 }
1247
1248 std::string GenTypeGet(const Type &type) {
Austin Schuh272c6132020-11-14 16:37:52 -08001249 if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001250 return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1251 }
1252
1253 std::string TypeName(const FieldDef &field) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001254 std::string prefix;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001255 if (field.IsScalarOptional()) { prefix = "*"; }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001256 return prefix + GenTypeGet(field.value.type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001257 }
1258
1259 // If type is an enum, returns value with a cast to the enum type, otherwise
1260 // returns value as-is.
1261 std::string CastToEnum(const Type &type, std::string value) {
1262 if (type.enum_def == nullptr) {
1263 return value;
1264 } else {
1265 return GenTypeGet(type) + "(" + value + ")";
1266 }
1267 }
1268
1269 // If type is an enum, returns value with a cast to the enum base type,
1270 // otherwise returns value as-is.
1271 std::string CastToBaseType(const Type &type, std::string value) {
1272 if (type.enum_def == nullptr) {
1273 return value;
1274 } else {
1275 return GenTypeBasic(type) + "(" + value + ")";
1276 }
1277 }
1278
1279 std::string GenConstant(const FieldDef &field) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001280 if (field.IsScalarOptional()) { return "nil"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001281 switch (field.value.type.base_type) {
Austin Schuh272c6132020-11-14 16:37:52 -08001282 case BASE_TYPE_BOOL:
1283 return field.value.constant == "0" ? "false" : "true";
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001284 case BASE_TYPE_FLOAT:
1285 case BASE_TYPE_DOUBLE: {
1286 const std::string float_type =
1287 field.value.type.base_type == BASE_TYPE_FLOAT ? "float32"
1288 : "float64";
1289 if (StringIsFlatbufferNan(field.value.constant)) {
1290 needs_math_import_ = true;
1291 return float_type + "(math.NaN())";
1292 } else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
1293 needs_math_import_ = true;
1294 return float_type + "(math.Inf(1))";
1295 } else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
1296 needs_math_import_ = true;
1297 return float_type + "(math.Inf(-1))";
1298 }
1299 return field.value.constant;
1300 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001301 default: return field.value.constant;
1302 }
1303 }
1304
James Kuszmaul8e62b022022-03-22 09:33:25 -07001305 std::string NativeName(const StructDef &struct_def) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001306 return namer_.ObjectType(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001307 }
1308
James Kuszmaul8e62b022022-03-22 09:33:25 -07001309 std::string NativeName(const EnumDef &enum_def) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001310 return namer_.ObjectType(enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001311 }
1312
1313 std::string NativeType(const Type &type) {
1314 if (IsScalar(type.base_type)) {
1315 if (type.enum_def == nullptr) {
1316 return GenTypeBasic(type);
1317 } else {
1318 return GetEnumTypeName(*type.enum_def);
1319 }
1320 } else if (IsString(type)) {
1321 return "string";
1322 } else if (IsVector(type)) {
1323 return "[]" + NativeType(type.VectorType());
1324 } else if (type.base_type == BASE_TYPE_STRUCT) {
1325 return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace,
1326 NativeName(*type.struct_def));
1327 } else if (type.base_type == BASE_TYPE_UNION) {
1328 return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace,
1329 NativeName(*type.enum_def));
1330 }
1331 FLATBUFFERS_ASSERT(0);
1332 return std::string();
1333 }
1334
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001335 // Create a struct with a builder and the struct's arguments.
1336 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
1337 BeginBuilderArgs(struct_def, code_ptr);
1338 StructBuilderArgs(struct_def, "", code_ptr);
1339 EndBuilderArgs(code_ptr);
1340
1341 StructBuilderBody(struct_def, "", code_ptr);
1342 EndBuilderBody(code_ptr);
1343 }
1344 // Begin by declaring namespace and imports.
1345 void BeginFile(const std::string &name_space_name, const bool needs_imports,
1346 const bool is_enum, std::string *code_ptr) {
1347 std::string &code = *code_ptr;
Austin Schuh272c6132020-11-14 16:37:52 -08001348 code = code +
1349 "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001350 code += "package " + name_space_name + "\n\n";
1351 if (needs_imports) {
1352 code += "import (\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001353 if (is_enum) { code += "\t\"strconv\"\n\n"; }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001354 // math is needed to support non-finite scalar default values.
1355 if (needs_math_import_) { code += "\t\"math\"\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001356 if (!parser_.opts.go_import.empty()) {
1357 code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
1358 } else {
1359 code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
1360 }
1361 if (tracked_imported_namespaces_.size() > 0) {
1362 code += "\n";
1363 for (auto it = tracked_imported_namespaces_.begin();
Austin Schuh272c6132020-11-14 16:37:52 -08001364 it != tracked_imported_namespaces_.end(); ++it) {
1365 code += "\t" + NamespaceImportName(*it) + " \"" +
1366 NamespaceImportPath(*it) + "\"\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001367 }
1368 }
1369 code += ")\n\n";
1370 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08001371 if (is_enum) { code += "import \"strconv\"\n\n"; }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001372 if (needs_math_import_) {
1373 // math is needed to support non-finite scalar default values.
1374 code += "import \"math\"\n\n";
1375 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001376 }
1377 }
1378
1379 // Save out the generated code for a Go Table type.
1380 bool SaveType(const Definition &def, const std::string &classcode,
1381 const bool needs_imports, const bool is_enum) {
1382 if (!classcode.length()) return true;
1383
1384 Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
1385 : go_namespace_;
1386 std::string code = "";
1387 BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
1388 code += classcode;
1389 // Strip extra newlines at end of file to make it gofmt-clean.
1390 while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
1391 code.pop_back();
1392 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001393 std::string directory = namer_.Directories(ns);
1394 std::string file = namer_.File(def, SkipFile::Suffix);
1395 EnsureDirExists(directory);
1396 std::string filename = directory + file;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001397 return SaveFile(filename.c_str(), code, false);
1398 }
1399
1400 // Create the full name of the imported namespace (format: A__B__C).
James Kuszmaul8e62b022022-03-22 09:33:25 -07001401 std::string NamespaceImportName(const Namespace *ns) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001402 return namer_.Namespace(*ns);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001403 }
1404
1405 // Create the full path for the imported namespace (format: A/B/C).
James Kuszmaul8e62b022022-03-22 09:33:25 -07001406 std::string NamespaceImportPath(const Namespace *ns) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001407 return namer_.Directories(*ns, SkipDir::OutputPathAndTrailingPathSeparator);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001408 }
1409
1410 // Ensure that a type is prefixed with its go package import name if it is
1411 // used outside of its namespace.
1412 std::string WrapInNameSpaceAndTrack(const Namespace *ns,
1413 const std::string &name) {
1414 if (CurrentNameSpace() == ns) return name;
1415
1416 tracked_imported_namespaces_.insert(ns);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001417 return NamespaceImportName(ns) + "." + name;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001418 }
1419
1420 std::string WrapInNameSpaceAndTrack(const Definition &def) {
1421 return WrapInNameSpaceAndTrack(def.defined_namespace, def.name);
1422 }
1423
1424 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
1425
1426 static size_t MaxNameLength(const EnumDef &enum_def) {
1427 size_t max = 0;
Austin Schuh272c6132020-11-14 16:37:52 -08001428 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001429 max = std::max((*it)->name.length(), max);
1430 }
1431 return max;
1432 }
1433};
1434} // namespace go
1435
1436bool GenerateGo(const Parser &parser, const std::string &path,
1437 const std::string &file_name) {
1438 go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
1439 return generator.generate();
1440}
1441
1442} // namespace flatbuffers