blob: cb605defd1c8674c975975269dc575de6f7c0f5f [file] [log] [blame]
Austin Schuh272c6132020-11-14 16:37:52 -08001/*
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 Kuszmaul8e62b022022-03-22 09:33:25 -070019#include <unordered_set>
20
Austin Schuh272c6132020-11-14 16:37:52 -080021#include "flatbuffers/code_generators.h"
22#include "flatbuffers/flatbuffers.h"
23#include "flatbuffers/idl.h"
24#include "flatbuffers/util.h"
25
Austin Schuh272c6132020-11-14 16:37:52 -080026namespace flatbuffers {
27
28static TypedFloatConstantGenerator CSharpFloatGen("Double.", "Single.", "NaN",
29 "PositiveInfinity",
30 "NegativeInfinity");
31static CommentConfig comment_config = {
32 nullptr,
33 "///",
34 nullptr,
35};
36
37namespace csharp {
38class CSharpGenerator : public BaseGenerator {
39 struct FieldArrayLength {
40 std::string name;
41 int length;
42 };
43
44 public:
45 CSharpGenerator(const Parser &parser, const std::string &path,
46 const std::string &file_name)
James Kuszmaul8e62b022022-03-22 09:33:25 -070047 : BaseGenerator(parser, path, file_name,
48 parser.opts.cs_global_alias ? "global::" : "", ".", "cs"),
49 cur_name_space_(nullptr) {
50 // clang-format off
51
52 // List of keywords retrieved from here:
53 // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
54
55 // One per line to ease comparisons to that list are easier
56
57 static const char *const keywords[] = {
58 "abstract",
59 "as",
60 "base",
61 "bool",
62 "break",
63 "byte",
64 "case",
65 "catch",
66 "char",
67 "checked",
68 "class",
69 "const",
70 "continue",
71 "decimal",
72 "default",
73 "delegate",
74 "do",
75 "double",
76 "else",
77 "enum",
78 "event",
79 "explicit",
80 "extern",
81 "false",
82 "finally",
83 "fixed",
84 "float",
85 "for",
86 "foreach",
87 "goto",
88 "if",
89 "implicit",
90 "in",
91 "int",
92 "interface",
93 "internal",
94 "is",
95 "lock",
96 "long",
97 "namespace",
98 "new",
99 "null",
100 "object",
101 "operator",
102 "out",
103 "override",
104 "params",
105 "private",
106 "protected",
107 "public",
108 "readonly",
109 "ref",
110 "return",
111 "sbyte",
112 "sealed",
113 "short",
114 "sizeof",
115 "stackalloc",
116 "static",
117 "string",
118 "struct",
119 "switch",
120 "this",
121 "throw",
122 "true",
123 "try",
124 "typeof",
125 "uint",
126 "ulong",
127 "unchecked",
128 "unsafe",
129 "ushort",
130 "using",
131 "virtual",
132 "void",
133 "volatile",
134 "while",
135 nullptr,
136 // clang-format on
137 };
138
139 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
140 }
Austin Schuh272c6132020-11-14 16:37:52 -0800141
142 CSharpGenerator &operator=(const CSharpGenerator &);
143
144 bool generate() {
145 std::string one_file_code;
146 cur_name_space_ = parser_.current_namespace_;
147
148 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
149 ++it) {
150 std::string enumcode;
151 auto &enum_def = **it;
152 if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
153 GenEnum(enum_def, &enumcode, parser_.opts);
154 if (parser_.opts.one_file) {
155 one_file_code += enumcode;
156 } else {
157 if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700158 false, parser_.opts))
Austin Schuh272c6132020-11-14 16:37:52 -0800159 return false;
160 }
161 }
162
163 for (auto it = parser_.structs_.vec.begin();
164 it != parser_.structs_.vec.end(); ++it) {
165 std::string declcode;
166 auto &struct_def = **it;
167 if (!parser_.opts.one_file)
168 cur_name_space_ = struct_def.defined_namespace;
169 GenStruct(struct_def, &declcode, parser_.opts);
170 if (parser_.opts.one_file) {
171 one_file_code += declcode;
172 } else {
173 if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700174 true, parser_.opts))
Austin Schuh272c6132020-11-14 16:37:52 -0800175 return false;
176 }
177 }
178
179 if (parser_.opts.one_file) {
180 return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700181 true, parser_.opts);
Austin Schuh272c6132020-11-14 16:37:52 -0800182 }
183 return true;
184 }
185
James Kuszmaul8e62b022022-03-22 09:33:25 -0700186 private:
187 std::unordered_set<std::string> keywords_;
188
189 std::string EscapeKeyword(const std::string &name) const {
190 return keywords_.find(name) == keywords_.end() ? name : "@" + name;
191 }
192
193 std::string Name(const FieldDef &field) const {
194 std::string name = ConvertCase(field.name, Case::kUpperCamel);
195 return EscapeKeyword(name);
196 }
197
198 std::string Name(const Definition &def) const {
199 return EscapeKeyword(def.name);
200 }
201
202 std::string NamespacedName(const Definition &def) const {
203 return WrapInNameSpace(def.defined_namespace, Name(def));
204 }
205
206 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
207
Austin Schuh272c6132020-11-14 16:37:52 -0800208 // Save out the generated code for a single class while adding
209 // declaration boilerplate.
210 bool SaveType(const std::string &defname, const Namespace &ns,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700211 const std::string &classcode, bool needs_includes,
212 const IDLOptions &options) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800213 if (!classcode.length()) return true;
214
215 std::string code =
216 "// <auto-generated>\n"
217 "// " +
218 std::string(FlatBuffersGeneratedWarning()) +
219 "\n"
220 "// </auto-generated>\n\n";
221
222 std::string namespace_name = FullNamespace(".", ns);
223 if (!namespace_name.empty()) {
224 code += "namespace " + namespace_name + "\n{\n\n";
225 }
226 if (needs_includes) {
227 code += "using global::System;\n";
228 code += "using global::System.Collections.Generic;\n";
229 code += "using global::FlatBuffers;\n\n";
230 }
231 code += classcode;
232 if (!namespace_name.empty()) { code += "\n}\n"; }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700233 auto filename = NamespaceDir(ns) + defname;
234 if (options.one_file) { filename += options.filename_suffix; }
235 filename +=
236 options.filename_extension.empty() ? ".cs" : options.filename_extension;
Austin Schuh272c6132020-11-14 16:37:52 -0800237 return SaveFile(filename.c_str(), code, false);
238 }
239
240 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
241
242 std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
243 // clang-format off
244 static const char * const csharp_typename[] = {
245 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, ...) \
246 #NTYPE,
247 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
248 #undef FLATBUFFERS_TD
249 };
250 // clang-format on
251
252 if (enableLangOverrides) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700253 if (IsEnum(type)) return NamespacedName(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800254 if (type.base_type == BASE_TYPE_STRUCT) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700255 return "Offset<" + NamespacedName(*type.struct_def) + ">";
Austin Schuh272c6132020-11-14 16:37:52 -0800256 }
257 }
258
259 return csharp_typename[type.base_type];
260 }
261
262 inline std::string GenTypeBasic(const Type &type) const {
263 return GenTypeBasic(type, true);
264 }
265
266 std::string GenTypePointer(const Type &type) const {
267 switch (type.base_type) {
268 case BASE_TYPE_STRING: return "string";
269 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
James Kuszmaul8e62b022022-03-22 09:33:25 -0700270 case BASE_TYPE_STRUCT: return NamespacedName(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800271 case BASE_TYPE_UNION: return "TTable";
272 default: return "Table";
273 }
274 }
275
276 std::string GenTypeGet(const Type &type) const {
277 return IsScalar(type.base_type)
278 ? GenTypeBasic(type)
279 : (IsArray(type) ? GenTypeGet(type.VectorType())
280 : GenTypePointer(type));
281 }
282
283 std::string GenOffsetType(const StructDef &struct_def) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700284 return "Offset<" + NamespacedName(struct_def) + ">";
Austin Schuh272c6132020-11-14 16:37:52 -0800285 }
286
287 std::string GenOffsetConstruct(const StructDef &struct_def,
288 const std::string &variable_name) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700289 return "new Offset<" + NamespacedName(struct_def) + ">(" + variable_name +
Austin Schuh272c6132020-11-14 16:37:52 -0800290 ")";
291 }
292
293 // Casts necessary to correctly read serialized data
294 std::string DestinationCast(const Type &type) const {
295 if (IsSeries(type)) {
296 return DestinationCast(type.VectorType());
297 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700298 if (IsEnum(type)) return "(" + NamespacedName(*type.enum_def) + ")";
Austin Schuh272c6132020-11-14 16:37:52 -0800299 }
300 return "";
301 }
302
303 // Cast statements for mutator method parameters.
304 // In Java, parameters representing unsigned numbers need to be cast down to
305 // their respective type. For example, a long holding an unsigned int value
306 // would be cast down to int before being put onto the buffer. In C#, one cast
307 // directly cast an Enum to its underlying type, which is essential before
308 // putting it onto the buffer.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700309 std::string SourceCast(const Type &type,
310 const bool isOptional = false) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800311 if (IsSeries(type)) {
312 return SourceCast(type.VectorType());
313 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700314 if (IsEnum(type))
315 return "(" + GenTypeBasic(type, false) + (isOptional ? "?" : "") + ")";
Austin Schuh272c6132020-11-14 16:37:52 -0800316 }
317 return "";
318 }
319
James Kuszmaul8e62b022022-03-22 09:33:25 -0700320 std::string SourceCastBasic(const Type &type, const bool isOptional) const {
321 return IsScalar(type.base_type) ? SourceCast(type, isOptional) : "";
Austin Schuh272c6132020-11-14 16:37:52 -0800322 }
323
324 std::string GenEnumDefaultValue(const FieldDef &field) const {
325 auto &value = field.value;
326 FLATBUFFERS_ASSERT(value.type.enum_def);
327 auto &enum_def = *value.type.enum_def;
328 auto enum_val = enum_def.FindByValue(value.constant);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700329 return enum_val ? (NamespacedName(enum_def) + "." + Name(*enum_val))
Austin Schuh272c6132020-11-14 16:37:52 -0800330 : value.constant;
331 }
332
333 std::string GenDefaultValue(const FieldDef &field,
334 bool enableLangOverrides) const {
335 // If it is an optional scalar field, the default is null
336 if (field.IsScalarOptional()) { return "null"; }
337
338 auto &value = field.value;
339 if (enableLangOverrides) {
340 // handles both enum case and vector of enum case
341 if (value.type.enum_def != nullptr &&
342 value.type.base_type != BASE_TYPE_UNION) {
343 return GenEnumDefaultValue(field);
344 }
345 }
346
347 auto longSuffix = "";
348 switch (value.type.base_type) {
349 case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
350 case BASE_TYPE_ULONG: return value.constant;
351 case BASE_TYPE_UINT:
352 case BASE_TYPE_LONG: return value.constant + longSuffix;
353 default:
354 if (IsFloat(value.type.base_type))
355 return CSharpFloatGen.GenFloatConstant(field);
356 else
357 return value.constant;
358 }
359 }
360
361 std::string GenDefaultValue(const FieldDef &field) const {
362 return GenDefaultValue(field, true);
363 }
364
365 std::string GenDefaultValueBasic(const FieldDef &field,
366 bool enableLangOverrides) const {
367 auto &value = field.value;
368 if (!IsScalar(value.type.base_type)) {
369 if (enableLangOverrides) {
370 switch (value.type.base_type) {
371 case BASE_TYPE_STRING: return "default(StringOffset)";
372 case BASE_TYPE_STRUCT:
James Kuszmaul8e62b022022-03-22 09:33:25 -0700373 return "default(Offset<" + NamespacedName(*value.type.struct_def) +
Austin Schuh272c6132020-11-14 16:37:52 -0800374 ">)";
375 case BASE_TYPE_VECTOR: return "default(VectorOffset)";
376 default: break;
377 }
378 }
379 return "0";
380 }
381 return GenDefaultValue(field, enableLangOverrides);
382 }
383
384 std::string GenDefaultValueBasic(const FieldDef &field) const {
385 return GenDefaultValueBasic(field, true);
386 }
387
388 void GenEnum(EnumDef &enum_def, std::string *code_ptr,
389 const IDLOptions &opts) const {
390 std::string &code = *code_ptr;
391 if (enum_def.generated) return;
392
393 // Generate enum definitions of the form:
394 // public static (final) int name = value;
395 // In Java, we use ints rather than the Enum feature, because we want them
396 // to map directly to how they're used in C/C++ and file formats.
397 // That, and Java Enums are expensive, and not universally liked.
398 GenComment(enum_def.doc_comment, code_ptr, &comment_config);
399
400 if (opts.cs_gen_json_serializer && opts.generate_object_based_api) {
401 code +=
402 "[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters."
403 "StringEnumConverter))]\n";
404 }
405 // In C# this indicates enumeration values can be treated as bit flags.
406 if (enum_def.attributes.Lookup("bit_flags")) {
407 code += "[System.FlagsAttribute]\n";
408 }
409 if (enum_def.attributes.Lookup("private")) {
410 code += "internal ";
411 } else {
412 code += "public ";
413 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700414 code += "enum " + Name(enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800415 code += " : " + GenTypeBasic(enum_def.underlying_type, false);
416 code += "\n{\n";
417 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
418 auto &ev = **it;
419 GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
420 code += " ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700421 code += Name(ev) + " = ";
Austin Schuh272c6132020-11-14 16:37:52 -0800422 code += enum_def.ToString(ev);
423 code += ",\n";
424 }
425 // Close the class
426 code += "};\n\n";
427
428 if (opts.generate_object_based_api) {
429 GenEnum_ObjectAPI(enum_def, code_ptr, opts);
430 }
431 }
432
433 bool HasUnionStringValue(const EnumDef &enum_def) const {
434 if (!enum_def.is_union) return false;
435 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
436 auto &val = **it;
437 if (IsString(val.union_type)) { return true; }
438 }
439 return false;
440 }
441
442 // Returns the function name that is able to read a value of the given type.
443 std::string GenGetter(const Type &type) const {
444 switch (type.base_type) {
445 case BASE_TYPE_STRING: return "__p.__string";
446 case BASE_TYPE_STRUCT: return "__p.__struct";
447 case BASE_TYPE_UNION: return "__p.__union";
448 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
449 case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
450 default: {
451 std::string getter = "__p.bb.Get";
452 if (type.base_type == BASE_TYPE_BOOL) {
453 getter = "0!=" + getter;
454 } else if (GenTypeBasic(type, false) != "byte") {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700455 getter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
Austin Schuh272c6132020-11-14 16:37:52 -0800456 }
457 return getter;
458 }
459 }
460 }
461
462 // Returns the function name that is able to read a value of the given type.
463 std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
464 const std::string &data_buffer,
465 const char *num = nullptr) const {
466 auto type = key_field->value.type;
467 auto dest_mask = "";
468 auto dest_cast = DestinationCast(type);
469 auto getter = data_buffer + ".Get";
470 if (GenTypeBasic(type, false) != "byte") {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700471 getter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
Austin Schuh272c6132020-11-14 16:37:52 -0800472 }
473 getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
474 dest_mask;
475 return getter;
476 }
477
478 // Direct mutation is only allowed for scalar fields.
479 // Hence a setter method will only be generated for such fields.
480 std::string GenSetter(const Type &type) const {
481 if (IsScalar(type.base_type)) {
482 std::string setter = "__p.bb.Put";
483 if (GenTypeBasic(type, false) != "byte" &&
484 type.base_type != BASE_TYPE_BOOL) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700485 setter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
Austin Schuh272c6132020-11-14 16:37:52 -0800486 }
487 return setter;
488 } else {
489 return "";
490 }
491 }
492
493 // Returns the method name for use with add/put calls.
494 std::string GenMethod(const Type &type) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700495 return IsScalar(type.base_type)
496 ? ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel)
497 : (IsStruct(type) ? "Struct" : "Offset");
Austin Schuh272c6132020-11-14 16:37:52 -0800498 }
499
500 // Recursively generate arguments for a constructor, to deal with nested
501 // structs.
502 void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
503 const char *nameprefix, size_t array_count = 0) const {
504 std::string &code = *code_ptr;
505 for (auto it = struct_def.fields.vec.begin();
506 it != struct_def.fields.vec.end(); ++it) {
507 auto &field = **it;
508 const auto &field_type = field.value.type;
509 const auto array_field = IsArray(field_type);
510 const auto &type = array_field ? field_type.VectorType() : field_type;
511 const auto array_cnt = array_field ? (array_count + 1) : array_count;
512 if (IsStruct(type)) {
513 // Generate arguments for a struct inside a struct. To ensure names
514 // don't clash, and to make it obvious these arguments are constructing
515 // a nested struct, prefix the name with the field name.
516 GenStructArgs(*field_type.struct_def, code_ptr,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700517 (nameprefix + (EscapeKeyword(field.name) + "_")).c_str(),
518 array_cnt);
Austin Schuh272c6132020-11-14 16:37:52 -0800519 } else {
520 code += ", ";
521 code += GenTypeBasic(type);
522 if (field.IsScalarOptional()) { code += "?"; }
523 if (array_cnt > 0) {
524 code += "[";
525 for (size_t i = 1; i < array_cnt; i++) code += ",";
526 code += "]";
527 }
528 code += " ";
529 code += nameprefix;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700530 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800531 }
532 }
533 }
534
535 // Recusively generate struct construction statements of the form:
536 // builder.putType(name);
537 // and insert manual padding.
538 void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
539 const char *nameprefix, size_t index = 0,
540 bool in_array = false) const {
541 std::string &code = *code_ptr;
542 std::string indent((index + 1) * 2, ' ');
543 code += indent + " builder.Prep(";
544 code += NumToString(struct_def.minalign) + ", ";
545 code += NumToString(struct_def.bytesize) + ");\n";
546 for (auto it = struct_def.fields.vec.rbegin();
547 it != struct_def.fields.vec.rend(); ++it) {
548 auto &field = **it;
549 const auto &field_type = field.value.type;
550 if (field.padding) {
551 code += indent + " builder.Pad(";
552 code += NumToString(field.padding) + ");\n";
553 }
554 if (IsStruct(field_type)) {
555 GenStructBody(*field_type.struct_def, code_ptr,
556 (nameprefix + (field.name + "_")).c_str(), index,
557 in_array);
558 } else {
559 const auto &type =
560 IsArray(field_type) ? field_type.VectorType() : field_type;
561 const auto index_var = "_idx" + NumToString(index);
562 if (IsArray(field_type)) {
563 code += indent + " for (int " + index_var + " = ";
564 code += NumToString(field_type.fixed_length);
565 code += "; " + index_var + " > 0; " + index_var + "--) {\n";
566 in_array = true;
567 }
568 if (IsStruct(type)) {
569 GenStructBody(*field_type.struct_def, code_ptr,
570 (nameprefix + (field.name + "_")).c_str(), index + 1,
571 in_array);
572 } else {
573 code += IsArray(field_type) ? " " : "";
574 code += indent + " builder.Put";
575 code += GenMethod(type) + "(";
576 code += SourceCast(type);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700577 auto argname = nameprefix + Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800578 code += argname;
579 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
580 if (array_cnt > 0) {
581 code += "[";
582 for (size_t i = 0; in_array && i < array_cnt; i++) {
583 code += "_idx" + NumToString(i) + "-1";
584 if (i != (array_cnt - 1)) code += ",";
585 }
586 code += "]";
587 }
588 code += ");\n";
589 }
590 if (IsArray(field_type)) { code += indent + " }\n"; }
591 }
592 }
593 }
594 std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
595 const char *num = nullptr) const {
596 std::string key_offset =
597 "Table.__offset(" + NumToString(key_field->value.offset) + ", ";
598 if (num) {
599 key_offset += num;
600 key_offset += ".Value, builder.DataBuffer)";
601 } else {
602 key_offset += "bb.Length";
603 key_offset += " - tableOffset, bb)";
604 }
605 return key_offset;
606 }
607
608 std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
609 std::string key_getter = " ";
610 key_getter += "int tableOffset = Table.";
611 key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
612 key_getter += ", bb);\n ";
613 if (IsString(key_field->value.type)) {
614 key_getter += "int comp = Table.";
615 key_getter += "CompareStrings(";
616 key_getter += GenOffsetGetter(key_field);
617 key_getter += ", byteKey, bb);\n";
618 } else {
619 auto get_val = GenGetterForLookupByKey(key_field, "bb");
620 key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
621 }
622 return key_getter;
623 }
624
625 std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
626 std::string key_getter = "";
627 auto data_buffer = "builder.DataBuffer";
628 if (IsString(key_field->value.type)) {
629 key_getter += "Table.CompareStrings(";
630 key_getter += GenOffsetGetter(key_field, "o1") + ", ";
631 key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
632 } else {
633 auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
634 key_getter += field_getter;
635 field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
636 key_getter += ".CompareTo(" + field_getter + ")";
637 }
638 return key_getter;
639 }
640
641 void GenStruct(StructDef &struct_def, std::string *code_ptr,
642 const IDLOptions &opts) const {
643 if (struct_def.generated) return;
644 std::string &code = *code_ptr;
645
646 // Generate a struct accessor class, with methods of the form:
647 // public type name() { return bb.getType(i + offset); }
648 // or for tables of the form:
649 // public type name() {
650 // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
651 // }
652 GenComment(struct_def.doc_comment, code_ptr, &comment_config);
653 if (struct_def.attributes.Lookup("private")) {
654 code += "internal ";
655 } else {
656 code += "public ";
657 }
658 if (struct_def.attributes.Lookup("csharp_partial")) {
659 // generate a partial class for this C# struct/table
660 code += "partial ";
661 }
662 code += "struct " + struct_def.name;
663 code += " : IFlatbufferObject";
664 code += "\n{\n";
665 code += " private ";
666 code += struct_def.fixed ? "Struct" : "Table";
667 code += " __p;\n";
668
669 code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
670
671 if (!struct_def.fixed) {
672 // Generate verson check method.
673 // Force compile time error if not using the same version runtime.
674 code += " public static void ValidateVersion() {";
675 code += " FlatBufferConstants.";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700676 code += "FLATBUFFERS_2_0_0(); ";
Austin Schuh272c6132020-11-14 16:37:52 -0800677 code += "}\n";
678
679 // Generate a special accessor for the table that when used as the root
680 // of a FlatBuffer
681 std::string method_name = "GetRootAs" + struct_def.name;
682 std::string method_signature =
683 " public static " + struct_def.name + " " + method_name;
684
685 // create convenience method that doesn't require an existing object
686 code += method_signature + "(ByteBuffer _bb) ";
687 code += "{ return " + method_name + "(_bb, new " + struct_def.name +
688 "()); }\n";
689
690 // create method that allows object reuse
691 code +=
692 method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
693 code += "return (obj.__assign(_bb.GetInt(_bb.Position";
694 code += ") + _bb.Position";
695 code += ", _bb)); }\n";
696 if (parser_.root_struct_def_ == &struct_def) {
697 if (parser_.file_identifier_.length()) {
698 // Check if a buffer has the identifier.
699 code += " public static ";
700 code += "bool " + struct_def.name;
701 code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
702 code += "Table.__has_identifier(_bb, \"";
703 code += parser_.file_identifier_;
704 code += "\"); }\n";
705 }
706 }
707 }
708 // Generate the __init method that sets the field in a pre-existing
709 // accessor object. This is to allow object reuse.
710 code += " public void __init(int _i, ByteBuffer _bb) ";
711 code += "{ ";
712 code += "__p = new ";
713 code += struct_def.fixed ? "Struct" : "Table";
714 code += "(_i, _bb); ";
715 code += "}\n";
716 code +=
717 " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
718 code += "{ __init(_i, _bb); return this; }\n\n";
719 for (auto it = struct_def.fields.vec.begin();
720 it != struct_def.fields.vec.end(); ++it) {
721 auto &field = **it;
722 if (field.deprecated) continue;
723 GenComment(field.doc_comment, code_ptr, &comment_config, " ");
724 std::string type_name = GenTypeGet(field.value.type);
725 std::string type_name_dest = GenTypeGet(field.value.type);
726 std::string conditional_cast = "";
727 std::string optional = "";
728 if (!struct_def.fixed &&
729 (field.value.type.base_type == BASE_TYPE_STRUCT ||
730 field.value.type.base_type == BASE_TYPE_UNION ||
731 (IsVector(field.value.type) &&
732 (field.value.type.element == BASE_TYPE_STRUCT ||
733 field.value.type.element == BASE_TYPE_UNION)))) {
734 optional = "?";
735 conditional_cast = "(" + type_name_dest + optional + ")";
736 }
737 if (field.IsScalarOptional()) { optional = "?"; }
738 std::string dest_mask = "";
739 std::string dest_cast = DestinationCast(field.value.type);
740 std::string src_cast = SourceCast(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700741 std::string field_name_camel = Name(field);
742 if (field_name_camel == struct_def.name) { field_name_camel += "_"; }
Austin Schuh272c6132020-11-14 16:37:52 -0800743 std::string method_start =
744 " public " + type_name_dest + optional + " " + field_name_camel;
745 std::string obj = "(new " + type_name + "())";
746
747 // Most field accessors need to retrieve and test the field offset first,
748 // this is the prefix code for that:
749 auto offset_prefix =
750 IsArray(field.value.type)
751 ? " { return "
752 : (" { int o = __p.__offset(" + NumToString(field.value.offset) +
753 "); return o != 0 ? ");
754 // Generate the accessors that don't do object reuse.
755 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
756 } else if (IsVector(field.value.type) &&
757 field.value.type.element == BASE_TYPE_STRUCT) {
758 } else if (field.value.type.base_type == BASE_TYPE_UNION ||
759 (IsVector(field.value.type) &&
760 field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
761 method_start += "<TTable>";
762 type_name = type_name_dest;
763 }
764 std::string getter = dest_cast + GenGetter(field.value.type);
765 code += method_start;
766 std::string default_cast = "";
767 // only create default casts for c# scalars or vectors of scalars
768 if ((IsScalar(field.value.type.base_type) ||
769 (IsVector(field.value.type) &&
770 IsScalar(field.value.type.element)))) {
771 // For scalars, default value will be returned by GetDefaultValue().
772 // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
773 // that doesn't need to be casted. However, default values for enum
774 // elements of vectors are integer literals ("0") and are still casted
775 // for clarity.
776 // If the scalar is optional and enum, we still need the cast.
777 if ((field.value.type.enum_def == nullptr ||
778 IsVector(field.value.type)) ||
779 (IsEnum(field.value.type) && field.IsScalarOptional())) {
780 default_cast = "(" + type_name_dest + optional + ")";
781 }
782 }
783 std::string member_suffix = "; ";
784 if (IsScalar(field.value.type.base_type)) {
785 code += " { get";
786 member_suffix += "} ";
787 if (struct_def.fixed) {
788 code += " { return " + getter;
789 code += "(__p.bb_pos + ";
790 code += NumToString(field.value.offset) + ")";
791 code += dest_mask;
792 } else {
793 code += offset_prefix + getter;
794 code += "(o + __p.bb_pos)" + dest_mask;
795 code += " : " + default_cast;
796 code += GenDefaultValue(field);
797 }
798 } else {
799 switch (field.value.type.base_type) {
800 case BASE_TYPE_STRUCT:
801 code += " { get";
802 member_suffix += "} ";
803 if (struct_def.fixed) {
804 code += " { return " + obj + ".__assign(" + "__p.";
805 code += "bb_pos + " + NumToString(field.value.offset) + ", ";
806 code += "__p.bb)";
807 } else {
808 code += offset_prefix + conditional_cast;
809 code += obj + ".__assign(";
810 code += field.value.type.struct_def->fixed
811 ? "o + __p.bb_pos"
812 : "__p.__indirect(o + __p.bb_pos)";
813 code += ", __p.bb) : null";
814 }
815 break;
816 case BASE_TYPE_STRING:
817 code += " { get";
818 member_suffix += "} ";
819 code += offset_prefix + getter + "(o + " + "__p.";
820 code += "bb_pos) : null";
821 break;
822 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
823 case BASE_TYPE_VECTOR: {
824 auto vectortype = field.value.type.VectorType();
825 if (vectortype.base_type == BASE_TYPE_UNION) {
826 conditional_cast = "(TTable?)";
827 getter += "<TTable>";
828 }
829 code += "(";
830 if (vectortype.base_type == BASE_TYPE_STRUCT) {
831 getter = obj + ".__assign";
832 } else if (vectortype.base_type == BASE_TYPE_UNION) {
833 }
834 code += "int j)";
835 const auto body = offset_prefix + conditional_cast + getter + "(";
836 if (vectortype.base_type == BASE_TYPE_UNION) {
837 code += " where TTable : struct, IFlatbufferObject" + body;
838 } else {
839 code += body;
840 }
841 std::string index = "__p.";
842 if (IsArray(field.value.type)) {
843 index += "bb_pos + " + NumToString(field.value.offset) + " + ";
844 } else {
845 index += "__vector(o) + ";
846 }
847 index += "j * " + NumToString(InlineSize(vectortype));
848 if (vectortype.base_type == BASE_TYPE_STRUCT) {
849 code += vectortype.struct_def->fixed
850 ? index
851 : "__p.__indirect(" + index + ")";
852 code += ", __p.bb";
853 } else {
854 code += index;
855 }
856 code += ")" + dest_mask;
857 if (!IsArray(field.value.type)) {
858 code += " : ";
859 code +=
860 field.value.type.element == BASE_TYPE_BOOL
861 ? "false"
862 : (IsScalar(field.value.type.element) ? default_cast + "0"
863 : "null");
864 }
865 if (vectortype.base_type == BASE_TYPE_UNION &&
866 HasUnionStringValue(*vectortype.enum_def)) {
867 code += member_suffix;
868 code += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700869 code += " public string " + Name(field) + "AsString(int j)";
Austin Schuh272c6132020-11-14 16:37:52 -0800870 code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
871 code += "(" + index + ") : null";
872 }
873 break;
874 }
875 case BASE_TYPE_UNION:
876 code += "() where TTable : struct, IFlatbufferObject";
877 code += offset_prefix + "(TTable?)" + getter;
878 code += "<TTable>(o + __p.bb_pos) : null";
879 if (HasUnionStringValue(*field.value.type.enum_def)) {
880 code += member_suffix;
881 code += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700882 code += " public string " + Name(field) + "AsString()";
Austin Schuh272c6132020-11-14 16:37:52 -0800883 code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
884 code += "(o + __p.bb_pos) : null";
885 }
886 // As<> accesors for Unions
887 // Loop through all the possible union types and generate an As
888 // accessor that casts to the correct type.
889 for (auto uit = field.value.type.enum_def->Vals().begin();
890 uit != field.value.type.enum_def->Vals().end(); ++uit) {
891 auto val = *uit;
892 if (val->union_type.base_type == BASE_TYPE_NONE) { continue; }
893 auto union_field_type_name = GenTypeGet(val->union_type);
894 code += member_suffix + "}\n";
895 if (val->union_type.base_type == BASE_TYPE_STRUCT &&
896 val->union_type.struct_def->attributes.Lookup("private")) {
897 code += " internal ";
898 } else {
899 code += " public ";
900 }
901 code += union_field_type_name + " ";
902 code += field_name_camel + "As" + val->name + "() { return ";
903 code += field_name_camel;
904 if (IsString(val->union_type)) {
905 code += "AsString()";
906 } else {
907 code += "<" + union_field_type_name + ">().Value";
908 }
909 }
910 break;
911 default: FLATBUFFERS_ASSERT(0);
912 }
913 }
914 code += member_suffix;
915 code += "}\n";
916 if (IsVector(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700917 code += " public int " + Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800918 code += "Length";
919 code += " { get";
920 code += offset_prefix;
921 code += "__p.__vector_len(o) : 0; ";
922 code += "} ";
923 code += "}\n";
924 // See if we should generate a by-key accessor.
925 if (field.value.type.element == BASE_TYPE_STRUCT &&
926 !field.value.type.struct_def->fixed) {
927 auto &sd = *field.value.type.struct_def;
928 auto &fields = sd.fields.vec;
929 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
930 auto &key_field = **kit;
931 if (key_field.key) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700932 auto qualified_name = NamespacedName(sd);
Austin Schuh272c6132020-11-14 16:37:52 -0800933 code += " public " + qualified_name + "? ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700934 code += Name(field) + "ByKey(";
Austin Schuh272c6132020-11-14 16:37:52 -0800935 code += GenTypeGet(key_field.value.type) + " key)";
936 code += offset_prefix;
937 code += qualified_name + ".__lookup_by_key(";
938 code += "__p.__vector(o), key, ";
939 code += "__p.bb) : null; ";
940 code += "}\n";
941 break;
942 }
943 }
944 }
945 }
946 // Generate a ByteBuffer accessor for strings & vectors of scalars.
947 if ((IsVector(field.value.type) &&
948 IsScalar(field.value.type.VectorType().base_type)) ||
949 IsString(field.value.type)) {
950 code += "#if ENABLE_SPAN_T\n";
951 code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
952 "> Get";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700953 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800954 code += "Bytes() { return ";
955 code += "__p.__vector_as_span<" +
956 GenTypeBasic(field.value.type.VectorType()) + ">(";
957 code += NumToString(field.value.offset);
958 code +=
959 ", " + NumToString(SizeOf(field.value.type.VectorType().base_type));
960 code += "); }\n";
961 code += "#else\n";
962 code += " public ArraySegment<byte>? Get";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700963 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800964 code += "Bytes() { return ";
965 code += "__p.__vector_as_arraysegment(";
966 code += NumToString(field.value.offset);
967 code += "); }\n";
968 code += "#endif\n";
969
970 // For direct blockcopying the data into a typed array
971 code += " public ";
972 code += GenTypeBasic(field.value.type.VectorType());
973 code += "[] Get";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700974 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800975 code += "Array() { ";
976 if (IsEnum(field.value.type.VectorType())) {
977 // Since __vector_as_array does not work for enum types,
978 // fill array using an explicit loop.
979 code += "int o = __p.__offset(";
980 code += NumToString(field.value.offset);
981 code += "); if (o == 0) return null; int p = ";
982 code += "__p.__vector(o); int l = ";
983 code += "__p.__vector_len(o); ";
984 code += GenTypeBasic(field.value.type.VectorType());
985 code += "[] a = new ";
986 code += GenTypeBasic(field.value.type.VectorType());
987 code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter;
988 code += "(p + i * ";
989 code += NumToString(InlineSize(field.value.type.VectorType()));
990 code += "); } return a;";
991 } else {
992 code += "return ";
993 code += "__p.__vector_as_array<";
994 code += GenTypeBasic(field.value.type.VectorType());
995 code += ">(";
996 code += NumToString(field.value.offset);
997 code += ");";
998 }
999 code += " }\n";
1000 }
1001 // generate object accessors if is nested_flatbuffer
1002 if (field.nested_flatbuffer) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001003 auto nested_type_name = NamespacedName(*field.nested_flatbuffer);
Austin Schuh272c6132020-11-14 16:37:52 -08001004 auto nested_method_name =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001005 Name(field) + "As" + field.nested_flatbuffer->name;
Austin Schuh272c6132020-11-14 16:37:52 -08001006 auto get_nested_method_name = nested_method_name;
1007 get_nested_method_name = "Get" + nested_method_name;
1008 conditional_cast = "(" + nested_type_name + "?)";
1009 obj = "(new " + nested_type_name + "())";
1010 code += " public " + nested_type_name + "? ";
1011 code += get_nested_method_name + "(";
1012 code += ") { int o = __p.__offset(";
1013 code += NumToString(field.value.offset) + "); ";
1014 code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
1015 code += "__p.";
1016 code += "__indirect(__p.__vector(o)), ";
1017 code += "__p.bb) : null; }\n";
1018 }
1019 // Generate mutators for scalar fields or vectors of scalars.
1020 if (parser_.opts.mutable_buffer) {
1021 auto is_series = (IsSeries(field.value.type));
1022 const auto &underlying_type =
1023 is_series ? field.value.type.VectorType() : field.value.type;
1024 // Boolean parameters have to be explicitly converted to byte
1025 // representation.
James Kuszmaul8e62b022022-03-22 09:33:25 -07001026 auto setter_parameter =
1027 underlying_type.base_type == BASE_TYPE_BOOL
1028 ? "(byte)(" + EscapeKeyword(field.name) + " ? 1 : 0)"
1029 : EscapeKeyword(field.name);
1030 auto mutator_prefix = "Mutate";
Austin Schuh272c6132020-11-14 16:37:52 -08001031 // A vector mutator also needs the index of the vector element it should
1032 // mutate.
1033 auto mutator_params = (is_series ? "(int j, " : "(") +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001034 GenTypeGet(underlying_type) + " " +
1035 EscapeKeyword(field.name) + ") { ";
Austin Schuh272c6132020-11-14 16:37:52 -08001036 auto setter_index =
1037 is_series
1038 ? "__p." +
1039 (IsArray(field.value.type)
1040 ? "bb_pos + " + NumToString(field.value.offset)
1041 : "__vector(o)") +
1042 +" + j * " + NumToString(InlineSize(underlying_type))
1043 : (struct_def.fixed
1044 ? "__p.bb_pos + " + NumToString(field.value.offset)
1045 : "o + __p.bb_pos");
1046 if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
1047 code += " public ";
1048 code += struct_def.fixed ? "void " : "bool ";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001049 code += mutator_prefix + Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001050 code += mutator_params;
1051 if (struct_def.fixed) {
1052 code += GenSetter(underlying_type) + "(" + setter_index + ", ";
1053 code += src_cast + setter_parameter + "); }\n";
1054 } else {
1055 code += "int o = __p.__offset(";
1056 code += NumToString(field.value.offset) + ");";
1057 code += " if (o != 0) { " + GenSetter(underlying_type);
1058 code += "(" + setter_index + ", " + src_cast + setter_parameter +
1059 "); return true; } else { return false; } }\n";
1060 }
1061 }
1062 }
1063 if (parser_.opts.java_primitive_has_method &&
1064 IsScalar(field.value.type.base_type) && !struct_def.fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001065 auto vt_offset_constant =
1066 " public static final int VT_" +
1067 ConvertCase(field.name, Case::kScreamingSnake) + " = " +
1068 NumToString(field.value.offset) + ";";
Austin Schuh272c6132020-11-14 16:37:52 -08001069
1070 code += vt_offset_constant;
1071 code += "\n";
1072 }
1073 }
1074 code += "\n";
1075 auto struct_has_create = false;
1076 std::set<flatbuffers::FieldDef *> field_has_create_set;
1077 flatbuffers::FieldDef *key_field = nullptr;
1078 if (struct_def.fixed) {
1079 struct_has_create = true;
1080 // create a struct constructor function
1081 code += " public static " + GenOffsetType(struct_def) + " ";
1082 code += "Create";
1083 code += struct_def.name + "(FlatBufferBuilder builder";
1084 GenStructArgs(struct_def, code_ptr, "");
1085 code += ") {\n";
1086 GenStructBody(struct_def, code_ptr, "");
1087 code += " return ";
1088 code += GenOffsetConstruct(struct_def, "builder.Offset");
1089 code += ";\n }\n";
1090 } else {
1091 // Generate a method that creates a table in one go. This is only possible
1092 // when the table has no struct fields, since those have to be created
1093 // inline, and there's no way to do so in Java.
1094 bool has_no_struct_fields = true;
1095 int num_fields = 0;
1096 for (auto it = struct_def.fields.vec.begin();
1097 it != struct_def.fields.vec.end(); ++it) {
1098 auto &field = **it;
1099 if (field.deprecated) continue;
1100 if (IsStruct(field.value.type)) {
1101 has_no_struct_fields = false;
1102 } else {
1103 num_fields++;
1104 }
1105 }
1106 // JVM specifications restrict default constructor params to be < 255.
1107 // Longs and doubles take up 2 units, so we set the limit to be < 127.
1108 if ((has_no_struct_fields || opts.generate_object_based_api) &&
1109 num_fields && num_fields < 127) {
1110 struct_has_create = true;
1111 // Generate a table constructor of the form:
1112 // public static int createName(FlatBufferBuilder builder, args...)
1113 code += " public static " + GenOffsetType(struct_def) + " ";
1114 code += "Create" + struct_def.name;
1115 code += "(FlatBufferBuilder builder";
1116 for (auto it = struct_def.fields.vec.begin();
1117 it != struct_def.fields.vec.end(); ++it) {
1118 auto &field = **it;
1119 if (field.deprecated) continue;
1120 code += ",\n ";
1121 if (IsStruct(field.value.type) && opts.generate_object_based_api) {
1122 code += WrapInNameSpace(
1123 field.value.type.struct_def->defined_namespace,
1124 GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts));
1125 code += " ";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001126 code += EscapeKeyword(field.name);
Austin Schuh272c6132020-11-14 16:37:52 -08001127 code += " = null";
1128 } else {
1129 code += GenTypeBasic(field.value.type);
1130 if (field.IsScalarOptional()) { code += "?"; }
1131 code += " ";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001132 code += EscapeKeyword(field.name);
Austin Schuh272c6132020-11-14 16:37:52 -08001133 if (!IsScalar(field.value.type.base_type)) code += "Offset";
1134
1135 code += " = ";
1136 code += GenDefaultValueBasic(field);
1137 }
1138 }
1139 code += ") {\n builder.";
1140 code += "StartTable(";
1141 code += NumToString(struct_def.fields.vec.size()) + ");\n";
1142 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1143 size; size /= 2) {
1144 for (auto it = struct_def.fields.vec.rbegin();
1145 it != struct_def.fields.vec.rend(); ++it) {
1146 auto &field = **it;
1147 if (!field.deprecated &&
1148 (!struct_def.sortbysize ||
1149 size == SizeOf(field.value.type.base_type))) {
1150 code += " " + struct_def.name + ".";
1151 code += "Add";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001152 code += Name(field) + "(builder, ";
Austin Schuh272c6132020-11-14 16:37:52 -08001153 if (IsStruct(field.value.type) &&
1154 opts.generate_object_based_api) {
1155 code += GenTypePointer(field.value.type) + ".Pack(builder, " +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001156 EscapeKeyword(field.name) + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001157 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001158 code += EscapeKeyword(field.name);
Austin Schuh272c6132020-11-14 16:37:52 -08001159 if (!IsScalar(field.value.type.base_type)) code += "Offset";
1160 }
1161
1162 code += ");\n";
1163 }
1164 }
1165 }
1166 code += " return " + struct_def.name + ".";
1167 code += "End" + struct_def.name;
1168 code += "(builder);\n }\n\n";
1169 }
1170 // Generate a set of static methods that allow table construction,
1171 // of the form:
1172 // public static void addName(FlatBufferBuilder builder, short name)
1173 // { builder.addShort(id, name, default); }
1174 // Unlike the Create function, these always work.
1175 code += " public static void Start";
1176 code += struct_def.name;
1177 code += "(FlatBufferBuilder builder) { builder.";
1178 code += "StartTable(";
1179 code += NumToString(struct_def.fields.vec.size()) + "); }\n";
1180 for (auto it = struct_def.fields.vec.begin();
1181 it != struct_def.fields.vec.end(); ++it) {
1182 auto &field = **it;
1183 if (field.deprecated) continue;
1184 if (field.key) key_field = &field;
1185 code += " public static void Add";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001186 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001187 code += "(FlatBufferBuilder builder, ";
1188 code += GenTypeBasic(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001189 auto argname = ConvertCase(field.name, Case::kLowerCamel);
Austin Schuh272c6132020-11-14 16:37:52 -08001190 if (!IsScalar(field.value.type.base_type)) argname += "Offset";
1191 if (field.IsScalarOptional()) { code += "?"; }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001192 code += " " + EscapeKeyword(argname) + ") { builder.Add";
Austin Schuh272c6132020-11-14 16:37:52 -08001193 code += GenMethod(field.value.type) + "(";
1194 code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001195 code += SourceCastBasic(field.value.type, field.IsScalarOptional());
1196 code += EscapeKeyword(argname);
Austin Schuh272c6132020-11-14 16:37:52 -08001197 if (!IsScalar(field.value.type.base_type) &&
1198 field.value.type.base_type != BASE_TYPE_UNION) {
1199 code += ".Value";
1200 }
1201 if (!field.IsScalarOptional()) {
1202 // When the scalar is optional, use the builder method that doesn't
1203 // supply a default value. Otherwise, we to continue to use the
1204 // default value method.
1205 code += ", ";
1206 code += GenDefaultValue(field, false);
1207 }
1208 code += "); }\n";
1209 if (IsVector(field.value.type)) {
1210 auto vector_type = field.value.type.VectorType();
1211 auto alignment = InlineAlignment(vector_type);
1212 auto elem_size = InlineSize(vector_type);
1213 if (!IsStruct(vector_type)) {
1214 field_has_create_set.insert(&field);
1215 code += " public static VectorOffset ";
1216 code += "Create";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001217 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001218 code += "Vector(FlatBufferBuilder builder, ";
1219 code += GenTypeBasic(vector_type) + "[] data) ";
1220 code += "{ builder.StartVector(";
1221 code += NumToString(elem_size);
1222 code += ", data.Length, ";
1223 code += NumToString(alignment);
1224 code += "); for (int i = data.";
1225 code += "Length - 1; i >= 0; i--) builder.";
1226 code += "Add";
1227 code += GenMethod(vector_type);
1228 code += "(";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001229 // At the moment there is no support of the type Vector with
1230 // optional enum, e.g. if we have enum type SomeEnum there is no way
1231 // to define `SomeEmum?[] enums` in FlatBuffer schema, so isOptional
1232 // = false
1233 code += SourceCastBasic(vector_type, false);
Austin Schuh272c6132020-11-14 16:37:52 -08001234 code += "data[i]";
1235 if (vector_type.base_type == BASE_TYPE_STRUCT ||
1236 IsString(vector_type))
1237 code += ".Value";
1238 code += "); return ";
1239 code += "builder.EndVector(); }\n";
1240
1241 code += " public static VectorOffset ";
1242 code += "Create";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001243 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001244 code += "VectorBlock(FlatBufferBuilder builder, ";
1245 code += GenTypeBasic(vector_type) + "[] data) ";
1246 code += "{ builder.StartVector(";
1247 code += NumToString(elem_size);
1248 code += ", data.Length, ";
1249 code += NumToString(alignment);
1250 code += "); builder.Add(data); return builder.EndVector(); }\n";
1251 }
1252 // Generate a method to start a vector, data to be added manually
1253 // after.
1254 code += " public static void Start";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001255 code += Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001256 code += "Vector(FlatBufferBuilder builder, int numElems) ";
1257 code += "{ builder.StartVector(";
1258 code += NumToString(elem_size);
1259 code += ", numElems, " + NumToString(alignment);
1260 code += "); }\n";
1261 }
1262 }
1263 code += " public static " + GenOffsetType(struct_def) + " ";
1264 code += "End" + struct_def.name;
1265 code += "(FlatBufferBuilder builder) {\n int o = builder.";
1266 code += "EndTable();\n";
1267 for (auto it = struct_def.fields.vec.begin();
1268 it != struct_def.fields.vec.end(); ++it) {
1269 auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001270 if (!field.deprecated && field.IsRequired()) {
Austin Schuh272c6132020-11-14 16:37:52 -08001271 code += " builder.Required(o, ";
1272 code += NumToString(field.value.offset);
1273 code += "); // " + field.name + "\n";
1274 }
1275 }
1276 code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
1277 if (parser_.root_struct_def_ == &struct_def) {
1278 std::string size_prefix[] = { "", "SizePrefixed" };
1279 for (int i = 0; i < 2; ++i) {
1280 code += " public static void ";
1281 code += "Finish" + size_prefix[i] + struct_def.name;
1282 code +=
1283 "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def);
1284 code += " offset) {";
1285 code += " builder.Finish" + size_prefix[i] + "(offset";
1286 code += ".Value";
1287
1288 if (parser_.file_identifier_.length())
1289 code += ", \"" + parser_.file_identifier_ + "\"";
1290 code += "); }\n";
1291 }
1292 }
1293 }
1294 // Only generate key compare function for table,
1295 // because `key_field` is not set for struct
1296 if (struct_def.has_key && !struct_def.fixed) {
1297 FLATBUFFERS_ASSERT(key_field);
1298 code += "\n public static VectorOffset ";
1299 code += "CreateSortedVectorOf" + struct_def.name;
1300 code += "(FlatBufferBuilder builder, ";
1301 code += "Offset<" + struct_def.name + ">";
1302 code += "[] offsets) {\n";
1303 code += " Array.Sort(offsets, (Offset<" + struct_def.name +
1304 "> o1, Offset<" + struct_def.name + "> o2) => " +
1305 GenKeyGetter(key_field);
1306 code += ");\n";
1307 code += " return builder.CreateVectorOfTables(offsets);\n }\n";
1308
1309 code += "\n public static " + struct_def.name + "?";
1310 code += " __lookup_by_key(";
1311 code += "int vectorLocation, ";
1312 code += GenTypeGet(key_field->value.type);
1313 code += " key, ByteBuffer bb) {\n";
1314 if (IsString(key_field->value.type)) {
1315 code += " byte[] byteKey = ";
1316 code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
1317 }
1318 code += " int span = ";
1319 code += "bb.GetInt(vectorLocation - 4);\n";
1320 code += " int start = 0;\n";
1321 code += " while (span != 0) {\n";
1322 code += " int middle = span / 2;\n";
1323 code += GenLookupKeyGetter(key_field);
1324 code += " if (comp > 0) {\n";
1325 code += " span = middle;\n";
1326 code += " } else if (comp < 0) {\n";
1327 code += " middle++;\n";
1328 code += " start += middle;\n";
1329 code += " span -= middle;\n";
1330 code += " } else {\n";
1331 code += " return ";
1332 code += "new " + struct_def.name + "()";
1333 code += ".__assign(tableOffset, bb);\n";
1334 code += " }\n }\n";
1335 code += " return null;\n";
1336 code += " }\n";
1337 }
1338
1339 if (opts.generate_object_based_api) {
1340 GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
1341 field_has_create_set);
1342 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001343 code += "}\n\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001344
1345 if (opts.generate_object_based_api) {
1346 GenStruct_ObjectAPI(struct_def, code_ptr, opts);
1347 }
1348 }
1349
1350 void GenVectorAccessObject(StructDef &struct_def,
1351 std::string *code_ptr) const {
1352 auto &code = *code_ptr;
1353 // Generate a vector of structs accessor class.
1354 code += "\n";
1355 code += " ";
1356 if (!struct_def.attributes.Lookup("private")) code += "public ";
1357 code += "static struct Vector : BaseVector\n{\n";
1358
1359 // Generate the __assign method that sets the field in a pre-existing
1360 // accessor object. This is to allow object reuse.
1361 std::string method_indent = " ";
1362 code += method_indent + "public Vector ";
1363 code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1364 code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1365
1366 auto type_name = struct_def.name;
1367 auto method_start = method_indent + "public " + type_name + " Get";
1368 // Generate the accessors that don't do object reuse.
1369 code += method_start + "(int j) { return Get";
1370 code += "(new " + type_name + "(), j); }\n";
1371 code += method_start + "(" + type_name + " obj, int j) { ";
1372 code += " return obj.__assign(";
1373 code += struct_def.fixed ? "__p.__element(j)"
1374 : "__p.__indirect(__p.__element(j), bb)";
1375 code += ", __p.bb); }\n";
1376 // See if we should generate a by-key accessor.
1377 if (!struct_def.fixed) {
1378 auto &fields = struct_def.fields.vec;
1379 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1380 auto &key_field = **kit;
1381 if (key_field.key) {
1382 auto nullable_annotation =
1383 parser_.opts.gen_nullable ? "@Nullable " : "";
1384 code += method_indent + nullable_annotation;
1385 code += "public " + type_name + "? ";
1386 code += "GetByKey(";
1387 code += GenTypeGet(key_field.value.type) + " key) { ";
1388 code += " return __lookup_by_key(null, ";
1389 code += "__p.__vector(), key, ";
1390 code += "__p.bb); ";
1391 code += "}\n";
1392 code += method_indent + nullable_annotation;
1393 code += "public " + type_name + "?" + " ";
1394 code += "GetByKey(";
1395 code += type_name + "? obj, ";
1396 code += GenTypeGet(key_field.value.type) + " key) { ";
1397 code += " return __lookup_by_key(obj, ";
1398 code += "__p.__vector(), key, ";
1399 code += "__p.bb); ";
1400 code += "}\n";
1401 break;
1402 }
1403 }
1404 }
1405 code += " }\n";
1406 }
1407
1408 void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr,
1409 const IDLOptions &opts) const {
1410 auto &code = *code_ptr;
1411 if (enum_def.generated) return;
1412 if (!enum_def.is_union) return;
1413 if (enum_def.attributes.Lookup("private")) {
1414 code += "internal ";
1415 } else {
1416 code += "public ";
1417 }
1418 auto union_name = enum_def.name + "Union";
1419 code += "class " + union_name + " {\n";
1420 // Type
1421 code += " public " + enum_def.name + " Type { get; set; }\n";
1422 // Value
1423 code += " public object Value { get; set; }\n";
1424 code += "\n";
1425 // Constructor
1426 code += " public " + union_name + "() {\n";
1427 code += " this.Type = " + enum_def.name + "." +
1428 enum_def.Vals()[0]->name + ";\n";
1429 code += " this.Value = null;\n";
1430 code += " }\n\n";
1431 // As<T>
1432 code += " public T As<T>() where T : class { return this.Value as T; }\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001433 // As, From
Austin Schuh272c6132020-11-14 16:37:52 -08001434 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1435 auto &ev = **it;
1436 if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
1437 auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001438 std::string accessibility =
1439 (ev.union_type.base_type == BASE_TYPE_STRUCT &&
1440 ev.union_type.struct_def->attributes.Lookup("private"))
1441 ? "internal"
1442 : "public";
1443 // As
1444 code += " " + accessibility + " " + type_name + " As" + ev.name +
1445 "() { return this.As<" + type_name + ">(); }\n";
1446 // From
1447 auto lower_ev_name = ev.name;
1448 std::transform(lower_ev_name.begin(), lower_ev_name.end(),
1449 lower_ev_name.begin(), CharToLower);
1450 code += " " + accessibility + " static " + union_name + " From" +
1451 ev.name + "(" + type_name + " _" + lower_ev_name +
1452 ") { return new " + union_name + "{ Type = " + Name(enum_def) +
1453 "." + Name(ev) + ", Value = _" + lower_ev_name + " }; }\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001454 }
1455 code += "\n";
1456 // Pack()
1457 code += " public static int Pack(FlatBuffers.FlatBufferBuilder builder, " +
1458 union_name + " _o) {\n";
1459 code += " switch (_o.Type) {\n";
1460 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1461 auto &ev = **it;
1462 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1463 code += " default: return 0;\n";
1464 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001465 code += " case " + Name(enum_def) + "." + Name(ev) + ": return ";
Austin Schuh272c6132020-11-14 16:37:52 -08001466 if (IsString(ev.union_type)) {
1467 code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n";
1468 } else {
1469 code += GenTypeGet(ev.union_type) + ".Pack(builder, _o.As" + ev.name +
1470 "()).Value;\n";
1471 }
1472 }
1473 }
1474 code += " }\n";
1475 code += " }\n";
1476 code += "}\n\n";
1477 // JsonConverter
1478 if (opts.cs_gen_json_serializer) {
1479 if (enum_def.attributes.Lookup("private")) {
1480 code += "internal ";
1481 } else {
1482 code += "public ";
1483 }
1484 code += "class " + union_name +
1485 "_JsonConverter : Newtonsoft.Json.JsonConverter {\n";
1486 code += " public override bool CanConvert(System.Type objectType) {\n";
1487 code += " return objectType == typeof(" + union_name +
1488 ") || objectType == typeof(System.Collections.Generic.List<" +
1489 union_name + ">);\n";
1490 code += " }\n";
1491 code +=
1492 " public override void WriteJson(Newtonsoft.Json.JsonWriter writer, "
1493 "object value, "
1494 "Newtonsoft.Json.JsonSerializer serializer) {\n";
1495 code += " var _olist = value as System.Collections.Generic.List<" +
1496 union_name + ">;\n";
1497 code += " if (_olist != null) {\n";
1498 code += " writer.WriteStartArray();\n";
1499 code +=
1500 " foreach (var _o in _olist) { this.WriteJson(writer, _o, "
1501 "serializer); }\n";
1502 code += " writer.WriteEndArray();\n";
1503 code += " } else {\n";
1504 code += " this.WriteJson(writer, value as " + union_name +
1505 ", serializer);\n";
1506 code += " }\n";
1507 code += " }\n";
1508 code += " public void WriteJson(Newtonsoft.Json.JsonWriter writer, " +
1509 union_name +
1510 " _o, "
1511 "Newtonsoft.Json.JsonSerializer serializer) {\n";
1512 code += " if (_o == null) return;\n";
1513 code += " serializer.Serialize(writer, _o.Value);\n";
1514 code += " }\n";
1515 code +=
1516 " public override object ReadJson(Newtonsoft.Json.JsonReader "
1517 "reader, "
1518 "System.Type objectType, "
1519 "object existingValue, Newtonsoft.Json.JsonSerializer serializer) "
1520 "{\n";
1521 code +=
1522 " var _olist = existingValue as System.Collections.Generic.List<" +
1523 union_name + ">;\n";
1524 code += " if (_olist != null) {\n";
1525 code += " for (var _j = 0; _j < _olist.Count; ++_j) {\n";
1526 code += " reader.Read();\n";
1527 code +=
1528 " _olist[_j] = this.ReadJson(reader, _olist[_j], "
1529 "serializer);\n";
1530 code += " }\n";
1531 code += " reader.Read();\n";
1532 code += " return _olist;\n";
1533 code += " } else {\n";
1534 code += " return this.ReadJson(reader, existingValue as " +
1535 union_name + ", serializer);\n";
1536 code += " }\n";
1537 code += " }\n";
1538 code += " public " + union_name +
1539 " ReadJson(Newtonsoft.Json.JsonReader reader, " + union_name +
1540 " _o, Newtonsoft.Json.JsonSerializer serializer) {\n";
1541 code += " if (_o == null) return null;\n";
1542 code += " switch (_o.Type) {\n";
1543 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1544 ++it) {
1545 auto &ev = **it;
1546 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1547 code += " default: break;\n";
1548 } else {
1549 auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001550 code += " case " + Name(enum_def) + "." + Name(ev) +
Austin Schuh272c6132020-11-14 16:37:52 -08001551 ": _o.Value = serializer.Deserialize<" + type_name +
1552 ">(reader); break;\n";
1553 }
1554 }
1555 code += " }\n";
1556 code += " return _o;\n";
1557 code += " }\n";
1558 code += "}\n\n";
1559 }
1560 }
1561
1562 std::string GenTypeName_ObjectAPI(const std::string &name,
1563 const IDLOptions &opts) const {
1564 return opts.object_prefix + name + opts.object_suffix;
1565 }
1566
1567 void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string *code_ptr,
1568 const std::string &camel_name,
1569 bool is_vector) const {
1570 auto &code = *code_ptr;
1571 std::string varialbe_name = "_o." + camel_name;
1572 std::string type_suffix = "";
1573 std::string func_suffix = "()";
1574 std::string indent = " ";
1575 if (is_vector) {
1576 varialbe_name = "_o_" + camel_name;
1577 type_suffix = "(_j)";
1578 func_suffix = "(_j)";
1579 indent = " ";
1580 }
1581 if (is_vector) {
1582 code += indent + "var " + varialbe_name + " = new ";
1583 } else {
1584 code += indent + varialbe_name + " = new ";
1585 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001586 code += NamespacedName(enum_def) + "Union();\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001587 code += indent + varialbe_name + ".Type = this." + camel_name + "Type" +
1588 type_suffix + ";\n";
1589 code +=
1590 indent + "switch (this." + camel_name + "Type" + type_suffix + ") {\n";
1591 for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end();
1592 ++eit) {
1593 auto &ev = **eit;
1594 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1595 code += indent + " default: break;\n";
1596 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001597 code += indent + " case " + NamespacedName(enum_def) + "." + ev.name +
Austin Schuh272c6132020-11-14 16:37:52 -08001598 ":\n";
1599 code += indent + " " + varialbe_name + ".Value = this." + camel_name;
1600 if (IsString(ev.union_type)) {
1601 code += "AsString" + func_suffix + ";\n";
1602 } else {
1603 code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix;
1604 code += ".HasValue ? this." + camel_name;
1605 code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix +
1606 ".Value.UnPack() : null;\n";
1607 }
1608 code += indent + " break;\n";
1609 }
1610 }
1611 code += indent + "}\n";
1612 if (is_vector) {
1613 code += indent + "_o." + camel_name + ".Add(" + varialbe_name + ");\n";
1614 }
1615 }
1616
1617 void GenPackUnPack_ObjectAPI(
1618 StructDef &struct_def, std::string *code_ptr, const IDLOptions &opts,
1619 bool struct_has_create,
1620 const std::set<FieldDef *> &field_has_create) const {
1621 auto &code = *code_ptr;
1622 auto struct_name = GenTypeName_ObjectAPI(struct_def.name, opts);
1623 // UnPack()
1624 code += " public " + struct_name + " UnPack() {\n";
1625 code += " var _o = new " + struct_name + "();\n";
1626 code += " this.UnPackTo(_o);\n";
1627 code += " return _o;\n";
1628 code += " }\n";
1629 // UnPackTo()
1630 code += " public void UnPackTo(" + struct_name + " _o) {\n";
1631 for (auto it = struct_def.fields.vec.begin();
1632 it != struct_def.fields.vec.end(); ++it) {
1633 auto &field = **it;
1634 if (field.deprecated) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001635 auto camel_name = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001636 auto start = " _o." + camel_name + " = ";
1637 switch (field.value.type.base_type) {
1638 case BASE_TYPE_STRUCT: {
1639 auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
1640 if (fixed) {
1641 code += start + "this." + camel_name + ".UnPack();\n";
1642 } else {
1643 code += start + "this." + camel_name + ".HasValue ? this." +
1644 camel_name + ".Value.UnPack() : null;\n";
1645 }
1646 break;
1647 }
1648 case BASE_TYPE_ARRAY: {
1649 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
1650 auto length_str = NumToString(field.value.type.fixed_length);
1651 auto unpack_method = field.value.type.struct_def == nullptr ? ""
1652 : field.value.type.struct_def->fixed
1653 ? ".UnPack()"
1654 : "?.UnPack()";
1655 code += start + "new " + type_name.substr(0, type_name.length() - 1) +
1656 length_str + "];\n";
1657 code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." +
1658 camel_name + "[_j] = this." + camel_name + "(_j)" +
1659 unpack_method + "; }\n";
1660 break;
1661 }
1662 case BASE_TYPE_VECTOR:
1663 if (field.value.type.element == BASE_TYPE_UNION) {
1664 code += start + "new " +
1665 GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
1666 code += " for (var _j = 0; _j < this." + camel_name +
1667 "Length; ++_j) {\n";
1668 GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
1669 camel_name, true);
1670 code += " }\n";
1671 } else if (field.value.type.element != BASE_TYPE_UTYPE) {
1672 auto fixed = field.value.type.struct_def == nullptr;
1673 code += start + "new " +
1674 GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
1675 code += " for (var _j = 0; _j < this." + camel_name +
1676 "Length; ++_j) {";
1677 code += "_o." + camel_name + ".Add(";
1678 if (fixed) {
1679 code += "this." + camel_name + "(_j)";
1680 } else {
1681 code += "this." + camel_name + "(_j).HasValue ? this." +
1682 camel_name + "(_j).Value.UnPack() : null";
1683 }
1684 code += ");}\n";
1685 }
1686 break;
1687 case BASE_TYPE_UTYPE: break;
1688 case BASE_TYPE_UNION: {
1689 GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
1690 camel_name, false);
1691 break;
1692 }
1693 default: {
1694 code += start + "this." + camel_name + ";\n";
1695 break;
1696 }
1697 }
1698 }
1699 code += " }\n";
1700 // Pack()
1701 code += " public static " + GenOffsetType(struct_def) +
1702 " Pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
1703 code += " if (_o == null) return default(" + GenOffsetType(struct_def) +
1704 ");\n";
1705 for (auto it = struct_def.fields.vec.begin();
1706 it != struct_def.fields.vec.end(); ++it) {
1707 auto &field = **it;
1708 if (field.deprecated) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001709 auto camel_name = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001710 // pre
1711 switch (field.value.type.base_type) {
1712 case BASE_TYPE_STRUCT: {
1713 if (!field.value.type.struct_def->fixed) {
1714 code += " var _" + field.name + " = _o." + camel_name +
1715 " == null ? default(" +
1716 GenOffsetType(*field.value.type.struct_def) +
1717 ") : " + GenTypeGet(field.value.type) +
1718 ".Pack(builder, _o." + camel_name + ");\n";
1719 } else if (struct_def.fixed && struct_has_create) {
1720 std::vector<FieldArrayLength> array_lengths;
1721 FieldArrayLength tmp_array_length = {
1722 field.name,
1723 field.value.type.fixed_length,
1724 };
1725 array_lengths.push_back(tmp_array_length);
1726 GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
1727 array_lengths);
1728 }
1729 break;
1730 }
1731 case BASE_TYPE_STRING: {
1732 std::string create_string =
1733 field.shared ? "CreateSharedString" : "CreateString";
1734 code += " var _" + field.name + " = _o." + camel_name +
1735 " == null ? default(StringOffset) : "
1736 "builder." +
1737 create_string + "(_o." + camel_name + ");\n";
1738 break;
1739 }
1740 case BASE_TYPE_VECTOR: {
1741 if (field_has_create.find(&field) != field_has_create.end()) {
1742 auto property_name = camel_name;
1743 auto gen_for_loop = true;
1744 std::string array_name = "__" + field.name;
1745 std::string array_type = "";
1746 std::string to_array = "";
1747 switch (field.value.type.element) {
1748 case BASE_TYPE_STRING: {
1749 std::string create_string =
1750 field.shared ? "CreateSharedString" : "CreateString";
1751 array_type = "StringOffset";
1752 to_array += "builder." + create_string + "(_o." +
1753 property_name + "[_j])";
1754 break;
1755 }
1756 case BASE_TYPE_STRUCT:
1757 array_type = "Offset<" + GenTypeGet(field.value.type) + ">";
1758 to_array = GenTypeGet(field.value.type) + ".Pack(builder, _o." +
1759 property_name + "[_j])";
1760 break;
1761 case BASE_TYPE_UTYPE:
1762 property_name = camel_name.substr(0, camel_name.size() - 4);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001763 array_type = NamespacedName(*field.value.type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001764 to_array = "_o." + property_name + "[_j].Type";
1765 break;
1766 case BASE_TYPE_UNION:
1767 array_type = "int";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001768 to_array = NamespacedName(*field.value.type.enum_def) +
Austin Schuh272c6132020-11-14 16:37:52 -08001769 "Union.Pack(builder, _o." + property_name + "[_j])";
1770 break;
1771 default: gen_for_loop = false; break;
1772 }
1773 code += " var _" + field.name + " = default(VectorOffset);\n";
1774 code += " if (_o." + property_name + " != null) {\n";
1775 if (gen_for_loop) {
1776 code += " var " + array_name + " = new " + array_type +
1777 "[_o." + property_name + ".Count];\n";
1778 code += " for (var _j = 0; _j < " + array_name +
1779 ".Length; ++_j) { ";
1780 code += array_name + "[_j] = " + to_array + "; }\n";
1781 } else {
1782 code += " var " + array_name + " = _o." + property_name +
1783 ".ToArray();\n";
1784 }
1785 code += " _" + field.name + " = Create" + camel_name +
1786 "Vector(builder, " + array_name + ");\n";
1787 code += " }\n";
1788 } else {
1789 auto pack_method =
1790 field.value.type.struct_def == nullptr
1791 ? "builder.Add" + GenMethod(field.value.type.VectorType()) +
1792 "(_o." + camel_name + "[_j]);"
1793 : GenTypeGet(field.value.type) + ".Pack(builder, _o." +
1794 camel_name + "[_j]);";
1795 code += " var _" + field.name + " = default(VectorOffset);\n";
1796 code += " if (_o." + camel_name + " != null) {\n";
1797 code += " Start" + camel_name + "Vector(builder, _o." +
1798 camel_name + ".Count);\n";
1799 code += " for (var _j = _o." + camel_name +
1800 ".Count - 1; _j >= 0; --_j) { " + pack_method + " }\n";
1801 code += " _" + field.name + " = builder.EndVector();\n";
1802 code += " }\n";
1803 }
1804 break;
1805 }
1806 case BASE_TYPE_ARRAY: {
1807 if (field.value.type.struct_def != nullptr) {
1808 std::vector<FieldArrayLength> array_lengths;
1809 FieldArrayLength tmp_array_length = {
1810 field.name,
1811 field.value.type.fixed_length,
1812 };
1813 array_lengths.push_back(tmp_array_length);
1814 GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
1815 array_lengths);
1816 } else {
1817 code += " var _" + field.name + " = _o." + camel_name + ";\n";
1818 }
1819 break;
1820 }
1821 case BASE_TYPE_UNION: {
1822 code += " var _" + field.name + "_type = _o." + camel_name +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001823 " == null ? " + NamespacedName(*field.value.type.enum_def) +
Austin Schuh272c6132020-11-14 16:37:52 -08001824 ".NONE : " + "_o." + camel_name + ".Type;\n";
1825 code +=
1826 " var _" + field.name + " = _o." + camel_name +
1827 " == null ? 0 : " + GenTypeGet_ObjectAPI(field.value.type, opts) +
1828 ".Pack(builder, _o." + camel_name + ");\n";
1829 break;
1830 }
1831 default: break;
1832 }
1833 }
1834 if (struct_has_create) {
1835 // Create
1836 code += " return Create" + struct_def.name + "(\n";
1837 code += " builder";
1838 for (auto it = struct_def.fields.vec.begin();
1839 it != struct_def.fields.vec.end(); ++it) {
1840 auto &field = **it;
1841 if (field.deprecated) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001842 auto camel_name = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001843 switch (field.value.type.base_type) {
1844 case BASE_TYPE_STRUCT: {
1845 if (struct_def.fixed) {
1846 GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
1847 code_ptr,
1848 " _" + field.name + "_");
1849 } else {
1850 code += ",\n";
1851 if (field.value.type.struct_def->fixed) {
1852 if (opts.generate_object_based_api)
1853 code += " _o." + camel_name;
1854 else
1855 code += " " + GenTypeGet(field.value.type) +
1856 ".Pack(builder, _o." + camel_name + ")";
1857 } else {
1858 code += " _" + field.name;
1859 }
1860 }
1861 break;
1862 }
1863 case BASE_TYPE_ARRAY: {
1864 if (field.value.type.struct_def != nullptr) {
1865 GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
1866 code_ptr,
1867 " _" + field.name + "_");
1868 } else {
1869 code += ",\n";
1870 code += " _" + field.name;
1871 }
1872 break;
1873 }
1874 case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // fall thru
1875 case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH(); // fall thru
1876 case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
1877 case BASE_TYPE_VECTOR: {
1878 code += ",\n";
1879 code += " _" + field.name;
1880 break;
1881 }
1882 default: // scalar
1883 code += ",\n";
1884 code += " _o." + camel_name;
1885 break;
1886 }
1887 }
1888 code += ");\n";
1889 } else {
1890 // Start, End
1891 code += " Start" + struct_def.name + "(builder);\n";
1892 for (auto it = struct_def.fields.vec.begin();
1893 it != struct_def.fields.vec.end(); ++it) {
1894 auto &field = **it;
1895 if (field.deprecated) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001896 auto camel_name = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001897 switch (field.value.type.base_type) {
1898 case BASE_TYPE_STRUCT: {
1899 if (field.value.type.struct_def->fixed) {
1900 code += " Add" + camel_name + "(builder, " +
1901 GenTypeGet(field.value.type) + ".Pack(builder, _o." +
1902 camel_name + "));\n";
1903 } else {
1904 code +=
1905 " Add" + camel_name + "(builder, _" + field.name + ");\n";
1906 }
1907 break;
1908 }
1909 case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
1910 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
1911 case BASE_TYPE_VECTOR: {
1912 code +=
1913 " Add" + camel_name + "(builder, _" + field.name + ");\n";
1914 break;
1915 }
1916 case BASE_TYPE_UTYPE: break;
1917 case BASE_TYPE_UNION: {
1918 code += " Add" + camel_name + "Type(builder, _" + field.name +
1919 "_type);\n";
1920 code +=
1921 " Add" + camel_name + "(builder, _" + field.name + ");\n";
1922 break;
1923 }
1924 // scalar
1925 default: {
1926 code +=
1927 " Add" + camel_name + "(builder, _o." + camel_name + ");\n";
1928 break;
1929 }
1930 }
1931 }
1932 code += " return End" + struct_def.name + "(builder);\n";
1933 }
1934 code += " }\n";
1935 }
1936
1937 void GenStructPackDecl_ObjectAPI(
1938 const StructDef &struct_def, std::string *code_ptr,
1939 std::vector<FieldArrayLength> &array_lengths) const {
1940 auto &code = *code_ptr;
1941 for (auto it = struct_def.fields.vec.begin();
1942 it != struct_def.fields.vec.end(); ++it) {
1943 auto &field = **it;
1944 auto is_array = IsArray(field.value.type);
1945 const auto &field_type =
1946 is_array ? field.value.type.VectorType() : field.value.type;
1947 FieldArrayLength tmp_array_length = {
1948 field.name,
1949 field_type.fixed_length,
1950 };
1951 array_lengths.push_back(tmp_array_length);
1952 if (field_type.struct_def != nullptr) {
1953 GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr,
1954 array_lengths);
1955 } else {
1956 std::vector<FieldArrayLength> array_only_lengths;
1957 for (size_t i = 0; i < array_lengths.size(); ++i) {
1958 if (array_lengths[i].length > 0) {
1959 array_only_lengths.push_back(array_lengths[i]);
1960 }
1961 }
1962 std::string name;
1963 for (size_t i = 0; i < array_lengths.size(); ++i) {
1964 name += "_" + array_lengths[i].name;
1965 }
1966 code += " var " + name + " = ";
1967 if (array_only_lengths.size() > 0) {
1968 code += "new " + GenTypeBasic(field_type) + "[";
1969 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1970 if (i != 0) { code += ","; }
1971 code += NumToString(array_only_lengths[i].length);
1972 }
1973 code += "];\n";
1974 code += " ";
1975 // initialize array
1976 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1977 auto idx = "idx" + NumToString(i);
1978 code += "for (var " + idx + " = 0; " + idx + " < " +
1979 NumToString(array_only_lengths[i].length) + "; ++" + idx +
1980 ") {";
1981 }
1982 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1983 auto idx = "idx" + NumToString(i);
1984 if (i == 0) {
1985 code += name + "[" + idx;
1986 } else {
1987 code += "," + idx;
1988 }
1989 }
1990 code += "] = _o";
1991 for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001992 code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel);
Austin Schuh272c6132020-11-14 16:37:52 -08001993 if (array_lengths[i].length <= 0) continue;
1994 code += "[idx" + NumToString(j++) + "]";
1995 }
1996 code += ";";
1997 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1998 code += "}";
1999 }
2000 } else {
2001 code += "_o";
2002 for (size_t i = 0; i < array_lengths.size(); ++i) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002003 code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel);
Austin Schuh272c6132020-11-14 16:37:52 -08002004 }
2005 code += ";";
2006 }
2007 code += "\n";
2008 }
2009 array_lengths.pop_back();
2010 }
2011 }
2012
2013 void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
2014 std::string *code_ptr,
2015 std::string prefix) const {
2016 auto &code = *code_ptr;
2017 for (auto it = struct_def.fields.vec.begin();
2018 it != struct_def.fields.vec.end(); ++it) {
2019 auto &field = **it;
2020 const auto &field_type = field.value.type;
2021 if (field_type.struct_def != nullptr) {
2022 GenStructPackCall_ObjectAPI(*field_type.struct_def, code_ptr,
2023 prefix + field.name + "_");
2024 } else {
2025 code += ",\n";
2026 code += prefix + field.name;
2027 }
2028 }
2029 }
2030
2031 std::string GenTypeGet_ObjectAPI(flatbuffers::Type type,
2032 const IDLOptions &opts) const {
2033 auto type_name = GenTypeGet(type);
2034 // Replace to ObjectBaseAPI Type Name
2035 switch (type.base_type) {
2036 case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru
2037 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
2038 case BASE_TYPE_VECTOR: {
2039 if (type.struct_def != nullptr) {
2040 auto type_name_length = type.struct_def->name.length();
2041 auto new_type_name =
2042 GenTypeName_ObjectAPI(type.struct_def->name, opts);
2043 type_name.replace(type_name.length() - type_name_length,
2044 type_name_length, new_type_name);
2045 } else if (type.element == BASE_TYPE_UNION) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002046 type_name = NamespacedName(*type.enum_def) + "Union";
Austin Schuh272c6132020-11-14 16:37:52 -08002047 }
2048 break;
2049 }
2050
2051 case BASE_TYPE_UNION: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002052 type_name = NamespacedName(*type.enum_def) + "Union";
Austin Schuh272c6132020-11-14 16:37:52 -08002053 break;
2054 }
2055 default: break;
2056 }
2057
2058 switch (type.base_type) {
2059 case BASE_TYPE_ARRAY: {
2060 type_name = type_name + "[]";
2061 break;
2062 }
2063 case BASE_TYPE_VECTOR: {
2064 type_name = "List<" + type_name + ">";
2065 break;
2066 }
2067 default: break;
2068 }
2069 return type_name;
2070 }
2071
2072 void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr,
2073 const IDLOptions &opts) const {
2074 auto &code = *code_ptr;
2075 if (struct_def.attributes.Lookup("private")) {
2076 code += "internal ";
2077 } else {
2078 code += "public ";
2079 }
2080 if (struct_def.attributes.Lookup("csharp_partial")) {
2081 // generate a partial class for this C# struct/table
2082 code += "partial ";
2083 }
2084 auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts);
2085 code += "class " + class_name;
2086 code += "\n{\n";
2087 // Generate Properties
2088 for (auto it = struct_def.fields.vec.begin();
2089 it != struct_def.fields.vec.end(); ++it) {
2090 auto &field = **it;
2091 if (field.deprecated) continue;
2092 if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2093 if (field.value.type.element == BASE_TYPE_UTYPE) continue;
2094 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
James Kuszmaul8e62b022022-03-22 09:33:25 -07002095 if (field.IsScalarOptional()) type_name += "?";
2096 auto camel_name = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08002097 if (opts.cs_gen_json_serializer) {
2098 if (IsUnion(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002099 auto utype_name = NamespacedName(*field.value.type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08002100 code +=
2101 " [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n";
2102 if (IsVector(field.value.type)) {
2103 code += " private " + utype_name + "[] " + camel_name + "Type {\n";
2104 code += " get {\n";
2105 code += " if (this." + camel_name + " == null) return null;\n";
2106 code += " var _o = new " + utype_name + "[this." + camel_name +
2107 ".Count];\n";
2108 code +=
2109 " for (var _j = 0; _j < _o.Length; ++_j) { _o[_j] = "
2110 "this." +
2111 camel_name + "[_j].Type; }\n";
2112 code += " return _o;\n";
2113 code += " }\n";
2114 code += " set {\n";
2115 code += " this." + camel_name + " = new List<" + utype_name +
2116 "Union>();\n";
2117 code += " for (var _j = 0; _j < value.Length; ++_j) {\n";
2118 code += " var _o = new " + utype_name + "Union();\n";
2119 code += " _o.Type = value[_j];\n";
2120 code += " this." + camel_name + ".Add(_o);\n";
2121 code += " }\n";
2122 code += " }\n";
2123 code += " }\n";
2124 } else {
2125 code += " private " + utype_name + " " + camel_name + "Type {\n";
2126 code += " get {\n";
2127 code += " return this." + camel_name + " != null ? this." +
2128 camel_name + ".Type : " + utype_name + ".NONE;\n";
2129 code += " }\n";
2130 code += " set {\n";
2131 code += " this." + camel_name + " = new " + utype_name +
2132 "Union();\n";
2133 code += " this." + camel_name + ".Type = value;\n";
2134 code += " }\n";
2135 code += " }\n";
2136 }
2137 }
2138 code += " [Newtonsoft.Json.JsonProperty(\"" + field.name + "\")]\n";
2139 if (IsUnion(field.value.type)) {
2140 auto union_name =
2141 (IsVector(field.value.type))
2142 ? GenTypeGet_ObjectAPI(field.value.type.VectorType(), opts)
2143 : type_name;
2144 code += " [Newtonsoft.Json.JsonConverter(typeof(" + union_name +
2145 "_JsonConverter))]\n";
2146 }
2147 if (field.attributes.Lookup("hash")) {
2148 code += " [Newtonsoft.Json.JsonIgnore()]\n";
2149 }
2150 }
2151 code += " public " + type_name + " " + camel_name + " { get; set; }\n";
2152 }
2153 // Generate Constructor
2154 code += "\n";
2155 code += " public " + class_name + "() {\n";
2156 for (auto it = struct_def.fields.vec.begin();
2157 it != struct_def.fields.vec.end(); ++it) {
2158 auto &field = **it;
2159 if (field.deprecated) continue;
2160 if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2161 if (field.value.type.element == BASE_TYPE_UTYPE) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -07002162 code += " this." + Name(field) + " = ";
Austin Schuh272c6132020-11-14 16:37:52 -08002163 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
2164 if (IsScalar(field.value.type.base_type)) {
2165 code += GenDefaultValue(field) + ";\n";
2166 } else {
2167 switch (field.value.type.base_type) {
2168 case BASE_TYPE_STRUCT: {
2169 if (IsStruct(field.value.type)) {
2170 code += "new " + type_name + "();\n";
2171 } else {
2172 code += "null;\n";
2173 }
2174 break;
2175 }
2176 case BASE_TYPE_ARRAY: {
2177 code += "new " + type_name.substr(0, type_name.length() - 1) +
2178 NumToString(field.value.type.fixed_length) + "];\n";
2179 break;
2180 }
2181 default: {
2182 code += "null;\n";
2183 break;
2184 }
2185 }
2186 }
2187 }
2188 code += " }\n";
2189 // Generate Serialization
2190 if (opts.cs_gen_json_serializer &&
2191 parser_.root_struct_def_ == &struct_def) {
2192 code += "\n";
2193 code += " public static " + class_name +
2194 " DeserializeFromJson(string jsonText) {\n";
2195 code += " return Newtonsoft.Json.JsonConvert.DeserializeObject<" +
2196 class_name + ">(jsonText);\n";
2197 code += " }\n";
2198 code += " public string SerializeToJson() {\n";
2199 code +=
2200 " return Newtonsoft.Json.JsonConvert.SerializeObject(this, "
2201 "Newtonsoft.Json.Formatting.Indented);\n";
2202 code += " }\n";
2203 }
2204 if (parser_.root_struct_def_ == &struct_def) {
2205 code += " public static " + class_name +
2206 " DeserializeFromBinary(byte[] fbBuffer) {\n";
2207 code += " return " + struct_def.name + ".GetRootAs" + struct_def.name +
2208 "(new ByteBuffer(fbBuffer)).UnPack();\n";
2209 code += " }\n";
2210 code += " public byte[] SerializeToBinary() {\n";
2211 code += " var fbb = new FlatBufferBuilder(0x10000);\n";
2212 code += " " + struct_def.name + ".Finish" + struct_def.name +
2213 "Buffer(fbb, " + struct_def.name + ".Pack(fbb, this));\n";
2214 code += " return fbb.DataBuffer.ToSizedArray();\n";
2215 code += " }\n";
2216 }
2217 code += "}\n\n";
2218 }
2219
2220 // This tracks the current namespace used to determine if a type need to be
2221 // prefixed by its namespace
2222 const Namespace *cur_name_space_;
2223};
2224} // namespace csharp
2225
2226bool GenerateCSharp(const Parser &parser, const std::string &path,
2227 const std::string &file_name) {
2228 csharp::CSharpGenerator generator(parser, path, file_name);
2229 return generator.generate();
2230}
2231
2232} // namespace flatbuffers