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_csharp.h"
20
21 #include <unordered_set>
22
23 #include "flatbuffers/code_generators.h"
24 #include "flatbuffers/flatbuffers.h"
25 #include "flatbuffers/idl.h"
26 #include "flatbuffers/util.h"
27
28 namespace flatbuffers {
29
30 static TypedFloatConstantGenerator CSharpFloatGen("Double.", "Single.", "NaN",
31 "PositiveInfinity",
32 "NegativeInfinity");
33 static CommentConfig comment_config = {
34 nullptr,
35 "///",
36 nullptr,
37 };
38
39 namespace csharp {
40 class CSharpGenerator : public BaseGenerator {
41 struct FieldArrayLength {
42 std::string name;
43 int length;
44 };
45
46 public:
CSharpGenerator(const Parser & parser,const std::string & path,const std::string & file_name)47 CSharpGenerator(const Parser &parser, const std::string &path,
48 const std::string &file_name)
49 : BaseGenerator(parser, path, file_name,
50 parser.opts.cs_global_alias ? "global::" : "", ".", "cs"),
51 cur_name_space_(nullptr) {
52 // clang-format off
53
54 // List of keywords retrieved from here:
55 // https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
56
57 // One per line to ease comparisons to that list are easier
58
59 static const char *const keywords[] = {
60 "abstract",
61 "as",
62 "base",
63 "bool",
64 "break",
65 "byte",
66 "case",
67 "catch",
68 "char",
69 "checked",
70 "class",
71 "const",
72 "continue",
73 "decimal",
74 "default",
75 "delegate",
76 "do",
77 "double",
78 "else",
79 "enum",
80 "event",
81 "explicit",
82 "extern",
83 "false",
84 "finally",
85 "fixed",
86 "float",
87 "for",
88 "foreach",
89 "goto",
90 "if",
91 "implicit",
92 "in",
93 "int",
94 "interface",
95 "internal",
96 "is",
97 "lock",
98 "long",
99 "namespace",
100 "new",
101 "null",
102 "object",
103 "operator",
104 "out",
105 "override",
106 "params",
107 "private",
108 "protected",
109 "public",
110 "readonly",
111 "ref",
112 "return",
113 "sbyte",
114 "sealed",
115 "short",
116 "sizeof",
117 "stackalloc",
118 "static",
119 "string",
120 "struct",
121 "switch",
122 "this",
123 "throw",
124 "true",
125 "try",
126 "typeof",
127 "uint",
128 "ulong",
129 "unchecked",
130 "unsafe",
131 "ushort",
132 "using",
133 "virtual",
134 "void",
135 "volatile",
136 "while",
137 nullptr,
138 // clang-format on
139 };
140
141 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
142 }
143
144 CSharpGenerator &operator=(const CSharpGenerator &);
145
generate()146 bool generate() {
147 std::string one_file_code;
148 cur_name_space_ = parser_.current_namespace_;
149
150 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
151 ++it) {
152 std::string enumcode;
153 auto &enum_def = **it;
154 if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
155 GenEnum(enum_def, &enumcode, parser_.opts);
156 if (parser_.opts.one_file) {
157 one_file_code += enumcode;
158 } else {
159 if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
160 false, parser_.opts))
161 return false;
162 }
163 }
164
165 for (auto it = parser_.structs_.vec.begin();
166 it != parser_.structs_.vec.end(); ++it) {
167 std::string declcode;
168 auto &struct_def = **it;
169 if (!parser_.opts.one_file)
170 cur_name_space_ = struct_def.defined_namespace;
171 GenStruct(struct_def, &declcode, parser_.opts);
172 GenStructVerifier(struct_def, &declcode);
173 if (parser_.opts.one_file) {
174 one_file_code += declcode;
175 } else {
176 if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
177 true, parser_.opts))
178 return false;
179 }
180 }
181
182 if (parser_.opts.one_file) {
183 return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
184 true, parser_.opts);
185 }
186 return true;
187 }
188
189 private:
190 std::unordered_set<std::string> keywords_;
191
EscapeKeyword(const std::string & name) const192 std::string EscapeKeyword(const std::string &name) const {
193 return keywords_.find(name) == keywords_.end() ? name : "@" + name;
194 }
195
Name(const FieldDef & field) const196 std::string Name(const FieldDef &field) const {
197 std::string name = ConvertCase(field.name, Case::kUpperCamel);
198 return EscapeKeyword(name);
199 }
200
Name(const Definition & def) const201 std::string Name(const Definition &def) const {
202 return EscapeKeyword(def.name);
203 }
204
NamespacedName(const Definition & def) const205 std::string NamespacedName(const Definition &def) const {
206 return WrapInNameSpace(def.defined_namespace, Name(def));
207 }
208
Name(const EnumVal & ev) const209 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
210
211 // Save out the generated code for a single class while adding
212 // declaration boilerplate.
SaveType(const std::string & defname,const Namespace & ns,const std::string & classcode,bool needs_includes,const IDLOptions & options) const213 bool SaveType(const std::string &defname, const Namespace &ns,
214 const std::string &classcode, bool needs_includes,
215 const IDLOptions &options) const {
216 if (!classcode.length()) return true;
217
218 std::string code =
219 "// <auto-generated>\n"
220 "// " +
221 std::string(FlatBuffersGeneratedWarning()) +
222 "\n"
223 "// </auto-generated>\n\n";
224
225 std::string namespace_name = FullNamespace(".", ns);
226 if (!namespace_name.empty()) {
227 code += "namespace " + namespace_name + "\n{\n\n";
228 }
229 if (needs_includes) {
230 code += "using global::System;\n";
231 code += "using global::System.Collections.Generic;\n";
232 code += "using global::Google.FlatBuffers;\n\n";
233 }
234 code += classcode;
235 if (!namespace_name.empty()) { code += "\n}\n"; }
236 auto filename = NamespaceDir(ns) + defname;
237 if (options.one_file) { filename += options.filename_suffix; }
238 filename +=
239 options.filename_extension.empty() ? ".cs" : options.filename_extension;
240 return SaveFile(filename.c_str(), code, false);
241 }
242
CurrentNameSpace() const243 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
244
GenTypeBasic(const Type & type,bool enableLangOverrides) const245 std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
246 // clang-format off
247 static const char * const csharp_typename[] = {
248 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, ...) \
249 #NTYPE,
250 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
251 #undef FLATBUFFERS_TD
252 };
253 // clang-format on
254
255 if (enableLangOverrides) {
256 if (IsEnum(type)) return NamespacedName(*type.enum_def);
257 if (type.base_type == BASE_TYPE_STRUCT) {
258 return "Offset<" + NamespacedName(*type.struct_def) + ">";
259 }
260 }
261
262 return csharp_typename[type.base_type];
263 }
264
GenTypeBasic(const Type & type) const265 inline std::string GenTypeBasic(const Type &type) const {
266 return GenTypeBasic(type, true);
267 }
268
GenTypePointer(const Type & type) const269 std::string GenTypePointer(const Type &type) const {
270 switch (type.base_type) {
271 case BASE_TYPE_STRING: return "string";
272 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
273 case BASE_TYPE_STRUCT: return NamespacedName(*type.struct_def);
274 case BASE_TYPE_UNION: return "TTable";
275 default: return "Table";
276 }
277 }
278
GenTypeGet(const Type & type) const279 std::string GenTypeGet(const Type &type) const {
280 return IsScalar(type.base_type)
281 ? GenTypeBasic(type)
282 : (IsArray(type) ? GenTypeGet(type.VectorType())
283 : GenTypePointer(type));
284 }
285
GenOffsetType(const StructDef & struct_def) const286 std::string GenOffsetType(const StructDef &struct_def) const {
287 return "Offset<" + NamespacedName(struct_def) + ">";
288 }
289
GenOffsetConstruct(const StructDef & struct_def,const std::string & variable_name) const290 std::string GenOffsetConstruct(const StructDef &struct_def,
291 const std::string &variable_name) const {
292 return "new Offset<" + NamespacedName(struct_def) + ">(" + variable_name +
293 ")";
294 }
295
296 // Casts necessary to correctly read serialized data
DestinationCast(const Type & type) const297 std::string DestinationCast(const Type &type) const {
298 if (IsSeries(type)) {
299 return DestinationCast(type.VectorType());
300 } else {
301 if (IsEnum(type)) return "(" + NamespacedName(*type.enum_def) + ")";
302 }
303 return "";
304 }
305
306 // Cast statements for mutator method parameters.
307 // In Java, parameters representing unsigned numbers need to be cast down to
308 // their respective type. For example, a long holding an unsigned int value
309 // would be cast down to int before being put onto the buffer. In C#, one cast
310 // directly cast an Enum to its underlying type, which is essential before
311 // putting it onto the buffer.
SourceCast(const Type & type,const bool isOptional=false) const312 std::string SourceCast(const Type &type,
313 const bool isOptional = false) const {
314 if (IsSeries(type)) {
315 return SourceCast(type.VectorType());
316 } else {
317 if (IsEnum(type))
318 return "(" + GenTypeBasic(type, false) + (isOptional ? "?" : "") + ")";
319 }
320 return "";
321 }
322
SourceCastBasic(const Type & type,const bool isOptional) const323 std::string SourceCastBasic(const Type &type, const bool isOptional) const {
324 return IsScalar(type.base_type) ? SourceCast(type, isOptional) : "";
325 }
326
GenEnumDefaultValue(const FieldDef & field) const327 std::string GenEnumDefaultValue(const FieldDef &field) const {
328 auto &value = field.value;
329 FLATBUFFERS_ASSERT(value.type.enum_def);
330 auto &enum_def = *value.type.enum_def;
331 auto enum_val = enum_def.FindByValue(value.constant);
332 return enum_val ? (NamespacedName(enum_def) + "." + Name(*enum_val))
333 : value.constant;
334 }
335
GenDefaultValue(const FieldDef & field,bool enableLangOverrides) const336 std::string GenDefaultValue(const FieldDef &field,
337 bool enableLangOverrides) const {
338 // If it is an optional scalar field, the default is null
339 if (field.IsScalarOptional()) { return "null"; }
340
341 auto &value = field.value;
342 if (enableLangOverrides) {
343 // handles both enum case and vector of enum case
344 if (value.type.enum_def != nullptr &&
345 value.type.base_type != BASE_TYPE_UNION) {
346 return GenEnumDefaultValue(field);
347 }
348 }
349
350 auto longSuffix = "";
351 switch (value.type.base_type) {
352 case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
353 case BASE_TYPE_ULONG: return value.constant;
354 case BASE_TYPE_UINT:
355 case BASE_TYPE_LONG: return value.constant + longSuffix;
356 default:
357 if (IsFloat(value.type.base_type))
358 return CSharpFloatGen.GenFloatConstant(field);
359 else
360 return value.constant;
361 }
362 }
363
GenDefaultValue(const FieldDef & field) const364 std::string GenDefaultValue(const FieldDef &field) const {
365 return GenDefaultValue(field, true);
366 }
367
GenDefaultValueBasic(const FieldDef & field,bool enableLangOverrides) const368 std::string GenDefaultValueBasic(const FieldDef &field,
369 bool enableLangOverrides) const {
370 auto &value = field.value;
371 if (!IsScalar(value.type.base_type)) {
372 if (enableLangOverrides) {
373 switch (value.type.base_type) {
374 case BASE_TYPE_STRING: return "default(StringOffset)";
375 case BASE_TYPE_STRUCT:
376 return "default(Offset<" + NamespacedName(*value.type.struct_def) +
377 ">)";
378 case BASE_TYPE_VECTOR: return "default(VectorOffset)";
379 default: break;
380 }
381 }
382 return "0";
383 }
384 return GenDefaultValue(field, enableLangOverrides);
385 }
386
GenDefaultValueBasic(const FieldDef & field) const387 std::string GenDefaultValueBasic(const FieldDef &field) const {
388 return GenDefaultValueBasic(field, true);
389 }
390
GenEnum(EnumDef & enum_def,std::string * code_ptr,const IDLOptions & opts) const391 void GenEnum(EnumDef &enum_def, std::string *code_ptr,
392 const IDLOptions &opts) const {
393 std::string &code = *code_ptr;
394 if (enum_def.generated) return;
395
396 // Generate enum definitions of the form:
397 // public static (final) int name = value;
398 // In Java, we use ints rather than the Enum feature, because we want them
399 // to map directly to how they're used in C/C++ and file formats.
400 // That, and Java Enums are expensive, and not universally liked.
401 GenComment(enum_def.doc_comment, code_ptr, &comment_config);
402
403 if (opts.cs_gen_json_serializer && opts.generate_object_based_api) {
404 code +=
405 "[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters."
406 "StringEnumConverter))]\n";
407 }
408 // In C# this indicates enumeration values can be treated as bit flags.
409 if (enum_def.attributes.Lookup("bit_flags")) {
410 code += "[System.FlagsAttribute]\n";
411 }
412 if (enum_def.attributes.Lookup("private")) {
413 code += "internal ";
414 } else {
415 code += "public ";
416 }
417 code += "enum " + Name(enum_def);
418 code += " : " + GenTypeBasic(enum_def.underlying_type, false);
419 code += "\n{\n";
420 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
421 auto &ev = **it;
422 GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
423 code += " ";
424 code += Name(ev) + " = ";
425 code += enum_def.ToString(ev);
426 code += ",\n";
427 }
428 // Close the class
429 code += "};\n\n";
430
431 if (opts.generate_object_based_api) {
432 GenEnum_ObjectAPI(enum_def, code_ptr, opts);
433 }
434
435 if (enum_def.is_union) {
436 code += GenUnionVerify(enum_def.underlying_type);
437 }
438 }
439
HasUnionStringValue(const EnumDef & enum_def) const440 bool HasUnionStringValue(const EnumDef &enum_def) const {
441 if (!enum_def.is_union) return false;
442 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
443 auto &val = **it;
444 if (IsString(val.union_type)) { return true; }
445 }
446 return false;
447 }
448
449 // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type) const450 std::string GenGetter(const Type &type) const {
451 switch (type.base_type) {
452 case BASE_TYPE_STRING: return "__p.__string";
453 case BASE_TYPE_STRUCT: return "__p.__struct";
454 case BASE_TYPE_UNION: return "__p.__union";
455 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
456 case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
457 default: {
458 std::string getter = "__p.bb.Get";
459 if (type.base_type == BASE_TYPE_BOOL) {
460 getter = "0!=" + getter;
461 } else if (GenTypeBasic(type, false) != "byte") {
462 getter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
463 }
464 return getter;
465 }
466 }
467 }
468
GetObjectConstructor(flatbuffers::StructDef & struct_def,const std::string & data_buffer,const std::string & offset) const469 std::string GetObjectConstructor(flatbuffers::StructDef &struct_def,
470 const std::string &data_buffer,
471 const std::string &offset) const {
472 // Use the generated type directly, to properly handle default values that
473 // might not be written to the buffer.
474 return "new " + Name(struct_def) + "().__assign(" + offset + ", " +
475 data_buffer + ")";
476 }
477
478 // Returns the function name that is able to read a value of the given type.
GenGetterForLookupByKey(flatbuffers::StructDef & struct_def,flatbuffers::FieldDef * key_field,const std::string & data_buffer,const std::string & offset) const479 std::string GenGetterForLookupByKey(flatbuffers::StructDef &struct_def,
480 flatbuffers::FieldDef *key_field,
481 const std::string &data_buffer,
482 const std::string &offset) const {
483 // Use the generated type directly, to properly handle default values that
484 // might not be written to the buffer.
485 auto name = Name(*key_field);
486 if (name == struct_def.name) { name += "_"; }
487 return GetObjectConstructor(struct_def, data_buffer, offset) + "." + name;
488 }
489
490 // Direct mutation is only allowed for scalar fields.
491 // Hence a setter method will only be generated for such fields.
GenSetter(const Type & type) const492 std::string GenSetter(const Type &type) const {
493 if (IsScalar(type.base_type)) {
494 std::string setter = "__p.bb.Put";
495 if (GenTypeBasic(type, false) != "byte" &&
496 type.base_type != BASE_TYPE_BOOL) {
497 setter += ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel);
498 }
499 return setter;
500 } else {
501 return "";
502 }
503 }
504
505 // Returns the method name for use with add/put calls.
GenMethod(const Type & type) const506 std::string GenMethod(const Type &type) const {
507 return IsScalar(type.base_type)
508 ? ConvertCase(GenTypeBasic(type, false), Case::kUpperCamel)
509 : (IsStruct(type) ? "Struct" : "Offset");
510 }
511
512 // Recursively generate arguments for a constructor, to deal with nested
513 // structs.
GenStructArgs(const StructDef & struct_def,std::string * code_ptr,const char * nameprefix,size_t array_count=0) const514 void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
515 const char *nameprefix, size_t array_count = 0) const {
516 std::string &code = *code_ptr;
517 for (auto it = struct_def.fields.vec.begin();
518 it != struct_def.fields.vec.end(); ++it) {
519 auto &field = **it;
520 const auto &field_type = field.value.type;
521 const auto array_field = IsArray(field_type);
522 const auto &type = array_field ? field_type.VectorType() : field_type;
523 const auto array_cnt = array_field ? (array_count + 1) : array_count;
524 if (IsStruct(type)) {
525 // Generate arguments for a struct inside a struct. To ensure names
526 // don't clash, and to make it obvious these arguments are constructing
527 // a nested struct, prefix the name with the field name.
528 GenStructArgs(*field_type.struct_def, code_ptr,
529 (nameprefix + (EscapeKeyword(field.name) + "_")).c_str(),
530 array_cnt);
531 } else {
532 code += ", ";
533 code += GenTypeBasic(type);
534 if (field.IsScalarOptional()) { code += "?"; }
535 if (array_cnt > 0) {
536 code += "[";
537 for (size_t i = 1; i < array_cnt; i++) code += ",";
538 code += "]";
539 }
540 code += " ";
541 code += nameprefix;
542 code += Name(field);
543 }
544 }
545 }
546
547 // Recusively generate struct construction statements of the form:
548 // builder.putType(name);
549 // and insert manual padding.
GenStructBody(const StructDef & struct_def,std::string * code_ptr,const char * nameprefix,size_t index=0,bool in_array=false) const550 void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
551 const char *nameprefix, size_t index = 0,
552 bool in_array = false) const {
553 std::string &code = *code_ptr;
554 std::string indent((index + 1) * 2, ' ');
555 code += indent + " builder.Prep(";
556 code += NumToString(struct_def.minalign) + ", ";
557 code += NumToString(struct_def.bytesize) + ");\n";
558 for (auto it = struct_def.fields.vec.rbegin();
559 it != struct_def.fields.vec.rend(); ++it) {
560 auto &field = **it;
561 const auto &field_type = field.value.type;
562 if (field.padding) {
563 code += indent + " builder.Pad(";
564 code += NumToString(field.padding) + ");\n";
565 }
566 if (IsStruct(field_type)) {
567 GenStructBody(*field_type.struct_def, code_ptr,
568 (nameprefix + (field.name + "_")).c_str(), index,
569 in_array);
570 } else {
571 const auto &type =
572 IsArray(field_type) ? field_type.VectorType() : field_type;
573 const auto index_var = "_idx" + NumToString(index);
574 if (IsArray(field_type)) {
575 code += indent + " for (int " + index_var + " = ";
576 code += NumToString(field_type.fixed_length);
577 code += "; " + index_var + " > 0; " + index_var + "--) {\n";
578 in_array = true;
579 }
580 if (IsStruct(type)) {
581 GenStructBody(*field_type.struct_def, code_ptr,
582 (nameprefix + (field.name + "_")).c_str(), index + 1,
583 in_array);
584 } else {
585 code += IsArray(field_type) ? " " : "";
586 code += indent + " builder.Put";
587 code += GenMethod(type) + "(";
588 code += SourceCast(type);
589 auto argname = nameprefix + Name(field);
590 code += argname;
591 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
592 if (array_cnt > 0) {
593 code += "[";
594 for (size_t i = 0; in_array && i < array_cnt; i++) {
595 code += "_idx" + NumToString(i) + "-1";
596 if (i != (array_cnt - 1)) code += ",";
597 }
598 code += "]";
599 }
600 code += ");\n";
601 }
602 if (IsArray(field_type)) { code += indent + " }\n"; }
603 }
604 }
605 }
GenOffsetGetter(flatbuffers::FieldDef * key_field,const char * num=nullptr) const606 std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
607 const char *num = nullptr) const {
608 std::string key_offset =
609 "Table.__offset(" + NumToString(key_field->value.offset) + ", ";
610 if (num) {
611 key_offset += num;
612 key_offset += ".Value, builder.DataBuffer)";
613 } else {
614 key_offset += "bb.Length";
615 key_offset += " - tableOffset, bb)";
616 }
617 return key_offset;
618 }
619
GenKeyGetter(flatbuffers::StructDef & struct_def,flatbuffers::FieldDef * key_field) const620 std::string GenKeyGetter(flatbuffers::StructDef &struct_def,
621 flatbuffers::FieldDef *key_field) const {
622 // Get the getter for the key of the struct.
623 return GenGetterForLookupByKey(struct_def, key_field, "builder.DataBuffer",
624 "builder.DataBuffer.Length - o1.Value") +
625 ".CompareTo(" +
626 GenGetterForLookupByKey(struct_def, key_field, "builder.DataBuffer",
627 "builder.DataBuffer.Length - o2.Value") +
628 ")";
629 }
630
631 // Get the value of a table verification function start
GetStartOfTableVerifier(const StructDef & struct_def,std::string * code_ptr)632 void GetStartOfTableVerifier(const StructDef &struct_def,
633 std::string *code_ptr) {
634 std::string &code = *code_ptr;
635 code += "\n";
636 code += "static public class " + struct_def.name + "Verify\n";
637 code += "{\n";
638 code += " static public bool Verify";
639 code += "(Google.FlatBuffers.Verifier verifier, uint tablePos)\n";
640 code += " {\n";
641 code += " return verifier.VerifyTableStart(tablePos)\n";
642 }
643
644 // Get the value of a table verification function end
GetEndOfTableVerifier(std::string * code_ptr)645 void GetEndOfTableVerifier(std::string *code_ptr) {
646 std::string &code = *code_ptr;
647 code += " && verifier.VerifyTableEnd(tablePos);\n";
648 code += " }\n";
649 code += "}\n";
650 }
651
GetNestedFlatBufferName(const FieldDef & field)652 std::string GetNestedFlatBufferName(const FieldDef &field) {
653 std::string name;
654 if (field.nested_flatbuffer) {
655 name = NamespacedName(*field.nested_flatbuffer);
656 } else {
657 name = "";
658 }
659 return name;
660 }
661
662 // Generate the code to call the appropriate Verify function(s) for a field.
GenVerifyCall(CodeWriter & code_,const FieldDef & field,const char * prefix)663 void GenVerifyCall(CodeWriter &code_, const FieldDef &field,
664 const char *prefix) {
665 code_.SetValue("PRE", prefix);
666 code_.SetValue("NAME", ConvertCase(field.name, Case::kUpperCamel));
667 code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
668 code_.SetValue("REQUIRED_FLAG", field.IsRequired() ? "true" : "false");
669 code_.SetValue("TYPE", GenTypeGet(field.value.type));
670 code_.SetValue("INLINESIZE", NumToString(InlineSize(field.value.type)));
671 code_.SetValue("OFFSET", NumToString(field.value.offset));
672
673 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
674 code_.SetValue("ALIGN", NumToString(InlineAlignment(field.value.type)));
675 code_ +=
676 "{{PRE}} && verifier.VerifyField(tablePos, "
677 "{{OFFSET}} /*{{NAME}}*/, {{INLINESIZE}} /*{{TYPE}}*/, {{ALIGN}}, "
678 "{{REQUIRED_FLAG}})";
679 } else {
680 // TODO - probably code below should go to this 'else' - code_ +=
681 // "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
682 }
683
684 switch (field.value.type.base_type) {
685 case BASE_TYPE_UNION: {
686 auto union_name = NamespacedName(*field.value.type.enum_def);
687 code_.SetValue("ENUM_NAME1", field.value.type.enum_def->name);
688 code_.SetValue("ENUM_NAME", union_name);
689 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
690 // Caution: This construction assumes, that UNION type id element has
691 // been created just before union data and its offset precedes union.
692 // Such assumption is common in flatbuffer implementation
693 code_.SetValue("TYPE_ID_OFFSET",
694 NumToString(field.value.offset - sizeof(voffset_t)));
695 code_ +=
696 "{{PRE}} && verifier.VerifyUnion(tablePos, "
697 "{{TYPE_ID_OFFSET}}, "
698 "{{OFFSET}} /*{{NAME}}*/, {{ENUM_NAME}}Verify.Verify, "
699 "{{REQUIRED_FLAG}})";
700 break;
701 }
702 case BASE_TYPE_STRUCT: {
703 if (!field.value.type.struct_def->fixed) {
704 code_ +=
705 "{{PRE}} && verifier.VerifyTable(tablePos, "
706 "{{OFFSET}} /*{{NAME}}*/, {{TYPE}}Verify.Verify, "
707 "{{REQUIRED_FLAG}})";
708 }
709 break;
710 }
711 case BASE_TYPE_STRING: {
712 code_ +=
713 "{{PRE}} && verifier.VerifyString(tablePos, "
714 "{{OFFSET}} /*{{NAME}}*/, {{REQUIRED_FLAG}})";
715 break;
716 }
717 case BASE_TYPE_VECTOR: {
718 switch (field.value.type.element) {
719 case BASE_TYPE_STRING: {
720 code_ +=
721 "{{PRE}} && verifier.VerifyVectorOfStrings(tablePos, "
722 "{{OFFSET}} /*{{NAME}}*/, {{REQUIRED_FLAG}})";
723 break;
724 }
725 case BASE_TYPE_STRUCT: {
726 if (!field.value.type.struct_def->fixed) {
727 code_ +=
728 "{{PRE}} && verifier.VerifyVectorOfTables(tablePos, "
729 "{{OFFSET}} /*{{NAME}}*/, {{TYPE}}Verify.Verify, "
730 "{{REQUIRED_FLAG}})";
731 } else {
732 code_.SetValue(
733 "VECTOR_ELEM_INLINESIZE",
734 NumToString(InlineSize(field.value.type.VectorType())));
735 code_ +=
736 "{{PRE}} && "
737 "verifier.VerifyVectorOfData(tablePos, "
738 "{{OFFSET}} /*{{NAME}}*/, {{VECTOR_ELEM_INLINESIZE}} "
739 "/*{{TYPE}}*/, {{REQUIRED_FLAG}})";
740 }
741 break;
742 }
743 case BASE_TYPE_UNION: {
744 // Vectors of unions are not yet supported for go
745 break;
746 }
747 default:
748 // Generate verifier for vector of data.
749 // It may be either nested flatbuffer of just vector of bytes
750 auto nfn = GetNestedFlatBufferName(field);
751 if (!nfn.empty()) {
752 code_.SetValue("CPP_NAME", nfn);
753 // FIXME: file_identifier.
754 code_ +=
755 "{{PRE}} && verifier.VerifyNestedBuffer(tablePos, "
756 "{{OFFSET}} /*{{NAME}}*/, {{CPP_NAME}}Verify.Verify, "
757 "{{REQUIRED_FLAG}})";
758 } else if (field.flexbuffer) {
759 code_ +=
760 "{{PRE}} && verifier.VerifyNestedBuffer(tablePos, "
761 "{{OFFSET}} /*{{NAME}}*/, null, {{REQUIRED_FLAG}})";
762 } else {
763 code_.SetValue(
764 "VECTOR_ELEM_INLINESIZE",
765 NumToString(InlineSize(field.value.type.VectorType())));
766 code_ +=
767 "{{PRE}} && verifier.VerifyVectorOfData(tablePos, "
768 "{{OFFSET}} /*{{NAME}}*/, {{VECTOR_ELEM_INLINESIZE}} "
769 "/*{{TYPE}}*/, {{REQUIRED_FLAG}})";
770 }
771 break;
772 }
773
774 break;
775 }
776 default: {
777 break;
778 }
779 }
780 }
781
782 // Generate table constructors, conditioned on its members' types.
GenTableVerifier(const StructDef & struct_def,std::string * code_ptr)783 void GenTableVerifier(const StructDef &struct_def, std::string *code_ptr) {
784 CodeWriter code_;
785
786 GetStartOfTableVerifier(struct_def, code_ptr);
787
788 // Generate struct fields accessors
789 for (auto it = struct_def.fields.vec.begin();
790 it != struct_def.fields.vec.end(); ++it) {
791 auto &field = **it;
792 if (field.deprecated) continue;
793
794 GenVerifyCall(code_, field, "");
795 }
796
797 *code_ptr += code_.ToString();
798
799 GetEndOfTableVerifier(code_ptr);
800 }
801
802 // Generate struct or table methods.
GenStructVerifier(const StructDef & struct_def,std::string * code_ptr)803 void GenStructVerifier(const StructDef &struct_def, std::string *code_ptr) {
804 if (struct_def.generated) return;
805
806 // cur_name_space_ = struct_def.defined_namespace;
807
808 // Generate verifiers
809 if (struct_def.fixed) {
810 // Fixed size structures do not require table members
811 // verification - instead structure size is verified using VerifyField
812 } else {
813 // Create table verification function
814 GenTableVerifier(struct_def, code_ptr);
815 }
816 }
817
GenStruct(StructDef & struct_def,std::string * code_ptr,const IDLOptions & opts) const818 void GenStruct(StructDef &struct_def, std::string *code_ptr,
819 const IDLOptions &opts) const {
820 if (struct_def.generated) return;
821 std::string &code = *code_ptr;
822
823 // Generate a struct accessor class, with methods of the form:
824 // public type name() { return bb.getType(i + offset); }
825 // or for tables of the form:
826 // public type name() {
827 // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
828 // }
829 GenComment(struct_def.doc_comment, code_ptr, &comment_config);
830 if (struct_def.attributes.Lookup("private")) {
831 code += "internal ";
832 } else {
833 code += "public ";
834 }
835 if (struct_def.attributes.Lookup("csharp_partial")) {
836 // generate a partial class for this C# struct/table
837 code += "partial ";
838 }
839 code += "struct " + struct_def.name;
840 code += " : IFlatbufferObject";
841 code += "\n{\n";
842 code += " private ";
843 code += struct_def.fixed ? "Struct" : "Table";
844 code += " __p;\n";
845
846 code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
847
848 if (!struct_def.fixed) {
849 // Generate version check method.
850 // Force compile time error if not using the same version runtime.
851 code += " public static void ValidateVersion() {";
852 code += " FlatBufferConstants.";
853 code += "FLATBUFFERS_25_1_24(); ";
854 code += "}\n";
855
856 // Generate a special accessor for the table that when used as the root
857 // of a FlatBuffer
858 std::string method_name = "GetRootAs" + struct_def.name;
859 std::string method_signature =
860 " public static " + struct_def.name + " " + method_name;
861
862 // create convenience method that doesn't require an existing object
863 code += method_signature + "(ByteBuffer _bb) ";
864 code += "{ return " + method_name + "(_bb, new " + struct_def.name +
865 "()); }\n";
866
867 // create method that allows object reuse
868 code +=
869 method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
870 code += "return (obj.__assign(_bb.GetInt(_bb.Position";
871 code += ") + _bb.Position";
872 code += ", _bb)); }\n";
873 if (parser_.root_struct_def_ == &struct_def) {
874 if (parser_.file_identifier_.length()) {
875 // Check if a buffer has the identifier.
876 code += " public static ";
877 code += "bool " + struct_def.name;
878 code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
879 code += "Table.__has_identifier(_bb, \"";
880 code += parser_.file_identifier_;
881 code += "\"); }\n";
882 }
883
884 // Generate the Verify method that checks if a ByteBuffer is save to
885 // access
886 code += " public static ";
887 code += "bool Verify" + struct_def.name + "(ByteBuffer _bb) {";
888 code += "Google.FlatBuffers.Verifier verifier = new ";
889 code += "Google.FlatBuffers.Verifier(_bb); ";
890 code += "return verifier.VerifyBuffer(\"";
891 code += parser_.file_identifier_;
892 code += "\", false, " + struct_def.name + "Verify.Verify);";
893 code += " }\n";
894 }
895 }
896
897 // Generate the __init method that sets the field in a pre-existing
898 // accessor object. This is to allow object reuse.
899 code += " public void __init(int _i, ByteBuffer _bb) ";
900 code += "{ ";
901 code += "__p = new ";
902 code += struct_def.fixed ? "Struct" : "Table";
903 code += "(_i, _bb); ";
904 code += "}\n";
905 code +=
906 " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
907 code += "{ __init(_i, _bb); return this; }\n\n";
908 for (auto it = struct_def.fields.vec.begin();
909 it != struct_def.fields.vec.end(); ++it) {
910 auto &field = **it;
911 if (field.deprecated) continue;
912 GenComment(field.doc_comment, code_ptr, &comment_config, " ");
913 std::string type_name = GenTypeGet(field.value.type);
914 std::string type_name_dest = GenTypeGet(field.value.type);
915 std::string conditional_cast = "";
916 std::string optional = "";
917 if (!struct_def.fixed &&
918 (field.value.type.base_type == BASE_TYPE_STRUCT ||
919 field.value.type.base_type == BASE_TYPE_UNION ||
920 (IsVector(field.value.type) &&
921 (field.value.type.element == BASE_TYPE_STRUCT ||
922 field.value.type.element == BASE_TYPE_UNION)))) {
923 optional = "?";
924 conditional_cast = "(" + type_name_dest + optional + ")";
925 }
926 if (field.IsScalarOptional()) { optional = "?"; }
927 std::string dest_mask = "";
928 std::string dest_cast = DestinationCast(field.value.type);
929 std::string src_cast = SourceCast(field.value.type);
930 std::string field_name_camel = Name(field);
931 if (field_name_camel == struct_def.name) { field_name_camel += "_"; }
932 std::string method_start =
933 " public " + type_name_dest + optional + " " + field_name_camel;
934 std::string obj = "(new " + type_name + "())";
935
936 // Most field accessors need to retrieve and test the field offset first,
937 // this is the prefix code for that:
938 auto offset_prefix =
939 IsArray(field.value.type)
940 ? " { return "
941 : (" { int o = __p.__offset(" + NumToString(field.value.offset) +
942 "); return o != 0 ? ");
943 // Generate the accessors that don't do object reuse.
944 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
945 } else if (IsVector(field.value.type) &&
946 field.value.type.element == BASE_TYPE_STRUCT) {
947 } else if (field.value.type.base_type == BASE_TYPE_UNION ||
948 (IsVector(field.value.type) &&
949 field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
950 method_start += "<TTable>";
951 type_name = type_name_dest;
952 }
953 std::string getter = dest_cast + GenGetter(field.value.type);
954 code += method_start;
955 std::string default_cast = "";
956 // only create default casts for c# scalars or vectors of scalars
957 if ((IsScalar(field.value.type.base_type) ||
958 (IsVector(field.value.type) &&
959 IsScalar(field.value.type.element)))) {
960 // For scalars, default value will be returned by GetDefaultValue().
961 // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
962 // that doesn't need to be casted. However, default values for enum
963 // elements of vectors are integer literals ("0") and are still casted
964 // for clarity.
965 // If the scalar is optional and enum, we still need the cast.
966 if ((field.value.type.enum_def == nullptr ||
967 IsVector(field.value.type)) ||
968 (IsEnum(field.value.type) && field.IsScalarOptional())) {
969 default_cast = "(" + type_name_dest + optional + ")";
970 }
971 }
972 std::string member_suffix = "; ";
973 if (IsScalar(field.value.type.base_type)) {
974 code += " { get";
975 member_suffix += "} ";
976 if (struct_def.fixed) {
977 code += " { return " + getter;
978 code += "(__p.bb_pos + ";
979 code += NumToString(field.value.offset) + ")";
980 code += dest_mask;
981 } else {
982 code += offset_prefix + getter;
983 code += "(o + __p.bb_pos)" + dest_mask;
984 code += " : " + default_cast;
985 code += GenDefaultValue(field);
986 }
987 } else {
988 switch (field.value.type.base_type) {
989 case BASE_TYPE_STRUCT:
990 code += " { get";
991 member_suffix += "} ";
992 if (struct_def.fixed) {
993 code += " { return " + obj + ".__assign(" + "__p.";
994 code += "bb_pos + " + NumToString(field.value.offset) + ", ";
995 code += "__p.bb)";
996 } else {
997 code += offset_prefix + conditional_cast;
998 code += obj + ".__assign(";
999 code += field.value.type.struct_def->fixed
1000 ? "o + __p.bb_pos"
1001 : "__p.__indirect(o + __p.bb_pos)";
1002 code += ", __p.bb) : null";
1003 }
1004 break;
1005 case BASE_TYPE_STRING:
1006 code += " { get";
1007 member_suffix += "} ";
1008 code += offset_prefix + getter + "(o + " + "__p.";
1009 code += "bb_pos) : null";
1010 break;
1011 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
1012 case BASE_TYPE_VECTOR: {
1013 auto vectortype = field.value.type.VectorType();
1014 if (vectortype.base_type == BASE_TYPE_UNION) {
1015 conditional_cast = "(TTable?)";
1016 getter += "<TTable>";
1017 }
1018 code += "(";
1019 if (vectortype.base_type == BASE_TYPE_STRUCT) {
1020 getter = obj + ".__assign";
1021 } else if (vectortype.base_type == BASE_TYPE_UNION) {
1022 }
1023 code += "int j)";
1024 const auto body = offset_prefix + conditional_cast + getter + "(";
1025 if (vectortype.base_type == BASE_TYPE_UNION) {
1026 code += " where TTable : struct, IFlatbufferObject" + body;
1027 } else {
1028 code += body;
1029 }
1030 std::string index = "__p.";
1031 if (IsArray(field.value.type)) {
1032 index += "bb_pos + " + NumToString(field.value.offset) + " + ";
1033 } else {
1034 index += "__vector(o) + ";
1035 }
1036 index += "j * " + NumToString(InlineSize(vectortype));
1037 if (vectortype.base_type == BASE_TYPE_STRUCT) {
1038 code += vectortype.struct_def->fixed
1039 ? index
1040 : "__p.__indirect(" + index + ")";
1041 code += ", __p.bb";
1042 } else {
1043 code += index;
1044 }
1045 code += ")" + dest_mask;
1046 if (!IsArray(field.value.type)) {
1047 code += " : ";
1048 code +=
1049 field.value.type.element == BASE_TYPE_BOOL
1050 ? "false"
1051 : (IsScalar(field.value.type.element) ? default_cast + "0"
1052 : "null");
1053 }
1054 if (vectortype.base_type == BASE_TYPE_UNION &&
1055 HasUnionStringValue(*vectortype.enum_def)) {
1056 code += member_suffix;
1057 code += "}\n";
1058 code += " public string " + Name(field) + "AsString(int j)";
1059 code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
1060 code += "(" + index + ") : null";
1061 }
1062 break;
1063 }
1064 case BASE_TYPE_UNION:
1065 code += "() where TTable : struct, IFlatbufferObject";
1066 code += offset_prefix + "(TTable?)" + getter;
1067 code += "<TTable>(o + __p.bb_pos) : null";
1068 if (HasUnionStringValue(*field.value.type.enum_def)) {
1069 code += member_suffix;
1070 code += "}\n";
1071 code += " public string " + Name(field) + "AsString()";
1072 code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
1073 code += "(o + __p.bb_pos) : null";
1074 }
1075 // As<> accesors for Unions
1076 // Loop through all the possible union types and generate an As
1077 // accessor that casts to the correct type.
1078 for (auto uit = field.value.type.enum_def->Vals().begin();
1079 uit != field.value.type.enum_def->Vals().end(); ++uit) {
1080 auto val = *uit;
1081 if (val->union_type.base_type == BASE_TYPE_NONE) { continue; }
1082 auto union_field_type_name = GenTypeGet(val->union_type);
1083 code += member_suffix + "}\n";
1084 if (val->union_type.base_type == BASE_TYPE_STRUCT &&
1085 val->union_type.struct_def->attributes.Lookup("private")) {
1086 code += " internal ";
1087 } else {
1088 code += " public ";
1089 }
1090 code += union_field_type_name + " ";
1091 code += field_name_camel + "As" + val->name + "() { return ";
1092 code += field_name_camel;
1093 if (IsString(val->union_type)) {
1094 code += "AsString()";
1095 } else {
1096 code += "<" + union_field_type_name + ">().Value";
1097 }
1098 }
1099 break;
1100 default: FLATBUFFERS_ASSERT(0);
1101 }
1102 }
1103 code += member_suffix;
1104 code += "}\n";
1105 if (IsVector(field.value.type)) {
1106 auto camel_name = Name(field);
1107 if (camel_name == struct_def.name) { camel_name += "_"; }
1108 code += " public int " + camel_name;
1109 code += "Length";
1110 code += " { get";
1111 code += offset_prefix;
1112 code += "__p.__vector_len(o) : 0; ";
1113 code += "} ";
1114 code += "}\n";
1115 // See if we should generate a by-key accessor.
1116 if (field.value.type.element == BASE_TYPE_STRUCT &&
1117 !field.value.type.struct_def->fixed) {
1118 auto &sd = *field.value.type.struct_def;
1119 auto &fields = sd.fields.vec;
1120 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1121 auto &key_field = **kit;
1122 if (key_field.key) {
1123 auto qualified_name = NamespacedName(sd);
1124 code += " public " + qualified_name + "? ";
1125 code += Name(field) + "ByKey(";
1126 code += GenTypeGet(key_field.value.type) + " key)";
1127 code += offset_prefix;
1128 code += qualified_name + ".__lookup_by_key(";
1129 code += "__p.__vector(o), key, ";
1130 code += "__p.bb) : null; ";
1131 code += "}\n";
1132 break;
1133 }
1134 }
1135 }
1136 }
1137 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1138 if ((IsVector(field.value.type) &&
1139 IsScalar(field.value.type.VectorType().base_type)) ||
1140 IsString(field.value.type)) {
1141 code += "#if ENABLE_SPAN_T\n";
1142 code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
1143 "> Get";
1144 code += Name(field);
1145 code += "Bytes() { return ";
1146 code += "__p.__vector_as_span<" +
1147 GenTypeBasic(field.value.type.VectorType()) + ">(";
1148 code += NumToString(field.value.offset);
1149 code +=
1150 ", " + NumToString(SizeOf(field.value.type.VectorType().base_type));
1151 code += "); }\n";
1152 code += "#else\n";
1153 code += " public ArraySegment<byte>? Get";
1154 code += Name(field);
1155 code += "Bytes() { return ";
1156 code += "__p.__vector_as_arraysegment(";
1157 code += NumToString(field.value.offset);
1158 code += "); }\n";
1159 code += "#endif\n";
1160
1161 // For direct blockcopying the data into a typed array
1162 code += " public ";
1163 code += GenTypeBasic(field.value.type.VectorType());
1164 code += "[] Get";
1165 code += Name(field);
1166 code += "Array() { ";
1167 if (IsEnum(field.value.type.VectorType())) {
1168 // Since __vector_as_array does not work for enum types,
1169 // fill array using an explicit loop.
1170 code += "int o = __p.__offset(";
1171 code += NumToString(field.value.offset);
1172 code += "); if (o == 0) return null; int p = ";
1173 code += "__p.__vector(o); int l = ";
1174 code += "__p.__vector_len(o); ";
1175 code += GenTypeBasic(field.value.type.VectorType());
1176 code += "[] a = new ";
1177 code += GenTypeBasic(field.value.type.VectorType());
1178 code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter;
1179 code += "(p + i * ";
1180 code += NumToString(InlineSize(field.value.type.VectorType()));
1181 code += "); } return a;";
1182 } else {
1183 code += "return ";
1184 code += "__p.__vector_as_array<";
1185 code += GenTypeBasic(field.value.type.VectorType());
1186 code += ">(";
1187 code += NumToString(field.value.offset);
1188 code += ");";
1189 }
1190 code += " }\n";
1191 }
1192 // generate object accessors if is nested_flatbuffer
1193 if (field.nested_flatbuffer) {
1194 auto nested_type_name = NamespacedName(*field.nested_flatbuffer);
1195 auto nested_method_name =
1196 Name(field) + "As" + field.nested_flatbuffer->name;
1197 auto get_nested_method_name = nested_method_name;
1198 get_nested_method_name = "Get" + nested_method_name;
1199 conditional_cast = "(" + nested_type_name + "?)";
1200 obj = "(new " + nested_type_name + "())";
1201 code += " public " + nested_type_name + "? ";
1202 code += get_nested_method_name + "(";
1203 code += ") { int o = __p.__offset(";
1204 code += NumToString(field.value.offset) + "); ";
1205 code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
1206 code += "__p.";
1207 code += "__indirect(__p.__vector(o)), ";
1208 code += "__p.bb) : null; }\n";
1209 }
1210 // Generate mutators for scalar fields or vectors of scalars.
1211 if (parser_.opts.mutable_buffer) {
1212 auto is_series = (IsSeries(field.value.type));
1213 const auto &underlying_type =
1214 is_series ? field.value.type.VectorType() : field.value.type;
1215 // Boolean parameters have to be explicitly converted to byte
1216 // representation.
1217 auto setter_parameter =
1218 underlying_type.base_type == BASE_TYPE_BOOL
1219 ? "(byte)(" + EscapeKeyword(field.name) + " ? 1 : 0)"
1220 : EscapeKeyword(field.name);
1221 auto mutator_prefix = "Mutate";
1222 // A vector mutator also needs the index of the vector element it should
1223 // mutate.
1224 auto mutator_params = (is_series ? "(int j, " : "(") +
1225 GenTypeGet(underlying_type) + " " +
1226 EscapeKeyword(field.name) + ") { ";
1227 auto setter_index =
1228 is_series
1229 ? "__p." +
1230 (IsArray(field.value.type)
1231 ? "bb_pos + " + NumToString(field.value.offset)
1232 : "__vector(o)") +
1233 +" + j * " + NumToString(InlineSize(underlying_type))
1234 : (struct_def.fixed
1235 ? "__p.bb_pos + " + NumToString(field.value.offset)
1236 : "o + __p.bb_pos");
1237 if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
1238 code += " public ";
1239 code += struct_def.fixed ? "void " : "bool ";
1240 code += mutator_prefix + Name(field);
1241 code += mutator_params;
1242 if (struct_def.fixed) {
1243 code += GenSetter(underlying_type) + "(" + setter_index + ", ";
1244 code += src_cast + setter_parameter + "); }\n";
1245 } else {
1246 code += "int o = __p.__offset(";
1247 code += NumToString(field.value.offset) + ");";
1248 code += " if (o != 0) { " + GenSetter(underlying_type);
1249 code += "(" + setter_index + ", " + src_cast + setter_parameter +
1250 "); return true; } else { return false; } }\n";
1251 }
1252 }
1253 }
1254 if (parser_.opts.java_primitive_has_method &&
1255 IsScalar(field.value.type.base_type) && !struct_def.fixed) {
1256 auto vt_offset_constant =
1257 " public static final int VT_" +
1258 ConvertCase(field.name, Case::kScreamingSnake) + " = " +
1259 NumToString(field.value.offset) + ";";
1260
1261 code += vt_offset_constant;
1262 code += "\n";
1263 }
1264 }
1265 code += "\n";
1266 auto struct_has_create = false;
1267 std::set<flatbuffers::FieldDef *> field_has_create_set;
1268 flatbuffers::FieldDef *key_field = nullptr;
1269 if (struct_def.fixed) {
1270 struct_has_create = true;
1271 // create a struct constructor function
1272 code += " public static " + GenOffsetType(struct_def) + " ";
1273 code += "Create";
1274 code += struct_def.name + "(FlatBufferBuilder builder";
1275 GenStructArgs(struct_def, code_ptr, "");
1276 code += ") {\n";
1277 GenStructBody(struct_def, code_ptr, "");
1278 code += " return ";
1279 code += GenOffsetConstruct(struct_def, "builder.Offset");
1280 code += ";\n }\n";
1281 } else {
1282 // Generate a method that creates a table in one go. This is only possible
1283 // when the table has no struct fields, since those have to be created
1284 // inline, and there's no way to do so in Java.
1285 bool has_no_struct_fields = true;
1286 int num_fields = 0;
1287 for (auto it = struct_def.fields.vec.begin();
1288 it != struct_def.fields.vec.end(); ++it) {
1289 auto &field = **it;
1290 if (field.deprecated) continue;
1291 if (IsStruct(field.value.type)) {
1292 has_no_struct_fields = false;
1293 } else {
1294 num_fields++;
1295 }
1296 }
1297 // JVM specifications restrict default constructor params to be < 255.
1298 // Longs and doubles take up 2 units, so we set the limit to be < 127.
1299 if ((has_no_struct_fields || opts.generate_object_based_api) &&
1300 num_fields && num_fields < 127) {
1301 struct_has_create = true;
1302 // Generate a table constructor of the form:
1303 // public static int createName(FlatBufferBuilder builder, args...)
1304 code += " public static " + GenOffsetType(struct_def) + " ";
1305 code += "Create" + struct_def.name;
1306 code += "(FlatBufferBuilder builder";
1307 for (auto it = struct_def.fields.vec.begin();
1308 it != struct_def.fields.vec.end(); ++it) {
1309 auto &field = **it;
1310 if (field.deprecated) continue;
1311 code += ",\n ";
1312 if (IsStruct(field.value.type) && opts.generate_object_based_api) {
1313 code += WrapInNameSpace(
1314 field.value.type.struct_def->defined_namespace,
1315 GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts));
1316 code += " ";
1317 code += EscapeKeyword(field.name);
1318 code += " = null";
1319 } else {
1320 code += GenTypeBasic(field.value.type);
1321 if (field.IsScalarOptional()) { code += "?"; }
1322 code += " ";
1323 code += EscapeKeyword(field.name);
1324 if (!IsScalar(field.value.type.base_type)) code += "Offset";
1325
1326 code += " = ";
1327 code += GenDefaultValueBasic(field);
1328 }
1329 }
1330 code += ") {\n builder.";
1331 code += "StartTable(";
1332 code += NumToString(struct_def.fields.vec.size()) + ");\n";
1333 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1334 size; size /= 2) {
1335 for (auto it = struct_def.fields.vec.rbegin();
1336 it != struct_def.fields.vec.rend(); ++it) {
1337 auto &field = **it;
1338 if (!field.deprecated &&
1339 (!struct_def.sortbysize ||
1340 size == SizeOf(field.value.type.base_type))) {
1341 code += " " + struct_def.name + ".";
1342 code += "Add";
1343 code += Name(field) + "(builder, ";
1344 if (IsStruct(field.value.type) &&
1345 opts.generate_object_based_api) {
1346 code += GenTypePointer(field.value.type) + ".Pack(builder, " +
1347 EscapeKeyword(field.name) + ")";
1348 } else {
1349 code += EscapeKeyword(field.name);
1350 if (!IsScalar(field.value.type.base_type)) code += "Offset";
1351 }
1352
1353 code += ");\n";
1354 }
1355 }
1356 }
1357 code += " return " + struct_def.name + ".";
1358 code += "End" + struct_def.name;
1359 code += "(builder);\n }\n\n";
1360 }
1361 // Generate a set of static methods that allow table construction,
1362 // of the form:
1363 // public static void addName(FlatBufferBuilder builder, short name)
1364 // { builder.addShort(id, name, default); }
1365 // Unlike the Create function, these always work.
1366 code += " public static void Start";
1367 code += struct_def.name;
1368 code += "(FlatBufferBuilder builder) { builder.";
1369 code += "StartTable(";
1370 code += NumToString(struct_def.fields.vec.size()) + "); }\n";
1371 for (auto it = struct_def.fields.vec.begin();
1372 it != struct_def.fields.vec.end(); ++it) {
1373 auto &field = **it;
1374 if (field.deprecated) continue;
1375 if (field.key) key_field = &field;
1376 code += " public static void Add";
1377 code += Name(field);
1378 code += "(FlatBufferBuilder builder, ";
1379 code += GenTypeBasic(field.value.type);
1380 auto argname = ConvertCase(field.name, Case::kLowerCamel);
1381 if (!IsScalar(field.value.type.base_type)) argname += "Offset";
1382 if (field.IsScalarOptional()) { code += "?"; }
1383 code += " " + EscapeKeyword(argname) + ") { builder.Add";
1384 code += GenMethod(field.value.type) + "(";
1385 code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
1386 code += SourceCastBasic(field.value.type, field.IsScalarOptional());
1387 code += EscapeKeyword(argname);
1388 if (!IsScalar(field.value.type.base_type) &&
1389 field.value.type.base_type != BASE_TYPE_UNION) {
1390 code += ".Value";
1391 }
1392 if (!field.IsScalarOptional()) {
1393 // When the scalar is optional, use the builder method that doesn't
1394 // supply a default value. Otherwise, we to continue to use the
1395 // default value method.
1396 code += ", ";
1397 code += GenDefaultValue(field, false);
1398 }
1399 code += "); }\n";
1400 if (IsVector(field.value.type)) {
1401 auto vector_type = field.value.type.VectorType();
1402 auto alignment = InlineAlignment(vector_type);
1403 auto elem_size = InlineSize(vector_type);
1404 if (!IsStruct(vector_type)) {
1405 field_has_create_set.insert(&field);
1406 code += " public static VectorOffset ";
1407 code += "Create";
1408 code += Name(field);
1409 code += "Vector(FlatBufferBuilder builder, ";
1410 code += GenTypeBasic(vector_type) + "[] data) ";
1411 code += "{ builder.StartVector(";
1412 code += NumToString(elem_size);
1413 code += ", data.Length, ";
1414 code += NumToString(alignment);
1415 code += "); for (int i = data.";
1416 code += "Length - 1; i >= 0; i--) builder.";
1417 code += "Add";
1418 code += GenMethod(vector_type);
1419 code += "(";
1420 // At the moment there is no support of the type Vector with
1421 // optional enum, e.g. if we have enum type SomeEnum there is no way
1422 // to define `SomeEmum?[] enums` in FlatBuffer schema, so isOptional
1423 // = false
1424 code += SourceCastBasic(vector_type, false);
1425 code += "data[i]";
1426 if (vector_type.base_type == BASE_TYPE_STRUCT ||
1427 IsString(vector_type))
1428 code += ".Value";
1429 code += "); return ";
1430 code += "builder.EndVector(); }\n";
1431
1432 // add Create...VectorBlock() overloads for T[], ArraySegment<T> and
1433 // IntPtr
1434 code += " public static VectorOffset ";
1435 code += "Create";
1436 code += Name(field);
1437 code += "VectorBlock(FlatBufferBuilder builder, ";
1438 code += GenTypeBasic(vector_type) + "[] data) ";
1439 code += "{ builder.StartVector(";
1440 code += NumToString(elem_size);
1441 code += ", data.Length, ";
1442 code += NumToString(alignment);
1443 code += "); builder.Add(data); return builder.EndVector(); }\n";
1444
1445 code += " public static VectorOffset ";
1446 code += "Create";
1447 code += Name(field);
1448 code += "VectorBlock(FlatBufferBuilder builder, ";
1449 code += "ArraySegment<" + GenTypeBasic(vector_type) + "> data) ";
1450 code += "{ builder.StartVector(";
1451 code += NumToString(elem_size);
1452 code += ", data.Count, ";
1453 code += NumToString(alignment);
1454 code += "); builder.Add(data); return builder.EndVector(); }\n";
1455
1456 code += " public static VectorOffset ";
1457 code += "Create";
1458 code += Name(field);
1459 code += "VectorBlock(FlatBufferBuilder builder, ";
1460 code += "IntPtr dataPtr, int sizeInBytes) ";
1461 code += "{ builder.StartVector(1, sizeInBytes, 1); ";
1462 code += "builder.Add<" + GenTypeBasic(vector_type) +
1463 ">(dataPtr, sizeInBytes); return builder.EndVector(); }\n";
1464 }
1465 // Generate a method to start a vector, data to be added manually
1466 // after.
1467 code += " public static void Start";
1468 code += Name(field);
1469 code += "Vector(FlatBufferBuilder builder, int numElems) ";
1470 code += "{ builder.StartVector(";
1471 code += NumToString(elem_size);
1472 code += ", numElems, " + NumToString(alignment);
1473 code += "); }\n";
1474 }
1475 }
1476 code += " public static " + GenOffsetType(struct_def) + " ";
1477 code += "End" + struct_def.name;
1478 code += "(FlatBufferBuilder builder) {\n int o = builder.";
1479 code += "EndTable();\n";
1480 for (auto it = struct_def.fields.vec.begin();
1481 it != struct_def.fields.vec.end(); ++it) {
1482 auto &field = **it;
1483 if (!field.deprecated && field.IsRequired()) {
1484 code += " builder.Required(o, ";
1485 code += NumToString(field.value.offset);
1486 code += "); // " + field.name + "\n";
1487 }
1488 }
1489 code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
1490 if (parser_.root_struct_def_ == &struct_def) {
1491 std::string size_prefix[] = { "", "SizePrefixed" };
1492 for (int i = 0; i < 2; ++i) {
1493 code += " public static void ";
1494 code += "Finish" + size_prefix[i] + struct_def.name;
1495 code +=
1496 "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def);
1497 code += " offset) {";
1498 code += " builder.Finish" + size_prefix[i] + "(offset";
1499 code += ".Value";
1500
1501 if (parser_.file_identifier_.length())
1502 code += ", \"" + parser_.file_identifier_ + "\"";
1503 code += "); }\n";
1504 }
1505 }
1506 }
1507 // Only generate key compare function for table,
1508 // because `key_field` is not set for struct
1509 if (struct_def.has_key && !struct_def.fixed) {
1510 FLATBUFFERS_ASSERT(key_field);
1511 auto name = Name(*key_field);
1512 if (name == struct_def.name) { name += "_"; }
1513 code += "\n public static VectorOffset ";
1514 code += "CreateSortedVectorOf" + struct_def.name;
1515 code += "(FlatBufferBuilder builder, ";
1516 code += "Offset<" + struct_def.name + ">";
1517 code += "[] offsets) {\n";
1518 code += " Array.Sort(offsets,\n";
1519 code += " (Offset<" + struct_def.name + "> o1, Offset<" +
1520 struct_def.name + "> o2) =>\n";
1521 code += " " + GenKeyGetter(struct_def, key_field);
1522 code += ");\n";
1523 code += " return builder.CreateVectorOfTables(offsets);\n }\n";
1524
1525 code += "\n public static " + struct_def.name + "?";
1526 code += " __lookup_by_key(";
1527 code += "int vectorLocation, ";
1528 code += GenTypeGet(key_field->value.type);
1529 code += " key, ByteBuffer bb) {\n";
1530 code +=
1531 " " + struct_def.name + " obj_ = new " + struct_def.name + "();\n";
1532 code += " int span = ";
1533 code += "bb.GetInt(vectorLocation - 4);\n";
1534 code += " int start = 0;\n";
1535 code += " while (span != 0) {\n";
1536 code += " int middle = span / 2;\n";
1537 code +=
1538 " int tableOffset = Table.__indirect(vectorLocation + 4 * "
1539 "(start + middle), bb);\n";
1540
1541 code += " obj_.__assign(tableOffset, bb);\n";
1542 code += " int comp = obj_." + name + ".CompareTo(key);\n";
1543 code += " if (comp > 0) {\n";
1544 code += " span = middle;\n";
1545 code += " } else if (comp < 0) {\n";
1546 code += " middle++;\n";
1547 code += " start += middle;\n";
1548 code += " span -= middle;\n";
1549 code += " } else {\n";
1550 code += " return obj_;\n";
1551 code += " }\n }\n";
1552 code += " return null;\n";
1553 code += " }\n";
1554 }
1555
1556 if (opts.generate_object_based_api) {
1557 GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
1558 field_has_create_set);
1559 }
1560 code += "}\n\n";
1561
1562 if (opts.generate_object_based_api) {
1563 GenStruct_ObjectAPI(struct_def, code_ptr, opts);
1564 }
1565 }
1566
GenVectorAccessObject(StructDef & struct_def,std::string * code_ptr) const1567 void GenVectorAccessObject(StructDef &struct_def,
1568 std::string *code_ptr) const {
1569 auto &code = *code_ptr;
1570 // Generate a vector of structs accessor class.
1571 code += "\n";
1572 code += " ";
1573 if (!struct_def.attributes.Lookup("private")) code += "public ";
1574 code += "static struct Vector : BaseVector\n{\n";
1575
1576 // Generate the __assign method that sets the field in a pre-existing
1577 // accessor object. This is to allow object reuse.
1578 std::string method_indent = " ";
1579 code += method_indent + "public Vector ";
1580 code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1581 code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1582
1583 auto type_name = struct_def.name;
1584 auto method_start = method_indent + "public " + type_name + " Get";
1585 // Generate the accessors that don't do object reuse.
1586 code += method_start + "(int j) { return Get";
1587 code += "(new " + type_name + "(), j); }\n";
1588 code += method_start + "(" + type_name + " obj, int j) { ";
1589 code += " return obj.__assign(";
1590 code += struct_def.fixed ? "__p.__element(j)"
1591 : "__p.__indirect(__p.__element(j), bb)";
1592 code += ", __p.bb); }\n";
1593 // See if we should generate a by-key accessor.
1594 if (!struct_def.fixed) {
1595 auto &fields = struct_def.fields.vec;
1596 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1597 auto &key_field = **kit;
1598 if (key_field.key) {
1599 auto nullable_annotation =
1600 parser_.opts.gen_nullable ? "@Nullable " : "";
1601 code += method_indent + nullable_annotation;
1602 code += "public " + type_name + "? ";
1603 code += "GetByKey(";
1604 code += GenTypeGet(key_field.value.type) + " key) { ";
1605 code += " return __lookup_by_key(null, ";
1606 code += "__p.__vector(), key, ";
1607 code += "__p.bb); ";
1608 code += "}\n";
1609 code += method_indent + nullable_annotation;
1610 code += "public " + type_name + "?" + " ";
1611 code += "GetByKey(";
1612 code += type_name + "? obj, ";
1613 code += GenTypeGet(key_field.value.type) + " key) { ";
1614 code += " return __lookup_by_key(obj, ";
1615 code += "__p.__vector(), key, ";
1616 code += "__p.bb); ";
1617 code += "}\n";
1618 break;
1619 }
1620 }
1621 }
1622 code += " }\n";
1623 }
1624
GenUnionVerify(const Type & union_type) const1625 std::string GenUnionVerify(const Type &union_type) const {
1626 if (union_type.enum_def) {
1627 const auto &enum_def = *union_type.enum_def;
1628
1629 auto ret = "\n\nstatic public class " + enum_def.name + "Verify\n";
1630 ret += "{\n";
1631 ret +=
1632 " static public bool Verify(Google.FlatBuffers.Verifier verifier, "
1633 "byte typeId, uint tablePos)\n";
1634 ret += " {\n";
1635 ret += " bool result = true;\n";
1636
1637 const auto union_enum_loop = [&]() {
1638 ret += " switch((" + enum_def.name + ")typeId)\n";
1639 ret += " {\n";
1640
1641 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1642 ++it) {
1643 const auto &ev = **it;
1644 if (ev.IsZero()) { continue; }
1645
1646 ret += " case " + Name(enum_def) + "." + Name(ev) + ":\n";
1647
1648 if (IsString(ev.union_type)) {
1649 ret += " result = verifier.VerifyUnionString(tablePos);\n";
1650 ret += " break;";
1651 } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1652 if (!ev.union_type.struct_def->fixed) {
1653 auto type = GenTypeGet(ev.union_type);
1654 ret += " result = " + type +
1655 "Verify.Verify(verifier, tablePos);\n";
1656 } else {
1657 ret += " result = verifier.VerifyUnionData(tablePos, " +
1658 NumToString(InlineSize(ev.union_type)) + ", " +
1659 NumToString(InlineAlignment(ev.union_type)) + ");\n";
1660 ;
1661 }
1662 ret += " break;";
1663 } else {
1664 FLATBUFFERS_ASSERT(false);
1665 }
1666 ret += "\n";
1667 }
1668
1669 ret += " default: result = true;\n";
1670 ret += " break;\n";
1671 ret += " }\n";
1672 ret += " return result;\n";
1673 };
1674
1675 union_enum_loop();
1676 ret += " }\n";
1677 ret += "}\n";
1678 ret += "\n";
1679
1680 return ret;
1681 }
1682 FLATBUFFERS_ASSERT(0);
1683 return "";
1684 }
1685
GenEnum_ObjectAPI(EnumDef & enum_def,std::string * code_ptr,const IDLOptions & opts) const1686 void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr,
1687 const IDLOptions &opts) const {
1688 auto &code = *code_ptr;
1689 if (enum_def.generated) return;
1690 if (!enum_def.is_union) return;
1691 if (enum_def.attributes.Lookup("private")) {
1692 code += "internal ";
1693 } else {
1694 code += "public ";
1695 }
1696 auto union_name = enum_def.name + "Union";
1697 auto class_member = std::string("Value");
1698 if (class_member == enum_def.name) { class_member += "_"; };
1699 code += "class " + union_name + " {\n";
1700 // Type
1701 code += " public " + enum_def.name + " Type { get; set; }\n";
1702 // Value
1703 code += " public object " + class_member + " { get; set; }\n";
1704 code += "\n";
1705 // Constructor
1706 code += " public " + union_name + "() {\n";
1707 code += " this.Type = " + enum_def.name + "." +
1708 enum_def.Vals()[0]->name + ";\n";
1709 code += " this." + class_member + " = null;\n";
1710 code += " }\n\n";
1711 // As<T>
1712 code += " public T As<T>() where T : class { return this." + class_member +
1713 " as T; }\n";
1714 // As, From
1715 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1716 auto &ev = **it;
1717 if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
1718 auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
1719 std::string accessibility =
1720 (ev.union_type.base_type == BASE_TYPE_STRUCT &&
1721 ev.union_type.struct_def->attributes.Lookup("private"))
1722 ? "internal"
1723 : "public";
1724 // As
1725 code += " " + accessibility + " " + type_name + " As" + ev.name +
1726 "() { return this.As<" + type_name + ">(); }\n";
1727 // From
1728 auto lower_ev_name = ev.name;
1729 std::transform(lower_ev_name.begin(), lower_ev_name.end(),
1730 lower_ev_name.begin(), CharToLower);
1731 code += " " + accessibility + " static " + union_name + " From" +
1732 ev.name + "(" + type_name + " _" + lower_ev_name +
1733 ") { return new " + union_name + "{ Type = " + Name(enum_def) +
1734 "." + Name(ev) + ", " + class_member + " = _" + lower_ev_name +
1735 " }; }\n";
1736 }
1737 code += "\n";
1738 // Pack()
1739 code +=
1740 " public static int Pack(Google.FlatBuffers.FlatBufferBuilder "
1741 "builder, " +
1742 union_name + " _o) {\n";
1743 code += " switch (_o.Type) {\n";
1744 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1745 auto &ev = **it;
1746 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1747 code += " default: return 0;\n";
1748 } else {
1749 code += " case " + Name(enum_def) + "." + Name(ev) + ": return ";
1750 if (IsString(ev.union_type)) {
1751 code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n";
1752 } else {
1753 code += GenTypeGet(ev.union_type) + ".Pack(builder, _o.As" + ev.name +
1754 "()).Value;\n";
1755 }
1756 }
1757 }
1758 code += " }\n";
1759 code += " }\n";
1760 code += "}\n\n";
1761
1762 // JsonConverter
1763 if (opts.cs_gen_json_serializer) {
1764 if (enum_def.attributes.Lookup("private")) {
1765 code += "internal ";
1766 } else {
1767 code += "public ";
1768 }
1769 code += "class " + union_name +
1770 "_JsonConverter : Newtonsoft.Json.JsonConverter {\n";
1771 code += " public override bool CanConvert(System.Type objectType) {\n";
1772 code += " return objectType == typeof(" + union_name +
1773 ") || objectType == typeof(System.Collections.Generic.List<" +
1774 union_name + ">);\n";
1775 code += " }\n";
1776 code +=
1777 " public override void WriteJson(Newtonsoft.Json.JsonWriter writer, "
1778 "object value, "
1779 "Newtonsoft.Json.JsonSerializer serializer) {\n";
1780 code += " var _olist = value as System.Collections.Generic.List<" +
1781 union_name + ">;\n";
1782 code += " if (_olist != null) {\n";
1783 code += " writer.WriteStartArray();\n";
1784 code +=
1785 " foreach (var _o in _olist) { this.WriteJson(writer, _o, "
1786 "serializer); }\n";
1787 code += " writer.WriteEndArray();\n";
1788 code += " } else {\n";
1789 code += " this.WriteJson(writer, value as " + union_name +
1790 ", serializer);\n";
1791 code += " }\n";
1792 code += " }\n";
1793 code += " public void WriteJson(Newtonsoft.Json.JsonWriter writer, " +
1794 union_name +
1795 " _o, "
1796 "Newtonsoft.Json.JsonSerializer serializer) {\n";
1797 code += " if (_o == null) return;\n";
1798 code += " serializer.Serialize(writer, _o." + class_member + ");\n";
1799 code += " }\n";
1800 code +=
1801 " public override object ReadJson(Newtonsoft.Json.JsonReader "
1802 "reader, "
1803 "System.Type objectType, "
1804 "object existingValue, Newtonsoft.Json.JsonSerializer serializer) "
1805 "{\n";
1806 code +=
1807 " var _olist = existingValue as System.Collections.Generic.List<" +
1808 union_name + ">;\n";
1809 code += " if (_olist != null) {\n";
1810 code += " for (var _j = 0; _j < _olist.Count; ++_j) {\n";
1811 code += " reader.Read();\n";
1812 code +=
1813 " _olist[_j] = this.ReadJson(reader, _olist[_j], "
1814 "serializer);\n";
1815 code += " }\n";
1816 code += " reader.Read();\n";
1817 code += " return _olist;\n";
1818 code += " } else {\n";
1819 code += " return this.ReadJson(reader, existingValue as " +
1820 union_name + ", serializer);\n";
1821 code += " }\n";
1822 code += " }\n";
1823 code += " public " + union_name +
1824 " ReadJson(Newtonsoft.Json.JsonReader reader, " + union_name +
1825 " _o, Newtonsoft.Json.JsonSerializer serializer) {\n";
1826 code += " if (_o == null) return null;\n";
1827 code += " switch (_o.Type) {\n";
1828 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1829 ++it) {
1830 auto &ev = **it;
1831 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1832 code += " default: break;\n";
1833 } else {
1834 auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
1835 code += " case " + Name(enum_def) + "." + Name(ev) + ": _o." +
1836 class_member + " = serializer.Deserialize<" + type_name +
1837 ">(reader); break;\n";
1838 }
1839 }
1840 code += " }\n";
1841 code += " return _o;\n";
1842 code += " }\n";
1843 code += "}\n\n";
1844 }
1845 }
1846
GenTypeName_ObjectAPI(const std::string & name,const IDLOptions & opts) const1847 std::string GenTypeName_ObjectAPI(const std::string &name,
1848 const IDLOptions &opts) const {
1849 return opts.object_prefix + name + opts.object_suffix;
1850 }
1851
GenUnionUnPack_ObjectAPI(const EnumDef & enum_def,std::string * code_ptr,const std::string & camel_name,const std::string & camel_name_short,bool is_vector) const1852 void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string *code_ptr,
1853 const std::string &camel_name,
1854 const std::string &camel_name_short,
1855 bool is_vector) const {
1856 auto &code = *code_ptr;
1857 std::string varialbe_name = "_o." + camel_name;
1858 std::string class_member = "Value";
1859 if (class_member == enum_def.name) class_member += "_";
1860 std::string type_suffix = "";
1861 std::string func_suffix = "()";
1862 std::string indent = " ";
1863 if (is_vector) {
1864 varialbe_name = "_o_" + camel_name;
1865 type_suffix = "(_j)";
1866 func_suffix = "(_j)";
1867 indent = " ";
1868 }
1869 if (is_vector) {
1870 code += indent + "var " + varialbe_name + " = new ";
1871 } else {
1872 code += indent + varialbe_name + " = new ";
1873 }
1874 code += NamespacedName(enum_def) + "Union();\n";
1875 code += indent + varialbe_name + ".Type = this." + camel_name_short +
1876 "Type" + type_suffix + ";\n";
1877 code += indent + "switch (this." + camel_name_short + "Type" + type_suffix +
1878 ") {\n";
1879 for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end();
1880 ++eit) {
1881 auto &ev = **eit;
1882 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1883 code += indent + " default: break;\n";
1884 } else {
1885 code += indent + " case " + NamespacedName(enum_def) + "." + ev.name +
1886 ":\n";
1887 code += indent + " " + varialbe_name + "." + class_member +
1888 " = this." + camel_name;
1889 if (IsString(ev.union_type)) {
1890 code += "AsString" + func_suffix + ";\n";
1891 } else {
1892 code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix;
1893 code += ".HasValue ? this." + camel_name;
1894 code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix +
1895 ".Value.UnPack() : null;\n";
1896 }
1897 code += indent + " break;\n";
1898 }
1899 }
1900 code += indent + "}\n";
1901 if (is_vector) {
1902 code += indent + "_o." + camel_name + ".Add(" + varialbe_name + ");\n";
1903 }
1904 }
1905
GenPackUnPack_ObjectAPI(StructDef & struct_def,std::string * code_ptr,const IDLOptions & opts,bool struct_has_create,const std::set<FieldDef * > & field_has_create) const1906 void GenPackUnPack_ObjectAPI(
1907 StructDef &struct_def, std::string *code_ptr, const IDLOptions &opts,
1908 bool struct_has_create,
1909 const std::set<FieldDef *> &field_has_create) const {
1910 auto &code = *code_ptr;
1911 auto struct_name = GenTypeName_ObjectAPI(struct_def.name, opts);
1912 // UnPack()
1913 code += " public " + struct_name + " UnPack() {\n";
1914 code += " var _o = new " + struct_name + "();\n";
1915 code += " this.UnPackTo(_o);\n";
1916 code += " return _o;\n";
1917 code += " }\n";
1918 // UnPackTo()
1919 code += " public void UnPackTo(" + struct_name + " _o) {\n";
1920 for (auto it = struct_def.fields.vec.begin();
1921 it != struct_def.fields.vec.end(); ++it) {
1922 auto &field = **it;
1923 if (field.deprecated) continue;
1924 auto camel_name = Name(field);
1925 if (camel_name == struct_def.name) { camel_name += "_"; }
1926 auto camel_name_short = Name(field);
1927 auto start = " _o." + camel_name + " = ";
1928 switch (field.value.type.base_type) {
1929 case BASE_TYPE_STRUCT: {
1930 auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
1931 if (fixed) {
1932 code += start + "this." + camel_name + ".UnPack();\n";
1933 } else {
1934 code += start + "this." + camel_name + ".HasValue ? this." +
1935 camel_name + ".Value.UnPack() : null;\n";
1936 }
1937 break;
1938 }
1939 case BASE_TYPE_ARRAY: {
1940 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
1941 auto length_str = NumToString(field.value.type.fixed_length);
1942 auto unpack_method = field.value.type.struct_def == nullptr ? ""
1943 : field.value.type.struct_def->fixed
1944 ? ".UnPack()"
1945 : "?.UnPack()";
1946 code += start + "new " + type_name.substr(0, type_name.length() - 1) +
1947 length_str + "];\n";
1948 code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." +
1949 camel_name + "[_j] = this." + camel_name + "(_j)" +
1950 unpack_method + "; }\n";
1951 break;
1952 }
1953 case BASE_TYPE_VECTOR:
1954 if (field.value.type.element == BASE_TYPE_UNION) {
1955 code += start + "new " +
1956 GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
1957 code += " for (var _j = 0; _j < this." + camel_name +
1958 "Length; ++_j) {\n";
1959 GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
1960 camel_name, camel_name_short, true);
1961 code += " }\n";
1962 } else if (field.value.type.element != BASE_TYPE_UTYPE) {
1963 auto fixed = field.value.type.struct_def == nullptr;
1964 code += start + "new " +
1965 GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
1966 code += " for (var _j = 0; _j < this." + camel_name +
1967 "Length; ++_j) {";
1968 code += "_o." + camel_name + ".Add(";
1969 if (fixed) {
1970 code += "this." + camel_name + "(_j)";
1971 } else {
1972 code += "this." + camel_name + "(_j).HasValue ? this." +
1973 camel_name + "(_j).Value.UnPack() : null";
1974 }
1975 code += ");}\n";
1976 }
1977 break;
1978 case BASE_TYPE_UTYPE: break;
1979 case BASE_TYPE_UNION: {
1980 GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
1981 camel_name, camel_name_short, false);
1982 break;
1983 }
1984 default: {
1985 code += start + "this." + camel_name + ";\n";
1986 break;
1987 }
1988 }
1989 }
1990 code += " }\n";
1991 // Pack()
1992 code += " public static " + GenOffsetType(struct_def) +
1993 " Pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
1994 code += " if (_o == null) return default(" + GenOffsetType(struct_def) +
1995 ");\n";
1996 for (auto it = struct_def.fields.vec.begin();
1997 it != struct_def.fields.vec.end(); ++it) {
1998 auto &field = **it;
1999 if (field.deprecated) continue;
2000 auto camel_name = Name(field);
2001 if (camel_name == struct_def.name) { camel_name += "_"; }
2002 auto camel_name_short = Name(field);
2003 // pre
2004 switch (field.value.type.base_type) {
2005 case BASE_TYPE_STRUCT: {
2006 if (!field.value.type.struct_def->fixed) {
2007 code += " var _" + field.name + " = _o." + camel_name +
2008 " == null ? default(" +
2009 GenOffsetType(*field.value.type.struct_def) +
2010 ") : " + GenTypeGet(field.value.type) +
2011 ".Pack(builder, _o." + camel_name + ");\n";
2012 } else if (struct_def.fixed && struct_has_create) {
2013 std::vector<FieldArrayLength> array_lengths;
2014 FieldArrayLength tmp_array_length = {
2015 field.name,
2016 field.value.type.fixed_length,
2017 };
2018 array_lengths.push_back(tmp_array_length);
2019 GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
2020 array_lengths);
2021 }
2022 break;
2023 }
2024 case BASE_TYPE_STRING: {
2025 std::string create_string =
2026 field.shared ? "CreateSharedString" : "CreateString";
2027 code += " var _" + field.name + " = _o." + camel_name +
2028 " == null ? default(StringOffset) : "
2029 "builder." +
2030 create_string + "(_o." + camel_name + ");\n";
2031 break;
2032 }
2033 case BASE_TYPE_VECTOR: {
2034 if (field_has_create.find(&field) != field_has_create.end()) {
2035 auto property_name = camel_name;
2036 auto gen_for_loop = true;
2037 std::string array_name = "__" + field.name;
2038 std::string array_type = "";
2039 std::string to_array = "";
2040 switch (field.value.type.element) {
2041 case BASE_TYPE_STRING: {
2042 std::string create_string =
2043 field.shared ? "CreateSharedString" : "CreateString";
2044 array_type = "StringOffset";
2045 to_array += "builder." + create_string + "(_o." +
2046 property_name + "[_j])";
2047 break;
2048 }
2049 case BASE_TYPE_STRUCT:
2050 array_type = "Offset<" + GenTypeGet(field.value.type) + ">";
2051 to_array = GenTypeGet(field.value.type) + ".Pack(builder, _o." +
2052 property_name + "[_j])";
2053 break;
2054 case BASE_TYPE_UTYPE:
2055 property_name = camel_name.substr(0, camel_name.size() - 4);
2056 array_type = NamespacedName(*field.value.type.enum_def);
2057 to_array = "_o." + property_name + "[_j].Type";
2058 break;
2059 case BASE_TYPE_UNION:
2060 array_type = "int";
2061 to_array = NamespacedName(*field.value.type.enum_def) +
2062 "Union.Pack(builder, _o." + property_name + "[_j])";
2063 break;
2064 default: gen_for_loop = false; break;
2065 }
2066 code += " var _" + field.name + " = default(VectorOffset);\n";
2067 code += " if (_o." + property_name + " != null) {\n";
2068 if (gen_for_loop) {
2069 code += " var " + array_name + " = new " + array_type +
2070 "[_o." + property_name + ".Count];\n";
2071 code += " for (var _j = 0; _j < " + array_name +
2072 ".Length; ++_j) { ";
2073 code += array_name + "[_j] = " + to_array + "; }\n";
2074 } else {
2075 code += " var " + array_name + " = _o." + property_name +
2076 ".ToArray();\n";
2077 }
2078 code += " _" + field.name + " = Create" + camel_name_short +
2079 "Vector(builder, " + array_name + ");\n";
2080 code += " }\n";
2081 } else {
2082 auto pack_method =
2083 field.value.type.struct_def == nullptr
2084 ? "builder.Add" + GenMethod(field.value.type.VectorType()) +
2085 "(_o." + camel_name + "[_j]);"
2086 : GenTypeGet(field.value.type) + ".Pack(builder, _o." +
2087 camel_name + "[_j]);";
2088 code += " var _" + field.name + " = default(VectorOffset);\n";
2089 code += " if (_o." + camel_name + " != null) {\n";
2090 code += " Start" + camel_name_short + "Vector(builder, _o." +
2091 camel_name + ".Count);\n";
2092 code += " for (var _j = _o." + camel_name +
2093 ".Count - 1; _j >= 0; --_j) { " + pack_method + " }\n";
2094 code += " _" + field.name + " = builder.EndVector();\n";
2095 code += " }\n";
2096 }
2097 break;
2098 }
2099 case BASE_TYPE_ARRAY: {
2100 if (field.value.type.struct_def != nullptr) {
2101 std::vector<FieldArrayLength> array_lengths;
2102 FieldArrayLength tmp_array_length = {
2103 field.name,
2104 field.value.type.fixed_length,
2105 };
2106 array_lengths.push_back(tmp_array_length);
2107 GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
2108 array_lengths);
2109 } else {
2110 code += " var _" + field.name + " = _o." + camel_name + ";\n";
2111 }
2112 break;
2113 }
2114 case BASE_TYPE_UNION: {
2115 code += " var _" + field.name + "_type = _o." + camel_name +
2116 " == null ? " + NamespacedName(*field.value.type.enum_def) +
2117 ".NONE : " + "_o." + camel_name + ".Type;\n";
2118 code +=
2119 " var _" + field.name + " = _o." + camel_name +
2120 " == null ? 0 : " + GenTypeGet_ObjectAPI(field.value.type, opts) +
2121 ".Pack(builder, _o." + camel_name + ");\n";
2122 break;
2123 }
2124 default: break;
2125 }
2126 }
2127 if (struct_has_create) {
2128 // Create
2129 code += " return Create" + struct_def.name + "(\n";
2130 code += " builder";
2131 for (auto it = struct_def.fields.vec.begin();
2132 it != struct_def.fields.vec.end(); ++it) {
2133 auto &field = **it;
2134 if (field.deprecated) continue;
2135 auto camel_name = Name(field);
2136 if (camel_name == struct_def.name) { camel_name += "_"; }
2137 switch (field.value.type.base_type) {
2138 case BASE_TYPE_STRUCT: {
2139 if (struct_def.fixed) {
2140 GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
2141 code_ptr,
2142 " _" + field.name + "_");
2143 } else {
2144 code += ",\n";
2145 if (field.value.type.struct_def->fixed) {
2146 if (opts.generate_object_based_api)
2147 code += " _o." + camel_name;
2148 else
2149 code += " " + GenTypeGet(field.value.type) +
2150 ".Pack(builder, _o." + camel_name + ")";
2151 } else {
2152 code += " _" + field.name;
2153 }
2154 }
2155 break;
2156 }
2157 case BASE_TYPE_ARRAY: {
2158 if (field.value.type.struct_def != nullptr) {
2159 GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
2160 code_ptr,
2161 " _" + field.name + "_");
2162 } else {
2163 code += ",\n";
2164 code += " _" + field.name;
2165 }
2166 break;
2167 }
2168 case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // fall thru
2169 case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH(); // fall thru
2170 case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
2171 case BASE_TYPE_VECTOR: {
2172 code += ",\n";
2173 code += " _" + field.name;
2174 break;
2175 }
2176 default: // scalar
2177 code += ",\n";
2178 code += " _o." + camel_name;
2179 break;
2180 }
2181 }
2182 code += ");\n";
2183 } else {
2184 // Start, End
2185 code += " Start" + struct_def.name + "(builder);\n";
2186 for (auto it = struct_def.fields.vec.begin();
2187 it != struct_def.fields.vec.end(); ++it) {
2188 auto &field = **it;
2189 if (field.deprecated) continue;
2190 auto camel_name = Name(field);
2191 switch (field.value.type.base_type) {
2192 case BASE_TYPE_STRUCT: {
2193 if (field.value.type.struct_def->fixed) {
2194 code += " Add" + camel_name + "(builder, " +
2195 GenTypeGet(field.value.type) + ".Pack(builder, _o." +
2196 camel_name + "));\n";
2197 } else {
2198 code +=
2199 " Add" + camel_name + "(builder, _" + field.name + ");\n";
2200 }
2201 break;
2202 }
2203 case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
2204 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
2205 case BASE_TYPE_VECTOR: {
2206 code +=
2207 " Add" + camel_name + "(builder, _" + field.name + ");\n";
2208 break;
2209 }
2210 case BASE_TYPE_UTYPE: break;
2211 case BASE_TYPE_UNION: {
2212 code += " Add" + camel_name + "Type(builder, _" + field.name +
2213 "_type);\n";
2214 code +=
2215 " Add" + camel_name + "(builder, _" + field.name + ");\n";
2216 break;
2217 }
2218 // scalar
2219 default: {
2220 code +=
2221 " Add" + camel_name + "(builder, _o." + camel_name + ");\n";
2222 break;
2223 }
2224 }
2225 }
2226 code += " return End" + struct_def.name + "(builder);\n";
2227 }
2228 code += " }\n";
2229 }
2230
GenStructPackDecl_ObjectAPI(const StructDef & struct_def,std::string * code_ptr,std::vector<FieldArrayLength> & array_lengths) const2231 void GenStructPackDecl_ObjectAPI(
2232 const StructDef &struct_def, std::string *code_ptr,
2233 std::vector<FieldArrayLength> &array_lengths) const {
2234 auto &code = *code_ptr;
2235 for (auto it = struct_def.fields.vec.begin();
2236 it != struct_def.fields.vec.end(); ++it) {
2237 auto &field = **it;
2238 auto is_array = IsArray(field.value.type);
2239 const auto &field_type =
2240 is_array ? field.value.type.VectorType() : field.value.type;
2241 FieldArrayLength tmp_array_length = {
2242 field.name,
2243 field_type.fixed_length,
2244 };
2245 array_lengths.push_back(tmp_array_length);
2246 if (field_type.struct_def != nullptr) {
2247 GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr,
2248 array_lengths);
2249 } else {
2250 std::vector<FieldArrayLength> array_only_lengths;
2251 for (size_t i = 0; i < array_lengths.size(); ++i) {
2252 if (array_lengths[i].length > 0) {
2253 array_only_lengths.push_back(array_lengths[i]);
2254 }
2255 }
2256 std::string name;
2257 for (size_t i = 0; i < array_lengths.size(); ++i) {
2258 name += "_" + array_lengths[i].name;
2259 }
2260 code += " var " + name + " = ";
2261 if (array_only_lengths.size() > 0) {
2262 code += "new " + GenTypeBasic(field_type) + "[";
2263 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
2264 if (i != 0) { code += ","; }
2265 code += NumToString(array_only_lengths[i].length);
2266 }
2267 code += "];\n";
2268 code += " ";
2269 // initialize array
2270 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
2271 auto idx = "idx" + NumToString(i);
2272 code += "for (var " + idx + " = 0; " + idx + " < " +
2273 NumToString(array_only_lengths[i].length) + "; ++" + idx +
2274 ") {";
2275 }
2276 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
2277 auto idx = "idx" + NumToString(i);
2278 if (i == 0) {
2279 code += name + "[" + idx;
2280 } else {
2281 code += "," + idx;
2282 }
2283 }
2284 code += "] = _o";
2285 for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
2286 code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel);
2287 if (array_lengths[i].length <= 0) continue;
2288 code += "[idx" + NumToString(j++) + "]";
2289 }
2290 code += ";";
2291 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
2292 code += "}";
2293 }
2294 } else {
2295 code += "_o";
2296 for (size_t i = 0; i < array_lengths.size(); ++i) {
2297 code += "." + ConvertCase(array_lengths[i].name, Case::kUpperCamel);
2298 }
2299 code += ";";
2300 }
2301 code += "\n";
2302 }
2303 array_lengths.pop_back();
2304 }
2305 }
2306
GenStructPackCall_ObjectAPI(const StructDef & struct_def,std::string * code_ptr,std::string prefix) const2307 void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
2308 std::string *code_ptr,
2309 std::string prefix) const {
2310 auto &code = *code_ptr;
2311 for (auto it = struct_def.fields.vec.begin();
2312 it != struct_def.fields.vec.end(); ++it) {
2313 auto &field = **it;
2314 const auto &field_type = field.value.type;
2315 if (field_type.struct_def != nullptr) {
2316 GenStructPackCall_ObjectAPI(*field_type.struct_def, code_ptr,
2317 prefix + field.name + "_");
2318 } else {
2319 code += ",\n";
2320 code += prefix + field.name;
2321 }
2322 }
2323 }
2324
GenTypeGet_ObjectAPI(flatbuffers::Type type,const IDLOptions & opts) const2325 std::string GenTypeGet_ObjectAPI(flatbuffers::Type type,
2326 const IDLOptions &opts) const {
2327 auto type_name = GenTypeGet(type);
2328 // Replace to ObjectBaseAPI Type Name
2329 switch (type.base_type) {
2330 case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru
2331 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
2332 case BASE_TYPE_VECTOR: {
2333 if (type.struct_def != nullptr) {
2334 auto type_name_length = type.struct_def->name.length();
2335 auto new_type_name =
2336 GenTypeName_ObjectAPI(type.struct_def->name, opts);
2337 type_name.replace(type_name.length() - type_name_length,
2338 type_name_length, new_type_name);
2339 } else if (type.element == BASE_TYPE_UNION) {
2340 type_name = NamespacedName(*type.enum_def) + "Union";
2341 }
2342 break;
2343 }
2344
2345 case BASE_TYPE_UNION: {
2346 type_name = NamespacedName(*type.enum_def) + "Union";
2347 break;
2348 }
2349 default: break;
2350 }
2351
2352 switch (type.base_type) {
2353 case BASE_TYPE_ARRAY: {
2354 type_name = type_name + "[]";
2355 break;
2356 }
2357 case BASE_TYPE_VECTOR: {
2358 type_name = "List<" + type_name + ">";
2359 break;
2360 }
2361 default: break;
2362 }
2363 return type_name;
2364 }
2365
GenStruct_ObjectAPI(StructDef & struct_def,std::string * code_ptr,const IDLOptions & opts) const2366 void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr,
2367 const IDLOptions &opts) const {
2368 auto &code = *code_ptr;
2369 if (struct_def.attributes.Lookup("private")) {
2370 code += "internal ";
2371 } else {
2372 code += "public ";
2373 }
2374 if (struct_def.attributes.Lookup("csharp_partial")) {
2375 // generate a partial class for this C# struct/table
2376 code += "partial ";
2377 }
2378 auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts);
2379 code += "class " + class_name;
2380 code += "\n{\n";
2381 // Generate Properties
2382 for (auto it = struct_def.fields.vec.begin();
2383 it != struct_def.fields.vec.end(); ++it) {
2384 auto &field = **it;
2385 if (field.deprecated) continue;
2386 if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2387 if (field.value.type.element == BASE_TYPE_UTYPE) continue;
2388 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
2389 if (field.IsScalarOptional()) type_name += "?";
2390 auto camel_name = Name(field);
2391 if (camel_name == struct_def.name) { camel_name += "_"; }
2392 if (opts.cs_gen_json_serializer) {
2393 if (IsUnion(field.value.type)) {
2394 auto utype_name = NamespacedName(*field.value.type.enum_def);
2395 code +=
2396 " [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n";
2397 if (IsVector(field.value.type)) {
2398 code += " private " + utype_name + "[] " + camel_name + "Type {\n";
2399 code += " get {\n";
2400 code += " if (this." + camel_name + " == null) return null;\n";
2401 code += " var _o = new " + utype_name + "[this." + camel_name +
2402 ".Count];\n";
2403 code +=
2404 " for (var _j = 0; _j < _o.Length; ++_j) { _o[_j] = "
2405 "this." +
2406 camel_name + "[_j].Type; }\n";
2407 code += " return _o;\n";
2408 code += " }\n";
2409 code += " set {\n";
2410 code += " this." + camel_name + " = new List<" + utype_name +
2411 "Union>();\n";
2412 code += " for (var _j = 0; _j < value.Length; ++_j) {\n";
2413 code += " var _o = new " + utype_name + "Union();\n";
2414 code += " _o.Type = value[_j];\n";
2415 code += " this." + camel_name + ".Add(_o);\n";
2416 code += " }\n";
2417 code += " }\n";
2418 code += " }\n";
2419 } else {
2420 code += " private " + utype_name + " " + camel_name + "Type {\n";
2421 code += " get {\n";
2422 code += " return this." + camel_name + " != null ? this." +
2423 camel_name + ".Type : " + utype_name + ".NONE;\n";
2424 code += " }\n";
2425 code += " set {\n";
2426 code += " this." + camel_name + " = new " + utype_name +
2427 "Union();\n";
2428 code += " this." + camel_name + ".Type = value;\n";
2429 code += " }\n";
2430 code += " }\n";
2431 }
2432 }
2433 code += " [Newtonsoft.Json.JsonProperty(\"" + field.name + "\")]\n";
2434 if (IsUnion(field.value.type)) {
2435 auto union_name =
2436 (IsVector(field.value.type))
2437 ? GenTypeGet_ObjectAPI(field.value.type.VectorType(), opts)
2438 : type_name;
2439 code += " [Newtonsoft.Json.JsonConverter(typeof(" + union_name +
2440 "_JsonConverter))]\n";
2441 }
2442 if (field.attributes.Lookup("hash")) {
2443 code += " [Newtonsoft.Json.JsonIgnore()]\n";
2444 }
2445 }
2446 code += " public " + type_name + " " + camel_name + " { get; set; }\n";
2447 }
2448 // Generate Constructor
2449 code += "\n";
2450 code += " public " + class_name + "() {\n";
2451 for (auto it = struct_def.fields.vec.begin();
2452 it != struct_def.fields.vec.end(); ++it) {
2453 auto &field = **it;
2454 if (field.deprecated) continue;
2455 if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2456 if (field.value.type.element == BASE_TYPE_UTYPE) continue;
2457 auto camel_name = Name(field);
2458 if (camel_name == struct_def.name) { camel_name += "_"; }
2459 code += " this." + camel_name + " = ";
2460 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
2461 if (IsScalar(field.value.type.base_type)) {
2462 code += GenDefaultValue(field) + ";\n";
2463 } else {
2464 switch (field.value.type.base_type) {
2465 case BASE_TYPE_STRUCT: {
2466 if (IsStruct(field.value.type)) {
2467 code += "new " + type_name + "();\n";
2468 } else {
2469 code += "null;\n";
2470 }
2471 break;
2472 }
2473 case BASE_TYPE_ARRAY: {
2474 code += "new " + type_name.substr(0, type_name.length() - 1) +
2475 NumToString(field.value.type.fixed_length) + "];\n";
2476 break;
2477 }
2478 default: {
2479 code += "null;\n";
2480 break;
2481 }
2482 }
2483 }
2484 }
2485 code += " }\n";
2486 // Generate Serialization
2487 if (opts.cs_gen_json_serializer &&
2488 parser_.root_struct_def_ == &struct_def) {
2489 code += "\n";
2490 code += " public static " + class_name +
2491 " DeserializeFromJson(string jsonText) {\n";
2492 code += " return Newtonsoft.Json.JsonConvert.DeserializeObject<" +
2493 class_name + ">(jsonText);\n";
2494 code += " }\n";
2495 code += " public string SerializeToJson() {\n";
2496 code +=
2497 " return Newtonsoft.Json.JsonConvert.SerializeObject(this, "
2498 "Newtonsoft.Json.Formatting.Indented);\n";
2499 code += " }\n";
2500 }
2501 if (parser_.root_struct_def_ == &struct_def) {
2502 code += " public static " + class_name +
2503 " DeserializeFromBinary(byte[] fbBuffer) {\n";
2504 code += " return " + struct_def.name + ".GetRootAs" + struct_def.name +
2505 "(new ByteBuffer(fbBuffer)).UnPack();\n";
2506 code += " }\n";
2507 code += " public byte[] SerializeToBinary() {\n";
2508 code += " var fbb = new FlatBufferBuilder(0x10000);\n";
2509 code += " " + struct_def.name + ".Finish" + struct_def.name +
2510 "Buffer(fbb, " + struct_def.name + ".Pack(fbb, this));\n";
2511 code += " return fbb.DataBuffer.ToSizedArray();\n";
2512 code += " }\n";
2513 }
2514 code += "}\n\n";
2515 }
2516
2517 // This tracks the current namespace used to determine if a type need to be
2518 // prefixed by its namespace
2519 const Namespace *cur_name_space_;
2520 };
2521 } // namespace csharp
2522
GenerateCSharp(const Parser & parser,const std::string & path,const std::string & file_name)2523 static bool GenerateCSharp(const Parser &parser, const std::string &path,
2524 const std::string &file_name) {
2525 csharp::CSharpGenerator generator(parser, path, file_name);
2526 return generator.generate();
2527 }
2528
2529 namespace {
2530
2531 class CSharpCodeGenerator : public CodeGenerator {
2532 public:
GenerateCode(const Parser & parser,const std::string & path,const std::string & filename)2533 Status GenerateCode(const Parser &parser, const std::string &path,
2534 const std::string &filename) override {
2535 if (!GenerateCSharp(parser, path, filename)) { return Status::ERROR; }
2536 return Status::OK;
2537 }
2538
GenerateCode(const uint8_t *,int64_t,const CodeGenOptions &)2539 Status GenerateCode(const uint8_t *, int64_t,
2540 const CodeGenOptions &) override {
2541 return Status::NOT_IMPLEMENTED;
2542 }
2543
GenerateMakeRule(const Parser & parser,const std::string & path,const std::string & filename,std::string & output)2544 Status GenerateMakeRule(const Parser &parser, const std::string &path,
2545 const std::string &filename,
2546 std::string &output) override {
2547 output = JavaCSharpMakeRule(false, parser, path, filename);
2548 return Status::OK;
2549 }
2550
GenerateGrpcCode(const Parser & parser,const std::string & path,const std::string & filename)2551 Status GenerateGrpcCode(const Parser &parser, const std::string &path,
2552 const std::string &filename) override {
2553 (void)parser;
2554 (void)path;
2555 (void)filename;
2556 return Status::NOT_IMPLEMENTED;
2557 }
2558
GenerateRootFile(const Parser & parser,const std::string & path)2559 Status GenerateRootFile(const Parser &parser,
2560 const std::string &path) override {
2561 (void)parser;
2562 (void)path;
2563 return Status::NOT_IMPLEMENTED;
2564 }
2565
IsSchemaOnly() const2566 bool IsSchemaOnly() const override { return true; }
2567
SupportsBfbsGeneration() const2568 bool SupportsBfbsGeneration() const override { return false; }
2569
SupportsRootFileGeneration() const2570 bool SupportsRootFileGeneration() const override { return false; }
2571
Language() const2572 IDLOptions::Language Language() const override { return IDLOptions::kCSharp; }
2573
LanguageName() const2574 std::string LanguageName() const override { return "CSharp"; }
2575 };
2576 } // namespace
2577
NewCSharpCodeGenerator()2578 std::unique_ptr<CodeGenerator> NewCSharpCodeGenerator() {
2579 return std::unique_ptr<CSharpCodeGenerator>(new CSharpCodeGenerator());
2580 }
2581
2582 } // namespace flatbuffers
2583