Coverage Report

Created: 2026-05-30 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/flatbuffers/src/idl_gen_go.cpp
Line
Count
Source
1
/*
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
19
#include "idl_gen_go.h"
20
21
#include <algorithm>
22
#include <cmath>
23
#include <sstream>
24
#include <string>
25
26
#include "flatbuffers/base.h"
27
#include "flatbuffers/code_generators.h"
28
#include "flatbuffers/flatbuffers.h"
29
#include "flatbuffers/idl.h"
30
#include "flatbuffers/util.h"
31
#include "idl_namer.h"
32
33
#ifdef _WIN32
34
#include <direct.h>
35
#define PATH_SEPARATOR "\\"
36
#define mkdir(n, m) _mkdir(n)
37
#else
38
#include <sys/stat.h>
39
#define PATH_SEPARATOR "/"
40
#endif
41
42
namespace flatbuffers {
43
44
namespace go {
45
46
namespace {
47
48
// see https://golang.org/ref/spec#Keywords
49
0
static std::set<std::string> GoKeywords() {
50
0
  return {
51
0
      "break",    "default",     "func",   "interface", "select",
52
0
      "case",     "defer",       "go",     "map",       "struct",
53
0
      "chan",     "else",        "goto",   "package",   "switch",
54
0
      "const",    "fallthrough", "if",     "range",     "type",
55
0
      "continue", "for",         "import", "return",    "var",
56
0
  };
57
0
}
58
59
0
static Namer::Config GoDefaultConfig() {
60
  // Note that the functions with user defined types in the name use
61
  // upper camel case for all but the user defined type itself, which is keep
62
  // cased. Despite being a function, we interpret it as a Type.
63
0
  return {/*types=*/Case::kKeep,
64
0
          /*constants=*/Case::kUnknown,
65
0
          /*methods=*/Case::kUpperCamel,
66
0
          /*functions=*/Case::kUpperCamel,
67
0
          /*fields=*/Case::kUpperCamel,
68
0
          /*variables=*/Case::kLowerCamel,
69
0
          /*variants=*/Case::kKeep,
70
0
          /*enum_variant_seperator=*/"",  // I.e. Concatenate.
71
0
          /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
72
0
          /*namespaces=*/Case::kKeep,
73
0
          /*namespace_seperator=*/"__",
74
0
          /*object_prefix=*/"",
75
0
          /*object_suffix=*/"T",
76
0
          /*keyword_prefix=*/"",
77
0
          /*keyword_suffix=*/"_",
78
0
          /*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
79
0
          /*filenames=*/Case::kKeep,
80
0
          /*directories=*/Case::kKeep,
81
0
          /*output_path=*/"",
82
0
          /*filename_suffix=*/"",
83
0
          /*filename_extension=*/".go"};
84
0
}
85
86
}  // namespace
87
88
class GoGenerator : public BaseGenerator {
89
 public:
90
  GoGenerator(const Parser& parser, const std::string& path,
91
              const std::string& file_name, const std::string& go_namespace)
92
0
      : BaseGenerator(parser, path, file_name, "" /* not used*/,
93
0
                      "" /* not used */, "go"),
94
0
        cur_name_space_(nullptr),
95
0
        namer_(WithFlagOptions(GoDefaultConfig(), parser.opts, path),
96
0
               GoKeywords()) {
97
0
    std::istringstream iss(go_namespace);
98
0
    std::string component;
99
0
    while (std::getline(iss, component, '.')) {
100
0
      go_namespace_.components.push_back(component);
101
0
    }
102
0
  }
103
104
0
  bool generate() {
105
0
    std::string one_file_code;
106
107
0
    if (!generateEnums(&one_file_code)) return false;
108
0
    if (!generateStructs(&one_file_code)) return false;
109
110
0
    if (parser_.opts.one_file) {
111
0
      std::string code = "";
112
0
      const bool is_enum = !parser_.enums_.vec.empty();
113
0
      BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
114
0
      code += one_file_code;
115
0
      const std::string filename =
116
0
          GeneratedFileName(path_, file_name_, parser_.opts);
117
0
      return parser_.opts.file_saver->SaveFile(filename.c_str(), code, false);
118
0
    }
119
120
0
    return true;
121
0
  }
122
123
 private:
124
0
  bool generateEnums(std::string* one_file_code) {
125
0
    bool needs_imports = false;
126
0
    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
127
0
         ++it) {
128
0
      if (!parser_.opts.one_file) {
129
0
        needs_imports = false;
130
0
        ResetImports();
131
0
      }
132
0
      auto& enum_def = **it;
133
0
      std::string enumcode;
134
0
      GenEnum(enum_def, &enumcode);
135
0
      if (enum_def.is_union && parser_.opts.generate_object_based_api) {
136
0
        GenNativeUnionCreator(enum_def, &enumcode);
137
0
        needs_imports = true;
138
0
      }
139
0
      if (parser_.opts.one_file) {
140
0
        *one_file_code += enumcode;
141
0
      } else {
142
0
        if (!SaveType(enum_def, enumcode, needs_imports, true)) return false;
143
0
      }
144
0
    }
145
0
    return true;
146
0
  }
147
148
0
  void GenNativeUnionCreator(const EnumDef& enum_def, std::string* code_ptr) {
149
0
    if (enum_def.generated) return;
150
151
0
    GenNativeUnion(enum_def, code_ptr);
152
0
    GenNativeUnionPack(enum_def, code_ptr);
153
0
    GenNativeUnionUnPack(enum_def, code_ptr);
154
0
  }
155
156
0
  bool generateStructs(std::string* one_file_code) {
157
0
    for (auto it = parser_.structs_.vec.begin();
158
0
         it != parser_.structs_.vec.end(); ++it) {
159
0
      if (!parser_.opts.one_file) {
160
0
        ResetImports();
161
0
      }
162
0
      std::string declcode;
163
0
      auto& struct_def = **it;
164
0
      GenStruct(struct_def, &declcode);
165
0
      if (parser_.opts.one_file) {
166
0
        *one_file_code += declcode;
167
0
      } else {
168
0
        if (!SaveType(struct_def, declcode, true, false)) return false;
169
0
      }
170
0
    }
171
0
    return true;
172
0
  }
173
174
  Namespace go_namespace_;
175
  Namespace* cur_name_space_;
176
  const IdlNamer namer_;
177
178
  struct NamespacePtrLess {
179
0
    bool operator()(const Definition* a, const Definition* b) const {
180
0
      return *a->defined_namespace < *b->defined_namespace;
181
0
    }
182
  };
183
  std::set<const Definition*, NamespacePtrLess> tracked_imported_namespaces_;
184
  bool needs_math_import_ = false;
185
  bool needs_bytes_import_ = false;
186
187
  // Most field accessors need to retrieve and test the field offset first,
188
  // this is the prefix code for that.
189
0
  std::string OffsetPrefix(const FieldDef& field) {
190
0
    return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
191
0
           NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
192
0
  }
193
194
  // Begin a class declaration.
195
0
  void BeginClass(const StructDef& struct_def, std::string* code_ptr) {
196
0
    std::string& code = *code_ptr;
197
198
0
    code += "type " + namer_.Type(struct_def) + " struct {\n\t";
199
200
    // _ is reserved in flatbuffers field names, so no chance of name
201
    // conflict:
202
0
    code += "_tab ";
203
0
    code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
204
0
    code += "\n}\n\n";
205
0
  }
206
207
  // Construct the name of the type for this enum.
208
0
  std::string GetEnumTypeName(const EnumDef& enum_def) {
209
0
    return WrapInNameSpaceAndTrack(&enum_def, namer_.Type(enum_def));
210
0
  }
211
212
  // Create a type for the enum values.
213
0
  void GenEnumType(const EnumDef& enum_def, std::string* code_ptr) {
214
0
    std::string& code = *code_ptr;
215
0
    code += "type " + GetEnumTypeName(enum_def) + " ";
216
0
    code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
217
0
  }
218
219
  // Begin enum code with a class declaration.
220
0
  void BeginEnum(std::string* code_ptr) {
221
0
    std::string& code = *code_ptr;
222
0
    code += "const (\n";
223
0
  }
224
225
  // A single enum member.
226
  void EnumMember(const EnumDef& enum_def, const EnumVal& ev,
227
0
                  size_t max_name_length, std::string* code_ptr) {
228
0
    std::string& code = *code_ptr;
229
0
    code += "\t";
230
0
    code += namer_.EnumVariant(enum_def, ev);
231
0
    code += " ";
232
0
    code += std::string(max_name_length - ev.name.length(), ' ');
233
0
    code += GetEnumTypeName(enum_def);
234
0
    code += " = ";
235
0
    code += enum_def.ToString(ev) + "\n";
236
0
  }
237
238
  // End enum code.
239
0
  void EndEnum(std::string* code_ptr) {
240
0
    std::string& code = *code_ptr;
241
0
    code += ")\n\n";
242
0
  }
243
244
  // Begin enum name map.
245
0
  void BeginEnumNames(const EnumDef& enum_def, std::string* code_ptr) {
246
0
    std::string& code = *code_ptr;
247
0
    code += "var EnumNames";
248
0
    code += enum_def.name;
249
0
    code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
250
0
  }
251
252
  // A single enum name member.
253
  void EnumNameMember(const EnumDef& enum_def, const EnumVal& ev,
254
0
                      size_t max_name_length, std::string* code_ptr) {
255
0
    std::string& code = *code_ptr;
256
0
    code += "\t";
257
0
    code += namer_.EnumVariant(enum_def, ev);
258
0
    code += ": ";
259
0
    code += std::string(max_name_length - ev.name.length(), ' ');
260
0
    code += "\"";
261
0
    code += ev.name;
262
0
    code += "\",\n";
263
0
  }
264
265
  // End enum name map.
266
0
  void EndEnumNames(std::string* code_ptr) {
267
0
    std::string& code = *code_ptr;
268
0
    code += "}\n\n";
269
0
  }
270
271
  // Generate String() method on enum type.
272
0
  void EnumStringer(const EnumDef& enum_def, std::string* code_ptr) {
273
0
    std::string& code = *code_ptr;
274
0
    const std::string enum_type = namer_.Type(enum_def);
275
0
    code += "func (v " + enum_type + ") String() string {\n";
276
0
    code += "\tif s, ok := EnumNames" + enum_type + "[v]; ok {\n";
277
0
    code += "\t\treturn s\n";
278
0
    code += "\t}\n";
279
0
    code += "\treturn \"" + enum_def.name;
280
0
    code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
281
0
    code += "}\n\n";
282
0
  }
283
284
  // Begin enum value map.
285
0
  void BeginEnumValues(const EnumDef& enum_def, std::string* code_ptr) {
286
0
    std::string& code = *code_ptr;
287
0
    code += "var EnumValues";
288
0
    code += namer_.Type(enum_def);
289
0
    code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
290
0
  }
291
292
  // A single enum value member.
293
  void EnumValueMember(const EnumDef& enum_def, const EnumVal& ev,
294
0
                       size_t max_name_length, std::string* code_ptr) {
295
0
    std::string& code = *code_ptr;
296
0
    code += "\t\"";
297
0
    code += ev.name;
298
0
    code += "\": ";
299
0
    code += std::string(max_name_length - ev.name.length(), ' ');
300
0
    code += namer_.EnumVariant(enum_def, ev);
301
0
    code += ",\n";
302
0
  }
303
304
  // End enum value map.
305
0
  void EndEnumValues(std::string* code_ptr) {
306
0
    std::string& code = *code_ptr;
307
0
    code += "}\n\n";
308
0
  }
309
310
  // Initialize a new struct or table from existing data.
311
  void NewRootTypeFromBuffer(const StructDef& struct_def,
312
0
                             std::string* code_ptr) {
313
0
    std::string& code = *code_ptr;
314
0
    const std::string size_prefix[] = {"", "SizePrefixed"};
315
0
    const std::string struct_type = namer_.Type(struct_def);
316
317
0
    bool has_file_identifier = (parser_.root_struct_def_ == &struct_def) &&
318
0
                               parser_.file_identifier_.length();
319
320
0
    if (has_file_identifier) {
321
0
      code += "const " + struct_type + "Identifier = \"" +
322
0
              parser_.file_identifier_ + "\"\n\n";
323
0
    }
324
325
0
    for (int i = 0; i < 2; i++) {
326
0
      code += "func Get" + size_prefix[i] + "RootAs" + struct_type;
327
0
      code += "(buf []byte, offset flatbuffers.UOffsetT) ";
328
0
      code += "*" + struct_type + "";
329
0
      code += " {\n";
330
0
      if (i == 0) {
331
0
        code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
332
0
      } else {
333
0
        code +=
334
0
            "\tn := "
335
0
            "flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n";
336
0
      }
337
0
      code += "\tx := &" + struct_type + "{}\n";
338
0
      if (i == 0) {
339
0
        code += "\tx.Init(buf, n+offset)\n";
340
0
      } else {
341
0
        code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n";
342
0
      }
343
0
      code += "\treturn x\n";
344
0
      code += "}\n\n";
345
346
0
      code += "func Finish" + size_prefix[i] + struct_type +
347
0
              "Buffer(builder *flatbuffers.Builder, offset "
348
0
              "flatbuffers.UOffsetT) {\n";
349
0
      if (has_file_identifier) {
350
0
        code += "\tidentifierBytes := []byte(" + struct_type + "Identifier)\n";
351
0
        code += "\tbuilder.Finish" + size_prefix[i] +
352
0
                "WithFileIdentifier(offset, identifierBytes)\n";
353
0
      } else {
354
0
        code += "\tbuilder.Finish" + size_prefix[i] + "(offset)\n";
355
0
      }
356
0
      code += "}\n\n";
357
358
0
      if (has_file_identifier) {
359
0
        code += "func " + size_prefix[i] + struct_type +
360
0
                "BufferHasIdentifier(buf []byte) bool {\n";
361
0
        code += "\treturn flatbuffers." + size_prefix[i] +
362
0
                "BufferHasIdentifier(buf, " + struct_type + "Identifier)\n";
363
0
        code += "}\n\n";
364
0
      }
365
0
    }
366
0
  }
367
368
  // Initialize an existing object with other data, to avoid an allocation.
369
0
  void InitializeExisting(const StructDef& struct_def, std::string* code_ptr) {
370
0
    std::string& code = *code_ptr;
371
372
0
    GenReceiver(struct_def, code_ptr);
373
0
    code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
374
0
    code += "{\n";
375
0
    code += "\trcv._tab.Bytes = buf\n";
376
0
    code += "\trcv._tab.Pos = i\n";
377
0
    code += "}\n\n";
378
0
  }
379
380
  // Implement the table accessor
381
0
  void GenTableAccessor(const StructDef& struct_def, std::string* code_ptr) {
382
0
    std::string& code = *code_ptr;
383
384
0
    GenReceiver(struct_def, code_ptr);
385
0
    code += " Table() flatbuffers.Table ";
386
0
    code += "{\n";
387
388
0
    if (struct_def.fixed) {
389
0
      code += "\treturn rcv._tab.Table\n";
390
0
    } else {
391
0
      code += "\treturn rcv._tab\n";
392
0
    }
393
0
    code += "}\n\n";
394
0
  }
395
396
  // Get the length of a vector.
397
  void GetVectorLen(const StructDef& struct_def, const FieldDef& field,
398
0
                    std::string* code_ptr) {
399
0
    std::string& code = *code_ptr;
400
401
0
    GenReceiver(struct_def, code_ptr);
402
0
    code += " " + namer_.Function(field) + "Length(";
403
0
    code += ") int " + OffsetPrefix(field);
404
0
    code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
405
0
    code += "\treturn 0\n}\n\n";
406
0
  }
407
408
  // Get a [ubyte] vector as a byte slice.
409
  void GetUByteSlice(const StructDef& struct_def, const FieldDef& field,
410
0
                     std::string* code_ptr) {
411
0
    std::string& code = *code_ptr;
412
413
0
    GenReceiver(struct_def, code_ptr);
414
0
    code += " " + namer_.Function(field) + "Bytes(";
415
0
    code += ") []byte " + OffsetPrefix(field);
416
0
    code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
417
0
    code += "\treturn nil\n}\n\n";
418
0
  }
419
420
  // Get the value of a struct's scalar.
421
  void GetScalarFieldOfStruct(const StructDef& struct_def,
422
0
                              const FieldDef& field, std::string* code_ptr) {
423
0
    std::string& code = *code_ptr;
424
0
    std::string getter = GenGetter(field.value.type);
425
0
    GenReceiver(struct_def, code_ptr);
426
0
    code += " " + namer_.Function(field);
427
0
    code += "() " + TypeName(field) + " {\n";
428
0
    code += "\treturn " +
429
0
            CastToEnum(field.value.type,
430
0
                       getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
431
0
                           NumToString(field.value.offset) + "))");
432
0
    code += "\n}\n";
433
0
  }
434
435
  // Get the value of a table's scalar.
436
  void GetScalarFieldOfTable(const StructDef& struct_def, const FieldDef& field,
437
0
                             std::string* code_ptr) {
438
0
    std::string& code = *code_ptr;
439
0
    std::string getter = GenGetter(field.value.type);
440
0
    GenReceiver(struct_def, code_ptr);
441
0
    code += " " + namer_.Function(field);
442
0
    code += "() " + TypeName(field) + " ";
443
0
    code += OffsetPrefix(field);
444
0
    if (field.IsScalarOptional()) {
445
0
      code += "\t\tv := ";
446
0
    } else {
447
0
      code += "\t\treturn ";
448
0
    }
449
0
    code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
450
0
    if (field.IsScalarOptional()) {
451
0
      code += "\n\t\treturn &v";
452
0
    }
453
0
    code += "\n\t}\n";
454
0
    code += "\treturn " + GenConstant(field) + "\n";
455
0
    code += "}\n\n";
456
0
  }
457
458
  // Get a struct by initializing an existing struct.
459
  // Specific to Struct.
460
  void GetStructFieldOfStruct(const StructDef& struct_def,
461
0
                              const FieldDef& field, std::string* code_ptr) {
462
0
    std::string& code = *code_ptr;
463
0
    GenReceiver(struct_def, code_ptr);
464
0
    code += " " + namer_.Function(field);
465
0
    code += "(obj *" + TypeName(field);
466
0
    code += ") *" + TypeName(field);
467
0
    code += " {\n";
468
0
    code += "\tif obj == nil {\n";
469
0
    code += "\t\tobj = new(" + TypeName(field) + ")\n";
470
0
    code += "\t}\n";
471
0
    code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
472
0
    code += NumToString(field.value.offset) + ")";
473
0
    code += "\n\treturn obj\n";
474
0
    code += "}\n";
475
0
  }
476
477
  // Get a struct by initializing an existing struct.
478
  // Specific to Table.
479
  void GetStructFieldOfTable(const StructDef& struct_def, const FieldDef& field,
480
0
                             std::string* code_ptr) {
481
0
    std::string& code = *code_ptr;
482
0
    GenReceiver(struct_def, code_ptr);
483
0
    code += " " + namer_.Function(field);
484
0
    code += "(obj *";
485
0
    code += TypeName(field);
486
0
    code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
487
0
    if (field.value.type.struct_def->fixed) {
488
0
      code += "\t\tx := o + rcv._tab.Pos\n";
489
0
    } else {
490
0
      code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
491
0
    }
492
0
    code += "\t\tif obj == nil {\n";
493
0
    code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
494
0
    code += "\t\t}\n";
495
0
    code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
496
0
    code += "\t\treturn obj\n\t}\n\treturn nil\n";
497
0
    code += "}\n\n";
498
0
  }
499
500
  // Get the value of a string.
501
  void GetStringField(const StructDef& struct_def, const FieldDef& field,
502
0
                      std::string* code_ptr) {
503
0
    std::string& code = *code_ptr;
504
0
    GenReceiver(struct_def, code_ptr);
505
0
    code += " " + namer_.Function(field);
506
0
    code += "() " + TypeName(field) + " ";
507
0
    code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
508
0
    code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
509
0
    code += "}\n\n";
510
0
  }
511
512
  // Get the value of a union from an object.
513
  void GetUnionField(const StructDef& struct_def, const FieldDef& field,
514
0
                     std::string* code_ptr) {
515
0
    std::string& code = *code_ptr;
516
0
    GenReceiver(struct_def, code_ptr);
517
0
    code += " " + namer_.Function(field) + "(";
518
0
    code += "obj " + GenTypePointer(field.value.type) + ") bool ";
519
0
    code += OffsetPrefix(field);
520
0
    code += "\t\t" + GenGetter(field.value.type);
521
0
    code += "(obj, o)\n\t\treturn true\n\t}\n";
522
0
    code += "\treturn false\n";
523
0
    code += "}\n\n";
524
0
  }
525
526
  // Get the value of a vector's struct member.
527
  void GetMemberOfVectorOfStruct(const StructDef& struct_def,
528
0
                                 const FieldDef& field, std::string* code_ptr) {
529
0
    std::string& code = *code_ptr;
530
0
    auto vectortype = field.value.type.VectorType();
531
532
0
    GenReceiver(struct_def, code_ptr);
533
0
    code += " " + namer_.Function(field);
534
0
    code += "(obj *" + TypeName(field);
535
0
    code += ", j int) bool " + OffsetPrefix(field);
536
0
    code += "\t\tx := rcv._tab.Vector(o)\n";
537
0
    code += "\t\tx += flatbuffers.UOffsetT(j) * ";
538
0
    code += NumToString(InlineSize(vectortype)) + "\n";
539
0
    if (!(vectortype.struct_def->fixed)) {
540
0
      code += "\t\tx = rcv._tab.Indirect(x)\n";
541
0
    }
542
0
    code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
543
0
    code += "\t\treturn true\n\t}\n";
544
0
    code += "\treturn false\n";
545
0
    code += "}\n\n";
546
0
  }
547
548
  void GetMemberOfVectorOfStructByKey(const StructDef& struct_def,
549
                                      const FieldDef& field,
550
0
                                      std::string* code_ptr) {
551
0
    std::string& code = *code_ptr;
552
0
    auto vectortype = field.value.type.VectorType();
553
0
    FLATBUFFERS_ASSERT(vectortype.struct_def->has_key);
554
555
0
    auto& vector_struct_fields = vectortype.struct_def->fields.vec;
556
0
    auto kit =
557
0
        std::find_if(vector_struct_fields.begin(), vector_struct_fields.end(),
558
0
                     [&](FieldDef* vector_struct_field) {
559
0
                       return vector_struct_field->key;
560
0
                     });
561
562
0
    auto& key_field = **kit;
563
0
    FLATBUFFERS_ASSERT(key_field.key);
564
565
0
    GenReceiver(struct_def, code_ptr);
566
0
    code += " " + namer_.Field(field) + "ByKey";
567
0
    code += "(obj *" + TypeName(field);
568
0
    code += ", key " + NativeType(key_field.value.type) + ") bool " +
569
0
            OffsetPrefix(field);
570
0
    code += "\t\tx := rcv._tab.Vector(o)\n";
571
0
    code += "\t\treturn ";
572
0
    code += "obj.LookupByKey(key, x, rcv._tab.Bytes)\n";
573
0
    code += "\t}\n";
574
0
    code += "\treturn false\n";
575
0
    code += "}\n\n";
576
0
  }
577
578
  // Get the value of a vector's non-struct member.
579
  void GetMemberOfVectorOfNonStruct(const StructDef& struct_def,
580
                                    const FieldDef& field,
581
0
                                    std::string* code_ptr) {
582
0
    std::string& code = *code_ptr;
583
0
    auto vectortype = field.value.type.VectorType();
584
585
0
    GenReceiver(struct_def, code_ptr);
586
0
    code += " " + namer_.Function(field);
587
0
    code += "(j int) " + TypeName(field) + " ";
588
0
    code += OffsetPrefix(field);
589
0
    code += "\t\ta := rcv._tab.Vector(o)\n";
590
0
    code += "\t\treturn " +
591
0
            CastToEnum(field.value.type,
592
0
                       GenGetter(field.value.type) +
593
0
                           "(a + flatbuffers.UOffsetT(j*" +
594
0
                           NumToString(InlineSize(vectortype)) + "))");
595
0
    code += "\n\t}\n";
596
0
    if (IsString(vectortype)) {
597
0
      code += "\treturn nil\n";
598
0
    } else if (vectortype.base_type == BASE_TYPE_BOOL) {
599
0
      code += "\treturn false\n";
600
0
    } else {
601
0
      code += "\treturn 0\n";
602
0
    }
603
0
    code += "}\n\n";
604
0
  }
605
606
  // Begin the creator function signature.
607
0
  void BeginBuilderArgs(const StructDef& struct_def, std::string* code_ptr) {
608
0
    std::string& code = *code_ptr;
609
610
0
    if (code.substr(code.length() - 2) != "\n\n") {
611
      // a previous mutate has not put an extra new line
612
0
      code += "\n";
613
0
    }
614
0
    code += "func Create" + struct_def.name;
615
0
    code += "(builder *flatbuffers.Builder";
616
0
  }
617
618
  // Recursively generate arguments for a constructor, to deal with nested
619
  // structs.
620
  void StructBuilderArgs(const StructDef& struct_def, const char* nameprefix,
621
0
                         std::string* code_ptr) {
622
0
    for (auto it = struct_def.fields.vec.begin();
623
0
         it != struct_def.fields.vec.end(); ++it) {
624
0
      auto& field = **it;
625
0
      if (IsStruct(field.value.type)) {
626
        // Generate arguments for a struct inside a struct. To ensure names
627
        // don't clash, and to make it obvious these arguments are constructing
628
        // a nested struct, prefix the name with the field name.
629
0
        StructBuilderArgs(*field.value.type.struct_def,
630
0
                          (nameprefix + (field.name + "_")).c_str(), code_ptr);
631
0
      } else {
632
0
        std::string& code = *code_ptr;
633
0
        code += std::string(", ") + nameprefix;
634
0
        code += namer_.Variable(field);
635
0
        code += " " + TypeName(field);
636
0
      }
637
0
    }
638
0
  }
639
640
  // End the creator function signature.
641
0
  void EndBuilderArgs(std::string* code_ptr) {
642
0
    std::string& code = *code_ptr;
643
0
    code += ") flatbuffers.UOffsetT {\n";
644
0
  }
645
646
  // Recursively generate struct construction statements and instert manual
647
  // padding.
648
  void StructBuilderBody(const StructDef& struct_def, const char* nameprefix,
649
0
                         std::string* code_ptr) {
650
0
    std::string& code = *code_ptr;
651
0
    code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
652
0
    code += NumToString(struct_def.bytesize) + ")\n";
653
0
    for (auto it = struct_def.fields.vec.rbegin();
654
0
         it != struct_def.fields.vec.rend(); ++it) {
655
0
      auto& field = **it;
656
0
      if (field.padding)
657
0
        code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
658
0
      if (IsStruct(field.value.type)) {
659
0
        StructBuilderBody(*field.value.type.struct_def,
660
0
                          (nameprefix + (field.name + "_")).c_str(), code_ptr);
661
0
      } else {
662
0
        code += "\tbuilder.Prepend" + GenMethod(field) + "(";
663
0
        code += CastToBaseType(field.value.type,
664
0
                               nameprefix + namer_.Variable(field)) +
665
0
                ")\n";
666
0
      }
667
0
    }
668
0
  }
669
670
0
  void EndBuilderBody(std::string* code_ptr) {
671
0
    std::string& code = *code_ptr;
672
0
    code += "\treturn builder.Offset()\n";
673
0
    code += "}\n";
674
0
  }
675
676
  // Get the value of a table's starting offset.
677
0
  void GetStartOfTable(const StructDef& struct_def, std::string* code_ptr) {
678
0
    std::string& code = *code_ptr;
679
0
    code += "func " + namer_.Type(struct_def) + "Start";
680
0
    code += "(builder *flatbuffers.Builder) {\n";
681
0
    code += "\tbuilder.StartObject(";
682
0
    code += NumToString(struct_def.fields.vec.size());
683
0
    code += ")\n}\n";
684
0
  }
685
686
  // Set the value of a table's field.
687
  void BuildFieldOfTable(const StructDef& struct_def, const FieldDef& field,
688
0
                         const size_t offset, std::string* code_ptr) {
689
0
    std::string& code = *code_ptr;
690
0
    const std::string field_var = namer_.Variable(field);
691
0
    code += "func " + namer_.Type(struct_def) + "Add" + namer_.Function(field);
692
0
    code += "(builder *flatbuffers.Builder, ";
693
0
    code += field_var + " ";
694
0
    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
695
0
      code += "flatbuffers.UOffsetT";
696
0
    } else {
697
0
      code += GenTypeGet(field.value.type);
698
0
    }
699
0
    code += ") {\n\t";
700
0
    code += "builder.Prepend";
701
0
    code += GenMethod(field);
702
0
    if (field.IsScalarOptional()) {
703
0
      code += "(";
704
0
    } else {
705
0
      code += "Slot(" + NumToString(offset) + ", ";
706
0
    }
707
0
    if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
708
0
      code += "flatbuffers.UOffsetT";
709
0
      code += "(" + field_var + ")";
710
0
    } else {
711
0
      code += CastToBaseType(field.value.type, field_var);
712
0
    }
713
0
    if (field.IsScalarOptional()) {
714
0
      code += ")\n";
715
0
      code += "\tbuilder.Slot(" + NumToString(offset);
716
0
    } else {
717
0
      code += ", " + GenConstant(field);
718
0
    }
719
0
    code += ")\n";
720
0
    code += "}\n";
721
0
  }
722
723
  // Set the value of one of the members of a table's vector.
724
  void BuildVectorOfTable(const StructDef& struct_def, const FieldDef& field,
725
0
                          std::string* code_ptr) {
726
0
    std::string& code = *code_ptr;
727
0
    code += "func " + namer_.Type(struct_def) + "Start";
728
0
    code += namer_.Function(field);
729
0
    code += "Vector(builder *flatbuffers.Builder, numElems int) ";
730
0
    code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
731
0
    auto vector_type = field.value.type.VectorType();
732
0
    auto alignment = InlineAlignment(vector_type);
733
0
    auto elem_size = InlineSize(vector_type);
734
0
    code += NumToString(elem_size);
735
0
    code += ", numElems, " + NumToString(alignment);
736
0
    code += ")\n}\n";
737
0
  }
738
739
  // Get the offset of the end of a table.
740
0
  void GetEndOffsetOnTable(const StructDef& struct_def, std::string* code_ptr) {
741
0
    std::string& code = *code_ptr;
742
0
    code += "func " + namer_.Type(struct_def) + "End";
743
0
    code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
744
0
    code += "{\n\treturn builder.EndObject()\n}\n";
745
0
  }
746
747
  // Generate the receiver for function signatures.
748
0
  void GenReceiver(const StructDef& struct_def, std::string* code_ptr) {
749
0
    std::string& code = *code_ptr;
750
0
    code += "func (rcv *" + namer_.Type(struct_def) + ")";
751
0
  }
752
753
  // Generate a struct field getter, conditioned on its child type(s).
754
  void GenStructAccessor(const StructDef& struct_def, const FieldDef& field,
755
0
                         std::string* code_ptr) {
756
0
    GenComment(field.doc_comment, code_ptr, nullptr, "");
757
0
    if (IsScalar(field.value.type.base_type)) {
758
0
      if (struct_def.fixed) {
759
0
        GetScalarFieldOfStruct(struct_def, field, code_ptr);
760
0
      } else {
761
0
        GetScalarFieldOfTable(struct_def, field, code_ptr);
762
0
      }
763
0
    } else {
764
0
      switch (field.value.type.base_type) {
765
0
        case BASE_TYPE_STRUCT:
766
0
          if (struct_def.fixed) {
767
0
            GetStructFieldOfStruct(struct_def, field, code_ptr);
768
0
          } else {
769
0
            GetStructFieldOfTable(struct_def, field, code_ptr);
770
0
          }
771
0
          break;
772
0
        case BASE_TYPE_STRING:
773
0
          GetStringField(struct_def, field, code_ptr);
774
0
          break;
775
0
        case BASE_TYPE_VECTOR: {
776
0
          auto vectortype = field.value.type.VectorType();
777
0
          if (vectortype.base_type == BASE_TYPE_STRUCT) {
778
0
            GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
779
            // TODO(michaeltle): Support querying fixed struct by key.
780
            // Currently, we only support keyed tables.
781
0
            if (!vectortype.struct_def->fixed &&
782
0
                vectortype.struct_def->has_key) {
783
0
              GetMemberOfVectorOfStructByKey(struct_def, field, code_ptr);
784
0
            }
785
0
          } else {
786
0
            GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
787
0
          }
788
0
          break;
789
0
        }
790
0
        case BASE_TYPE_UNION:
791
0
          GetUnionField(struct_def, field, code_ptr);
792
0
          break;
793
0
        default:
794
0
          FLATBUFFERS_ASSERT(0);
795
0
      }
796
0
    }
797
0
    if (IsVector(field.value.type)) {
798
0
      GetVectorLen(struct_def, field, code_ptr);
799
0
      if (field.value.type.element == BASE_TYPE_UCHAR) {
800
0
        GetUByteSlice(struct_def, field, code_ptr);
801
0
      }
802
0
    }
803
0
  }
804
805
  // Mutate the value of a struct's scalar.
806
  void MutateScalarFieldOfStruct(const StructDef& struct_def,
807
0
                                 const FieldDef& field, std::string* code_ptr) {
808
0
    std::string& code = *code_ptr;
809
0
    std::string setter =
810
0
        "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(field.value.type));
811
0
    GenReceiver(struct_def, code_ptr);
812
0
    code += " Mutate" + namer_.Function(field);
813
0
    code +=
814
0
        "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn " + setter;
815
0
    code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
816
0
    code += NumToString(field.value.offset) + "), ";
817
0
    code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
818
0
  }
819
820
  // Mutate the value of a table's scalar.
821
  void MutateScalarFieldOfTable(const StructDef& struct_def,
822
0
                                const FieldDef& field, std::string* code_ptr) {
823
0
    std::string& code = *code_ptr;
824
0
    std::string setter = "rcv._tab.Mutate" +
825
0
                         namer_.Method(GenTypeBasic(field.value.type)) + "Slot";
826
0
    GenReceiver(struct_def, code_ptr);
827
0
    code += " Mutate" + namer_.Function(field);
828
0
    code += "(n " + GenTypeGet(field.value.type) + ") bool {\n\treturn ";
829
0
    code += setter + "(" + NumToString(field.value.offset) + ", ";
830
0
    code += CastToBaseType(field.value.type, "n") + ")\n";
831
0
    code += "}\n\n";
832
0
  }
833
834
  // Mutate an element of a vector of scalars.
835
  void MutateElementOfVectorOfNonStruct(const StructDef& struct_def,
836
                                        const FieldDef& field,
837
0
                                        std::string* code_ptr) {
838
0
    std::string& code = *code_ptr;
839
0
    auto vectortype = field.value.type.VectorType();
840
0
    std::string setter =
841
0
        "rcv._tab.Mutate" + namer_.Method(GenTypeBasic(vectortype));
842
0
    GenReceiver(struct_def, code_ptr);
843
0
    code += " Mutate" + namer_.Function(field);
844
0
    code += "(j int, n " + TypeName(field) + ") bool ";
845
0
    code += OffsetPrefix(field);
846
0
    code += "\t\ta := rcv._tab.Vector(o)\n";
847
0
    code += "\t\treturn " + setter + "(";
848
0
    code += "a+flatbuffers.UOffsetT(j*";
849
0
    code += NumToString(InlineSize(vectortype)) + "), ";
850
0
    code += CastToBaseType(vectortype, "n") + ")\n";
851
0
    code += "\t}\n";
852
0
    code += "\treturn false\n";
853
0
    code += "}\n\n";
854
0
  }
855
856
  // Generate a struct field setter, conditioned on its child type(s).
857
  void GenStructMutator(const StructDef& struct_def, const FieldDef& field,
858
0
                        std::string* code_ptr) {
859
0
    GenComment(field.doc_comment, code_ptr, nullptr, "");
860
0
    if (IsScalar(field.value.type.base_type)) {
861
0
      if (struct_def.fixed) {
862
0
        MutateScalarFieldOfStruct(struct_def, field, code_ptr);
863
0
      } else {
864
0
        MutateScalarFieldOfTable(struct_def, field, code_ptr);
865
0
      }
866
0
    } else if (IsVector(field.value.type)) {
867
0
      if (IsScalar(field.value.type.element)) {
868
0
        MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
869
0
      }
870
0
    }
871
0
  }
872
873
  // Generate table constructors, conditioned on its members' types.
874
0
  void GenTableBuilders(const StructDef& struct_def, std::string* code_ptr) {
875
0
    GetStartOfTable(struct_def, code_ptr);
876
877
0
    for (auto it = struct_def.fields.vec.begin();
878
0
         it != struct_def.fields.vec.end(); ++it) {
879
0
      auto& field = **it;
880
0
      if (field.deprecated) continue;
881
882
0
      auto offset = it - struct_def.fields.vec.begin();
883
0
      BuildFieldOfTable(struct_def, field, offset, code_ptr);
884
0
      if (IsVector(field.value.type)) {
885
0
        BuildVectorOfTable(struct_def, field, code_ptr);
886
0
      }
887
0
    }
888
889
0
    GetEndOffsetOnTable(struct_def, code_ptr);
890
0
  }
891
892
  // Generate struct or table methods.
893
0
  void GenStruct(const StructDef& struct_def, std::string* code_ptr) {
894
0
    if (struct_def.generated) return;
895
896
0
    cur_name_space_ = struct_def.defined_namespace;
897
898
0
    GenComment(struct_def.doc_comment, code_ptr, nullptr);
899
0
    if (parser_.opts.generate_object_based_api) {
900
0
      GenNativeStruct(struct_def, code_ptr);
901
0
    }
902
0
    BeginClass(struct_def, code_ptr);
903
0
    if (!struct_def.fixed) {
904
      // Generate a special accessor for the table that has been declared as
905
      // the root type.
906
0
      NewRootTypeFromBuffer(struct_def, code_ptr);
907
0
    }
908
    // Generate the Init method that sets the field in a pre-existing
909
    // accessor object. This is to allow object reuse.
910
0
    InitializeExisting(struct_def, code_ptr);
911
    // Generate _tab accessor
912
0
    GenTableAccessor(struct_def, code_ptr);
913
914
    // Generate struct fields accessors
915
0
    for (auto it = struct_def.fields.vec.begin();
916
0
         it != struct_def.fields.vec.end(); ++it) {
917
0
      auto& field = **it;
918
0
      if (field.deprecated) continue;
919
920
0
      GenStructAccessor(struct_def, field, code_ptr);
921
0
      GenStructMutator(struct_def, field, code_ptr);
922
      // TODO(michaeltle): Support querying fixed struct by key. Currently,
923
      // we only support keyed tables.
924
0
      if (!struct_def.fixed && field.key) {
925
0
        GenKeyCompare(struct_def, field, code_ptr);
926
0
        GenLookupByKey(struct_def, field, code_ptr);
927
0
      }
928
0
    }
929
930
    // Generate builders
931
0
    if (struct_def.fixed) {
932
      // create a struct constructor function
933
0
      GenStructBuilder(struct_def, code_ptr);
934
0
    } else {
935
      // Create a set of functions that allow table construction.
936
0
      GenTableBuilders(struct_def, code_ptr);
937
0
    }
938
0
  }
939
940
  void GenKeyCompare(const StructDef& struct_def, const FieldDef& field,
941
0
                     std::string* code_ptr) {
942
0
    FLATBUFFERS_ASSERT(struct_def.has_key);
943
0
    FLATBUFFERS_ASSERT(field.key);
944
0
    std::string& code = *code_ptr;
945
946
0
    code += "func " + namer_.Type(struct_def) + "KeyCompare(";
947
0
    code += "o1, o2 flatbuffers.UOffsetT, buf []byte) bool {\n";
948
0
    code += "\tobj1 := &" + namer_.Type(struct_def) + "{}\n";
949
0
    code += "\tobj2 := &" + namer_.Type(struct_def) + "{}\n";
950
0
    code += "\tobj1.Init(buf, flatbuffers.UOffsetT(len(buf))-o1)\n";
951
0
    code += "\tobj2.Init(buf, flatbuffers.UOffsetT(len(buf))-o2)\n";
952
0
    if (IsString(field.value.type)) {
953
0
      code += "\treturn string(obj1." + namer_.Function(field.name) + "()) < ";
954
0
      code += "string(obj2." + namer_.Function(field.name) + "())\n";
955
0
    } else {
956
0
      code += "\treturn obj1." + namer_.Function(field.name) + "() < ";
957
0
      code += "obj2." + namer_.Function(field.name) + "()\n";
958
0
    }
959
0
    code += "}\n\n";
960
0
  }
961
962
  void GenLookupByKey(const StructDef& struct_def, const FieldDef& field,
963
0
                      std::string* code_ptr) {
964
0
    FLATBUFFERS_ASSERT(struct_def.has_key);
965
0
    FLATBUFFERS_ASSERT(field.key);
966
0
    std::string& code = *code_ptr;
967
968
0
    GenReceiver(struct_def, code_ptr);
969
0
    code += " LookupByKey(";
970
0
    code += "key " + NativeType(field.value.type) + ", ";
971
0
    code += "vectorLocation flatbuffers.UOffsetT, ";
972
0
    code += "buf []byte) bool {\n";
973
0
    code += "\tspan := flatbuffers.GetUOffsetT(buf[vectorLocation-4:])\n";
974
0
    code += "\tstart := flatbuffers.UOffsetT(0)\n";
975
0
    if (IsString(field.value.type)) {
976
0
      code += "\tbKey := []byte(key)\n";
977
0
    }
978
0
    code += "\tfor span != 0 {\n";
979
0
    code += "\t\tmiddle := span / 2\n";
980
0
    code += "\t\ttableOffset := flatbuffers.GetIndirectOffset(buf, ";
981
0
    code += "vectorLocation+4*(start+middle))\n";
982
983
0
    code += "\t\tobj := &" + namer_.Type(struct_def) + "{}\n";
984
0
    code += "\t\tobj.Init(buf, tableOffset)\n";
985
986
0
    if (IsString(field.value.type)) {
987
0
      needs_bytes_import_ = true;
988
0
      code +=
989
0
          "\t\tcomp := bytes.Compare(obj." + namer_.Function(field.name) + "()";
990
0
      code += ", bKey)\n";
991
0
    } else {
992
0
      code += "\t\tval := obj." + namer_.Function(field.name) + "()\n";
993
0
      code += "\t\tcomp := 0\n";
994
0
      code += "\t\tif val > key {\n";
995
0
      code += "\t\t\tcomp = 1\n";
996
0
      code += "\t\t} else if val < key {\n";
997
0
      code += "\t\t\tcomp = -1\n";
998
0
      code += "\t\t}\n";
999
0
    }
1000
0
    code += "\t\tif comp > 0 {\n";
1001
0
    code += "\t\t\tspan = middle\n";
1002
0
    code += "\t\t} else if comp < 0 {\n";
1003
0
    code += "\t\t\tmiddle += 1\n";
1004
0
    code += "\t\t\tstart += middle\n";
1005
0
    code += "\t\t\tspan -= middle\n";
1006
0
    code += "\t\t} else {\n";
1007
0
    code += "\t\t\trcv.Init(buf, tableOffset)\n";
1008
0
    code += "\t\t\treturn true\n";
1009
0
    code += "\t\t}\n";
1010
0
    code += "\t}\n";
1011
0
    code += "\treturn false\n";
1012
0
    code += "}\n\n";
1013
0
  }
1014
1015
0
  void GenNativeStruct(const StructDef& struct_def, std::string* code_ptr) {
1016
0
    std::string& code = *code_ptr;
1017
1018
0
    code += "type " + NativeName(struct_def) + " struct {\n";
1019
0
    for (auto it = struct_def.fields.vec.begin();
1020
0
         it != struct_def.fields.vec.end(); ++it) {
1021
0
      const FieldDef& field = **it;
1022
0
      if (field.deprecated) continue;
1023
0
      if (IsScalar(field.value.type.base_type) &&
1024
0
          field.value.type.enum_def != nullptr &&
1025
0
          field.value.type.enum_def->is_union)
1026
0
        continue;
1027
0
      code += "\t" + namer_.Field(field) + " ";
1028
0
      if (field.IsScalarOptional()) {
1029
0
        code += "*";
1030
0
      }
1031
0
      code += NativeType(field.value.type) + " `json:\"" + field.name + "\"`" +
1032
0
              "\n";
1033
0
    }
1034
0
    code += "}\n\n";
1035
1036
0
    if (!struct_def.fixed) {
1037
0
      GenNativeTablePack(struct_def, code_ptr);
1038
0
      GenNativeTableUnPack(struct_def, code_ptr);
1039
0
    } else {
1040
0
      GenNativeStructPack(struct_def, code_ptr);
1041
0
      GenNativeStructUnPack(struct_def, code_ptr);
1042
0
    }
1043
0
  }
1044
1045
0
  void GenNativeUnion(const EnumDef& enum_def, std::string* code_ptr) {
1046
0
    if (enum_def.generated) return;
1047
1048
0
    std::string& code = *code_ptr;
1049
0
    code += "type " + NativeName(enum_def) + " struct {\n";
1050
0
    code += "\tType " + namer_.Type(enum_def) + "\n";
1051
0
    code += "\tValue interface{}\n";
1052
0
    code += "}\n\n";
1053
0
  }
1054
1055
0
  void GenNativeUnionPack(const EnumDef& enum_def, std::string* code_ptr) {
1056
0
    if (enum_def.generated) return;
1057
1058
0
    std::string& code = *code_ptr;
1059
0
    code += "func (t *" + NativeName(enum_def) +
1060
0
            ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1061
0
    code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
1062
1063
0
    code += "\tswitch t.Type {\n";
1064
0
    for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
1065
0
         ++it2) {
1066
0
      const EnumVal& ev = **it2;
1067
0
      if (ev.IsZero()) continue;
1068
0
      code += "\tcase " + namer_.EnumVariant(enum_def, ev) + ":\n";
1069
0
      code += "\t\treturn t.Value.(" + NativeType(ev.union_type) +
1070
0
              ").Pack(builder)\n";
1071
0
    }
1072
0
    code += "\t}\n";
1073
0
    code += "\treturn 0\n";
1074
0
    code += "}\n\n";
1075
0
  }
1076
1077
0
  void GenNativeUnionUnPack(const EnumDef& enum_def, std::string* code_ptr) {
1078
0
    if (enum_def.generated) return;
1079
1080
0
    std::string& code = *code_ptr;
1081
1082
0
    code += "func (rcv " + namer_.Type(enum_def) +
1083
0
            ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) +
1084
0
            " {\n";
1085
0
    code += "\tswitch rcv {\n";
1086
1087
0
    for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end();
1088
0
         ++it2) {
1089
0
      const EnumVal& ev = **it2;
1090
0
      if (ev.IsZero()) continue;
1091
0
      code += "\tcase " + namer_.EnumVariant(enum_def, ev) + ":\n";
1092
0
      code += "\t\tvar x " +
1093
0
              WrapInNameSpaceAndTrack(ev.union_type.struct_def,
1094
0
                                      ev.union_type.struct_def->name) +
1095
0
              "\n";
1096
0
      code += "\t\tx.Init(table.Bytes, table.Pos)\n";
1097
1098
0
      code += "\t\treturn &" +
1099
0
              WrapInNameSpaceAndTrack(&enum_def, NativeName(enum_def)) +
1100
0
              "{Type: " + namer_.EnumVariant(enum_def, ev) +
1101
0
              ", Value: x.UnPack()}\n";
1102
0
    }
1103
0
    code += "\t}\n";
1104
0
    code += "\treturn nil\n";
1105
0
    code += "}\n\n";
1106
0
  }
1107
1108
0
  void GenNativeTablePack(const StructDef& struct_def, std::string* code_ptr) {
1109
0
    std::string& code = *code_ptr;
1110
0
    const std::string struct_type = namer_.Type(struct_def);
1111
1112
0
    code += "func (t *" + NativeName(struct_def) +
1113
0
            ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1114
0
    code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
1115
0
    for (auto it = struct_def.fields.vec.begin();
1116
0
         it != struct_def.fields.vec.end(); ++it) {
1117
0
      const FieldDef& field = **it;
1118
0
      if (field.deprecated) continue;
1119
0
      if (IsScalar(field.value.type.base_type)) continue;
1120
1121
0
      const std::string field_field = namer_.Field(field);
1122
0
      const std::string field_var = namer_.Variable(field);
1123
0
      const std::string offset = field_var + "Offset";
1124
1125
0
      if (IsString(field.value.type)) {
1126
0
        if (!field.IsRequired()) {
1127
0
          code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
1128
0
          code += "\tif t." + field_field + " != \"\" {\n";
1129
0
          code += "\t\t" + offset + " = builder.CreateString(t." + field_field +
1130
0
                  ")\n";
1131
0
          code += "\t}\n";
1132
0
        } else {
1133
0
          code += "\t" + offset + " := builder.CreateString(t." + field_field +
1134
0
                  ")\n";
1135
0
        }
1136
0
      } else if (IsVector(field.value.type) &&
1137
0
                 field.value.type.element == BASE_TYPE_UCHAR &&
1138
0
                 field.value.type.enum_def == nullptr) {
1139
0
        code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
1140
0
        code += "\tif t." + field_field + " != nil {\n";
1141
0
        code += "\t\t" + offset + " = builder.CreateByteString(t." +
1142
0
                field_field + ")\n";
1143
0
        code += "\t}\n";
1144
0
      } else if (IsVector(field.value.type)) {
1145
0
        code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n";
1146
0
        code += "\tif t." + field_field + " != nil {\n";
1147
0
        std::string length = field_var + "Length";
1148
0
        std::string offsets = field_var + "Offsets";
1149
0
        code += "\t\t" + length + " := len(t." + field_field + ")\n";
1150
0
        if (field.value.type.element == BASE_TYPE_STRING) {
1151
0
          code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
1152
0
                  length + ")\n";
1153
0
          code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
1154
0
          code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." +
1155
0
                  field_field + "[j])\n";
1156
0
          code += "\t\t}\n";
1157
0
        } else if (field.value.type.element == BASE_TYPE_STRUCT &&
1158
0
                   !field.value.type.struct_def->fixed) {
1159
0
          code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " +
1160
0
                  length + ")\n";
1161
0
          code += "\t\tfor j := 0; j < " + length + "; j++ {\n";
1162
0
          code += "\t\t\t" + offsets + "[j] = t." + field_field +
1163
0
                  "[j].Pack(builder)\n";
1164
0
          code += "\t\t}\n";
1165
0
        }
1166
0
        code += "\t\t" + struct_type + "Start" + namer_.Function(field) +
1167
0
                "Vector(builder, " + length + ")\n";
1168
0
        code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n";
1169
0
        if (IsScalar(field.value.type.element)) {
1170
0
          code += "\t\t\tbuilder.Prepend" +
1171
0
                  namer_.Method(GenTypeBasic(field.value.type.VectorType())) +
1172
0
                  "(" +
1173
0
                  CastToBaseType(field.value.type.VectorType(),
1174
0
                                 "t." + field_field + "[j]") +
1175
0
                  ")\n";
1176
0
        } else if (field.value.type.element == BASE_TYPE_STRUCT &&
1177
0
                   field.value.type.struct_def->fixed) {
1178
0
          code += "\t\t\tt." + field_field + "[j].Pack(builder)\n";
1179
0
        } else {
1180
0
          code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n";
1181
0
        }
1182
0
        code += "\t\t}\n";
1183
0
        code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n";
1184
0
        code += "\t}\n";
1185
0
      } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1186
0
        if (field.value.type.struct_def->fixed) continue;
1187
0
        code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
1188
0
      } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1189
0
        code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n\n";
1190
0
      } else {
1191
0
        FLATBUFFERS_ASSERT(0);
1192
0
      }
1193
0
    }
1194
0
    code += "\t" + struct_type + "Start(builder)\n";
1195
0
    for (auto it = struct_def.fields.vec.begin();
1196
0
         it != struct_def.fields.vec.end(); ++it) {
1197
0
      const FieldDef& field = **it;
1198
0
      if (field.deprecated) continue;
1199
0
      const std::string field_field = namer_.Field(field);
1200
0
      const std::string field_fn = namer_.Function(field);
1201
0
      const std::string offset = namer_.Variable(field) + "Offset";
1202
1203
0
      if (IsScalar(field.value.type.base_type)) {
1204
0
        std::string prefix;
1205
0
        if (field.IsScalarOptional()) {
1206
0
          code += "\tif t." + field_field + " != nil {\n\t";
1207
0
          prefix = "*";
1208
0
        }
1209
0
        if (field.value.type.enum_def == nullptr ||
1210
0
            !field.value.type.enum_def->is_union) {
1211
0
          code += "\t" + struct_type + "Add" + field_fn + "(builder, " +
1212
0
                  prefix + "t." + field_field + ")\n";
1213
0
        }
1214
0
        if (field.IsScalarOptional()) {
1215
0
          code += "\t}\n";
1216
0
        }
1217
0
      } else {
1218
0
        if (field.value.type.base_type == BASE_TYPE_STRUCT &&
1219
0
            field.value.type.struct_def->fixed) {
1220
0
          code += "\t" + offset + " := t." + field_field + ".Pack(builder)\n";
1221
0
        } else if (field.value.type.enum_def != nullptr &&
1222
0
                   field.value.type.enum_def->is_union) {
1223
0
          code += "\tif t." + field_field + " != nil {\n";
1224
0
          code += "\t\t" + struct_type + "Add" +
1225
0
                  namer_.Method(field.name + UnionTypeFieldSuffix()) +
1226
0
                  "(builder, t." + field_field + ".Type)\n";
1227
0
          code += "\t}\n";
1228
0
        }
1229
0
        code += "\t" + struct_type + "Add" + field_fn + "(builder, " + offset +
1230
0
                ")\n";
1231
0
      }
1232
0
    }
1233
0
    code += "\treturn " + struct_type + "End(builder)\n";
1234
0
    code += "}\n\n";
1235
0
  }
1236
1237
  void GenNativeTableUnPack(const StructDef& struct_def,
1238
0
                            std::string* code_ptr) {
1239
0
    std::string& code = *code_ptr;
1240
0
    const std::string struct_type = namer_.Type(struct_def);
1241
1242
0
    code += "func (rcv *" + struct_type + ") UnPackTo(t *" +
1243
0
            NativeName(struct_def) + ") {\n";
1244
0
    for (auto it = struct_def.fields.vec.begin();
1245
0
         it != struct_def.fields.vec.end(); ++it) {
1246
0
      const FieldDef& field = **it;
1247
0
      if (field.deprecated) continue;
1248
0
      const std::string field_field = namer_.Field(field);
1249
0
      const std::string field_var = namer_.Variable(field);
1250
0
      const std::string length = field_var + "Length";
1251
0
      if (IsScalar(field.value.type.base_type)) {
1252
0
        if (field.value.type.enum_def != nullptr &&
1253
0
            field.value.type.enum_def->is_union)
1254
0
          continue;
1255
0
        code += "\tt." + field_field + " = rcv." + field_field + "()\n";
1256
0
      } else if (IsString(field.value.type)) {
1257
0
        code += "\tt." + field_field + " = string(rcv." + field_field + "())\n";
1258
0
      } else if (IsVector(field.value.type) &&
1259
0
                 field.value.type.element == BASE_TYPE_UCHAR &&
1260
0
                 field.value.type.enum_def == nullptr) {
1261
0
        code += "\tt." + field_field + " = rcv." + field_field + "Bytes()\n";
1262
0
      } else if (IsVector(field.value.type)) {
1263
0
        code += "\t" + length + " := rcv." + field_field + "Length()\n";
1264
0
        code += "\tt." + field_field + " = make(" +
1265
0
                NativeType(field.value.type) + ", " + length + ")\n";
1266
0
        code += "\tfor j := 0; j < " + length + "; j++ {\n";
1267
0
        if (field.value.type.element == BASE_TYPE_STRUCT) {
1268
0
          code += "\t\tx := " +
1269
0
                  WrapInNameSpaceAndTrack(field.value.type.struct_def,
1270
0
                                          field.value.type.struct_def->name) +
1271
0
                  "{}\n";
1272
0
          code += "\t\trcv." + field_field + "(&x, j)\n";
1273
0
        }
1274
0
        code += "\t\tt." + field_field + "[j] = ";
1275
0
        if (IsScalar(field.value.type.element)) {
1276
0
          code += "rcv." + field_field + "(j)";
1277
0
        } else if (field.value.type.element == BASE_TYPE_STRING) {
1278
0
          code += "string(rcv." + field_field + "(j))";
1279
0
        } else if (field.value.type.element == BASE_TYPE_STRUCT) {
1280
0
          code += "x.UnPack()";
1281
0
        } else {
1282
          // TODO(iceboy): Support vector of unions.
1283
0
          FLATBUFFERS_ASSERT(0);
1284
0
        }
1285
0
        code += "\n";
1286
0
        code += "\t}\n";
1287
0
      } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1288
0
        code +=
1289
0
            "\tt." + field_field + " = rcv." + field_field + "(nil).UnPack()\n";
1290
0
      } else if (field.value.type.base_type == BASE_TYPE_UNION) {
1291
0
        const std::string field_table = field_var + "Table";
1292
0
        code += "\t" + field_table + " := flatbuffers.Table{}\n";
1293
0
        code +=
1294
0
            "\tif rcv." + namer_.Method(field) + "(&" + field_table + ") {\n";
1295
0
        code += "\t\tt." + field_field + " = rcv." +
1296
0
                namer_.Method(field.name + UnionTypeFieldSuffix()) +
1297
0
                "().UnPack(" + field_table + ")\n";
1298
0
        code += "\t}\n";
1299
0
      } else {
1300
0
        FLATBUFFERS_ASSERT(0);
1301
0
      }
1302
0
    }
1303
0
    code += "}\n\n";
1304
1305
0
    code += "func (rcv *" + struct_type + ") UnPack() *" +
1306
0
            NativeName(struct_def) + " {\n";
1307
0
    code += "\tif rcv == nil {\n\t\treturn nil\n\t}\n";
1308
0
    code += "\tt := &" + NativeName(struct_def) + "{}\n";
1309
0
    code += "\trcv.UnPackTo(t)\n";
1310
0
    code += "\treturn t\n";
1311
0
    code += "}\n\n";
1312
0
  }
1313
1314
0
  void GenNativeStructPack(const StructDef& struct_def, std::string* code_ptr) {
1315
0
    std::string& code = *code_ptr;
1316
1317
0
    code += "func (t *" + NativeName(struct_def) +
1318
0
            ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n";
1319
0
    code += "\tif t == nil {\n\t\treturn 0\n\t}\n";
1320
0
    code += "\treturn Create" + namer_.Type(struct_def) + "(builder";
1321
0
    StructPackArgs(struct_def, "", code_ptr);
1322
0
    code += ")\n";
1323
0
    code += "}\n";
1324
0
  }
1325
1326
  void StructPackArgs(const StructDef& struct_def, const char* nameprefix,
1327
0
                      std::string* code_ptr) {
1328
0
    std::string& code = *code_ptr;
1329
0
    for (auto it = struct_def.fields.vec.begin();
1330
0
         it != struct_def.fields.vec.end(); ++it) {
1331
0
      const FieldDef& field = **it;
1332
0
      if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1333
0
        StructPackArgs(*field.value.type.struct_def,
1334
0
                       (nameprefix + namer_.Field(field) + ".").c_str(),
1335
0
                       code_ptr);
1336
0
      } else {
1337
0
        code += std::string(", t.") + nameprefix + namer_.Field(field);
1338
0
      }
1339
0
    }
1340
0
  }
1341
1342
  void GenNativeStructUnPack(const StructDef& struct_def,
1343
0
                             std::string* code_ptr) {
1344
0
    std::string& code = *code_ptr;
1345
1346
0
    code += "func (rcv *" + namer_.Type(struct_def) + ") UnPackTo(t *" +
1347
0
            NativeName(struct_def) + ") {\n";
1348
0
    for (auto it = struct_def.fields.vec.begin();
1349
0
         it != struct_def.fields.vec.end(); ++it) {
1350
0
      const FieldDef& field = **it;
1351
0
      if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1352
0
        code += "\tt." + namer_.Field(field) + " = rcv." +
1353
0
                namer_.Method(field) + "(nil).UnPack()\n";
1354
0
      } else {
1355
0
        code += "\tt." + namer_.Field(field) + " = rcv." +
1356
0
                namer_.Method(field) + "()\n";
1357
0
      }
1358
0
    }
1359
0
    code += "}\n\n";
1360
1361
0
    code += "func (rcv *" + namer_.Type(struct_def) + ") UnPack() *" +
1362
0
            NativeName(struct_def) + " {\n";
1363
0
    code += "\tif rcv == nil {\n\t\treturn nil\n\t}\n";
1364
0
    code += "\tt := &" + NativeName(struct_def) + "{}\n";
1365
0
    code += "\trcv.UnPackTo(t)\n";
1366
0
    code += "\treturn t\n";
1367
0
    code += "}\n\n";
1368
0
  }
1369
1370
  // Generate enum declarations.
1371
0
  void GenEnum(const EnumDef& enum_def, std::string* code_ptr) {
1372
0
    if (enum_def.generated) return;
1373
1374
0
    auto max_name_length = MaxNameLength(enum_def);
1375
0
    cur_name_space_ = enum_def.defined_namespace;
1376
1377
0
    GenComment(enum_def.doc_comment, code_ptr, nullptr);
1378
0
    GenEnumType(enum_def, code_ptr);
1379
0
    BeginEnum(code_ptr);
1380
0
    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1381
0
      const EnumVal& ev = **it;
1382
0
      GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
1383
0
      EnumMember(enum_def, ev, max_name_length, code_ptr);
1384
0
    }
1385
0
    EndEnum(code_ptr);
1386
1387
0
    BeginEnumNames(enum_def, code_ptr);
1388
0
    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1389
0
      const EnumVal& ev = **it;
1390
0
      EnumNameMember(enum_def, ev, max_name_length, code_ptr);
1391
0
    }
1392
0
    EndEnumNames(code_ptr);
1393
1394
0
    BeginEnumValues(enum_def, code_ptr);
1395
0
    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1396
0
      auto& ev = **it;
1397
0
      EnumValueMember(enum_def, ev, max_name_length, code_ptr);
1398
0
    }
1399
0
    EndEnumValues(code_ptr);
1400
1401
0
    EnumStringer(enum_def, code_ptr);
1402
0
  }
1403
1404
  // Returns the function name that is able to read a value of the given type.
1405
0
  std::string GenGetter(const Type& type) {
1406
0
    switch (type.base_type) {
1407
0
      case BASE_TYPE_STRING:
1408
0
        return "rcv._tab.ByteVector";
1409
0
      case BASE_TYPE_UNION:
1410
0
        return "rcv._tab.Union";
1411
0
      case BASE_TYPE_VECTOR:
1412
0
        return GenGetter(type.VectorType());
1413
0
      default:
1414
0
        return "rcv._tab.Get" + namer_.Function(GenTypeBasic(type));
1415
0
    }
1416
0
  }
1417
1418
  // Returns the method name for use with add/put calls.
1419
0
  std::string GenMethod(const FieldDef& field) {
1420
0
    return IsScalar(field.value.type.base_type)
1421
0
               ? namer_.Method(GenTypeBasic(field.value.type))
1422
0
               : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
1423
0
  }
1424
1425
0
  std::string GenTypeBasic(const Type& type) {
1426
    // clang-format off
1427
0
    static const char *ctypename[] = {
1428
0
      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \
1429
0
        #GTYPE,
1430
0
        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1431
0
      #undef FLATBUFFERS_TD
1432
0
    };
1433
    // clang-format on
1434
0
    return ctypename[type.base_type];
1435
0
  }
1436
1437
0
  std::string GenTypePointer(const Type& type) {
1438
0
    switch (type.base_type) {
1439
0
      case BASE_TYPE_STRING:
1440
0
        return "[]byte";
1441
0
      case BASE_TYPE_VECTOR:
1442
0
        return GenTypeGet(type.VectorType());
1443
0
      case BASE_TYPE_STRUCT:
1444
0
        return WrapInNameSpaceAndTrack(type.struct_def, type.struct_def->name);
1445
0
      case BASE_TYPE_UNION:
1446
        // fall through
1447
0
      default:
1448
0
        return "*flatbuffers.Table";
1449
0
    }
1450
0
  }
1451
1452
0
  std::string GenTypeGet(const Type& type) {
1453
0
    if (type.enum_def != nullptr) {
1454
0
      return GetEnumTypeName(*type.enum_def);
1455
0
    }
1456
0
    return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1457
0
  }
1458
1459
0
  std::string TypeName(const FieldDef& field) {
1460
0
    std::string prefix;
1461
0
    if (field.IsScalarOptional()) {
1462
0
      prefix = "*";
1463
0
    }
1464
0
    return prefix + GenTypeGet(field.value.type);
1465
0
  }
1466
1467
  // If type is an enum, returns value with a cast to the enum type, otherwise
1468
  // returns value as-is.
1469
0
  std::string CastToEnum(const Type& type, std::string value) {
1470
0
    if (type.enum_def == nullptr) {
1471
0
      return value;
1472
0
    } else {
1473
0
      return GenTypeGet(type) + "(" + value + ")";
1474
0
    }
1475
0
  }
1476
1477
  // If type is an enum, returns value with a cast to the enum base type,
1478
  // otherwise returns value as-is.
1479
0
  std::string CastToBaseType(const Type& type, std::string value) {
1480
0
    if (type.enum_def == nullptr) {
1481
0
      return value;
1482
0
    } else {
1483
0
      return GenTypeBasic(type) + "(" + value + ")";
1484
0
    }
1485
0
  }
1486
1487
0
  std::string GenConstant(const FieldDef& field) {
1488
0
    if (field.IsScalarOptional()) {
1489
0
      return "nil";
1490
0
    }
1491
0
    switch (field.value.type.base_type) {
1492
0
      case BASE_TYPE_BOOL:
1493
0
        return field.value.constant == "0" ? "false" : "true";
1494
0
      case BASE_TYPE_FLOAT:
1495
0
      case BASE_TYPE_DOUBLE: {
1496
0
        const std::string float_type =
1497
0
            field.value.type.base_type == BASE_TYPE_FLOAT ? "float32"
1498
0
                                                          : "float64";
1499
0
        if (StringIsFlatbufferNan(field.value.constant)) {
1500
0
          needs_math_import_ = true;
1501
0
          return float_type + "(math.NaN())";
1502
0
        } else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
1503
0
          needs_math_import_ = true;
1504
0
          return float_type + "(math.Inf(1))";
1505
0
        } else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
1506
0
          needs_math_import_ = true;
1507
0
          return float_type + "(math.Inf(-1))";
1508
0
        }
1509
0
        return field.value.constant;
1510
0
      }
1511
0
      default:
1512
0
        return field.value.constant;
1513
0
    }
1514
0
  }
1515
1516
0
  std::string NativeName(const StructDef& struct_def) const {
1517
0
    return namer_.ObjectType(struct_def);
1518
0
  }
1519
1520
0
  std::string NativeName(const EnumDef& enum_def) const {
1521
0
    return namer_.ObjectType(enum_def);
1522
0
  }
1523
1524
0
  std::string NativeType(const Type& type) {
1525
0
    if (IsScalar(type.base_type)) {
1526
0
      if (type.enum_def == nullptr) {
1527
0
        return GenTypeBasic(type);
1528
0
      } else {
1529
0
        return GetEnumTypeName(*type.enum_def);
1530
0
      }
1531
0
    } else if (IsString(type)) {
1532
0
      return "string";
1533
0
    } else if (IsVector(type)) {
1534
0
      return "[]" + NativeType(type.VectorType());
1535
0
    } else if (type.base_type == BASE_TYPE_STRUCT) {
1536
0
      return "*" + WrapInNameSpaceAndTrack(type.struct_def,
1537
0
                                           NativeName(*type.struct_def));
1538
0
    } else if (type.base_type == BASE_TYPE_UNION) {
1539
0
      return "*" +
1540
0
             WrapInNameSpaceAndTrack(type.enum_def, NativeName(*type.enum_def));
1541
0
    }
1542
0
    FLATBUFFERS_ASSERT(0);
1543
0
    return std::string();
1544
0
  }
1545
1546
  // Create a struct with a builder and the struct's arguments.
1547
0
  void GenStructBuilder(const StructDef& struct_def, std::string* code_ptr) {
1548
0
    BeginBuilderArgs(struct_def, code_ptr);
1549
0
    StructBuilderArgs(struct_def, "", code_ptr);
1550
0
    EndBuilderArgs(code_ptr);
1551
1552
0
    StructBuilderBody(struct_def, "", code_ptr);
1553
0
    EndBuilderBody(code_ptr);
1554
0
  }
1555
1556
  // Begin by declaring namespace and imports.
1557
  void BeginFile(const std::string& name_space_name, const bool needs_imports,
1558
0
                 const bool is_enum, std::string* code_ptr) {
1559
0
    std::string& code = *code_ptr;
1560
0
    code = code +
1561
0
           "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
1562
0
    code += "package " + name_space_name + "\n\n";
1563
0
    if (needs_imports) {
1564
0
      code += "import (\n";
1565
      // standard imports, in alphabetical order for go fmt
1566
0
      if (needs_bytes_import_) code += "\t\"bytes\"\n";
1567
0
      if (!parser_.opts.go_import.empty()) {
1568
0
        code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
1569
0
      } else {
1570
0
        code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
1571
0
      }
1572
      // math is needed to support non-finite scalar default values.
1573
0
      if (needs_math_import_) {
1574
0
        code += "\t\"math\"\n";
1575
0
      }
1576
0
      if (is_enum) {
1577
0
        code += "\t\"strconv\"\n";
1578
0
      }
1579
1580
0
      if (tracked_imported_namespaces_.size() > 0) {
1581
0
        code += "\n";
1582
0
        for (auto it = tracked_imported_namespaces_.begin();
1583
0
             it != tracked_imported_namespaces_.end(); ++it) {
1584
0
          if ((*it)->defined_namespace->components.empty()) {
1585
0
            code += "\t" + (*it)->name + " \"" + (*it)->name + "\"\n";
1586
0
          } else {
1587
0
            code += "\t" + NamespaceImportName((*it)->defined_namespace) +
1588
0
                    " \"" + NamespaceImportPath((*it)->defined_namespace) +
1589
0
                    "\"\n";
1590
0
          }
1591
0
        }
1592
0
      }
1593
0
      code += ")\n\n";
1594
0
    } else {
1595
0
      if (is_enum) {
1596
0
        code += "import \"strconv\"\n\n";
1597
0
      }
1598
0
      if (needs_math_import_) {
1599
        // math is needed to support non-finite scalar default values.
1600
0
        code += "import \"math\"\n\n";
1601
0
      }
1602
0
    }
1603
0
  }
1604
1605
  // Resets the needed imports before generating a new file.
1606
0
  void ResetImports() {
1607
0
    tracked_imported_namespaces_.clear();
1608
0
    needs_bytes_import_ = false;
1609
0
    needs_math_import_ = false;
1610
0
  }
1611
1612
  // Save out the generated code for a Go Table type.
1613
  bool SaveType(const Definition& def, const std::string& classcode,
1614
0
                const bool needs_imports, const bool is_enum) {
1615
0
    if (!classcode.length()) return true;
1616
1617
0
    Namespace& ns = go_namespace_.components.empty() ? *def.defined_namespace
1618
0
                                                     : go_namespace_;
1619
0
    std::string code = "";
1620
0
    BeginFile(ns.components.empty() ? def.name : LastNamespacePart(ns),
1621
0
              needs_imports, is_enum, &code);
1622
0
    code += classcode;
1623
    // Strip extra newlines at end of file to make it gofmt-clean.
1624
0
    while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
1625
0
      code.pop_back();
1626
0
    }
1627
0
    std::string directory = namer_.Directories(ns);
1628
0
    std::string file = namer_.File(def, SkipFile::Suffix);
1629
0
    EnsureDirExists(directory);
1630
0
    std::string filename = directory + file;
1631
0
    return parser_.opts.file_saver->SaveFile(filename.c_str(), code, false);
1632
0
  }
1633
1634
  // Create the full name of the imported namespace (format: A__B__C).
1635
0
  std::string NamespaceImportName(const Namespace* ns) const {
1636
0
    return namer_.Namespace(*ns);
1637
0
  }
1638
1639
  // Create the full path for the imported namespace (format: A/B/C).
1640
0
  std::string NamespaceImportPath(const Namespace* ns) const {
1641
0
    std::string path =
1642
0
        namer_.Directories(*ns, SkipDir::OutputPathAndTrailingPathSeparator);
1643
0
    if (!parser_.opts.go_module_name.empty()) {
1644
0
      path = parser_.opts.go_module_name + "/" + path;
1645
0
    }
1646
0
    return path;
1647
0
  }
1648
1649
  // Ensure that a type is prefixed with its go package import name if it is
1650
  // used outside of its namespace.
1651
  std::string WrapInNameSpaceAndTrack(const Definition* def,
1652
0
                                      const std::string& name) {
1653
0
    if (CurrentNameSpace() == def->defined_namespace) return name;
1654
0
    tracked_imported_namespaces_.insert(def);
1655
0
    if (def->defined_namespace->components.empty())
1656
0
      return def->name + "." + name;
1657
0
    else
1658
0
      return NamespaceImportName(def->defined_namespace) + "." + name;
1659
0
  }
1660
1661
0
  const Namespace* CurrentNameSpace() const { return cur_name_space_; }
1662
1663
0
  static size_t MaxNameLength(const EnumDef& enum_def) {
1664
0
    size_t max = 0;
1665
0
    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1666
0
      max = std::max((*it)->name.length(), max);
1667
0
    }
1668
0
    return max;
1669
0
  }
1670
};
1671
}  // namespace go
1672
1673
static bool GenerateGo(const Parser& parser, const std::string& path,
1674
0
                       const std::string& file_name) {
1675
0
  go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
1676
0
  return generator.generate();
1677
0
}
1678
1679
namespace {
1680
1681
class GoCodeGenerator : public CodeGenerator {
1682
 public:
1683
  Status GenerateCode(const Parser& parser, const std::string& path,
1684
0
                      const std::string& filename) override {
1685
0
    if (!GenerateGo(parser, path, filename)) {
1686
0
      return Status::ERROR;
1687
0
    }
1688
0
    return Status::OK;
1689
0
  }
1690
1691
0
  Status GenerateCode(const uint8_t*, int64_t, const CodeGenOptions&) override {
1692
0
    return Status::NOT_IMPLEMENTED;
1693
0
  }
1694
1695
  Status GenerateMakeRule(const Parser& parser, const std::string& path,
1696
                          const std::string& filename,
1697
0
                          std::string& output) override {
1698
0
    (void)parser;
1699
0
    (void)path;
1700
0
    (void)filename;
1701
0
    (void)output;
1702
0
    return Status::NOT_IMPLEMENTED;
1703
0
  }
1704
1705
  Status GenerateGrpcCode(const Parser& parser, const std::string& path,
1706
0
                          const std::string& filename) override {
1707
0
    if (!GenerateGoGRPC(parser, path, filename)) {
1708
0
      return Status::ERROR;
1709
0
    }
1710
0
    return Status::OK;
1711
0
  }
1712
1713
  Status GenerateRootFile(const Parser& parser,
1714
0
                          const std::string& path) override {
1715
0
    (void)parser;
1716
0
    (void)path;
1717
0
    return Status::NOT_IMPLEMENTED;
1718
0
  }
1719
1720
0
  bool IsSchemaOnly() const override { return true; }
1721
1722
0
  bool SupportsBfbsGeneration() const override { return false; }
1723
1724
0
  bool SupportsRootFileGeneration() const override { return false; }
1725
1726
0
  IDLOptions::Language Language() const override { return IDLOptions::kGo; }
1727
1728
0
  std::string LanguageName() const override { return "Go"; }
1729
};
1730
}  // namespace
1731
1732
0
std::unique_ptr<CodeGenerator> NewGoCodeGenerator() {
1733
0
  return std::unique_ptr<GoCodeGenerator>(new GoCodeGenerator());
1734
0
}
1735
1736
}  // namespace flatbuffers