2 * Copyright 2014 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // independent from idl_parser, since this code is not needed for most clients
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
24 #if defined(FLATBUFFERS_CPP98_STL)
26 #endif // defined(FLATBUFFERS_CPP98_STL)
28 namespace flatbuffers {
30 static TypedFloatConstantGenerator CSharpFloatGen("Double.", "Single.", "NaN",
33 static CommentConfig comment_config = {
40 class CSharpGenerator : public BaseGenerator {
41 struct FieldArrayLength {
47 CSharpGenerator(const Parser &parser, const std::string &path,
48 const std::string &file_name)
49 : BaseGenerator(parser, path, file_name, "", ".", "cs"),
50 cur_name_space_(nullptr) {}
52 CSharpGenerator &operator=(const CSharpGenerator &);
55 std::string one_file_code;
56 cur_name_space_ = parser_.current_namespace_;
58 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
61 auto &enum_def = **it;
62 if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
63 GenEnum(enum_def, &enumcode, parser_.opts);
64 if (parser_.opts.one_file) {
65 one_file_code += enumcode;
67 if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
73 for (auto it = parser_.structs_.vec.begin();
74 it != parser_.structs_.vec.end(); ++it) {
76 auto &struct_def = **it;
77 if (!parser_.opts.one_file)
78 cur_name_space_ = struct_def.defined_namespace;
79 GenStruct(struct_def, &declcode, parser_.opts);
80 if (parser_.opts.one_file) {
81 one_file_code += declcode;
83 if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
89 if (parser_.opts.one_file) {
90 return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
96 // Save out the generated code for a single class while adding
97 // declaration boilerplate.
98 bool SaveType(const std::string &defname, const Namespace &ns,
99 const std::string &classcode, bool needs_includes) const {
100 if (!classcode.length()) return true;
103 "// <auto-generated>\n"
105 std::string(FlatBuffersGeneratedWarning()) +
107 "// </auto-generated>\n\n";
109 std::string namespace_name = FullNamespace(".", ns);
110 if (!namespace_name.empty()) {
111 code += "namespace " + namespace_name + "\n{\n\n";
113 if (needs_includes) {
114 code += "using global::System;\n";
115 code += "using global::System.Collections.Generic;\n";
116 code += "using global::FlatBuffers;\n\n";
119 if (!namespace_name.empty()) { code += "\n}\n"; }
120 auto filename = NamespaceDir(ns) + defname + ".cs";
121 return SaveFile(filename.c_str(), code, false);
124 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
126 std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
128 static const char * const csharp_typename[] = {
129 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, ...) \
131 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
132 #undef FLATBUFFERS_TD
136 if (enableLangOverrides) {
137 if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
138 if (type.base_type == BASE_TYPE_STRUCT) {
139 return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
143 return csharp_typename[type.base_type];
146 inline std::string GenTypeBasic(const Type &type) const {
147 return GenTypeBasic(type, true);
150 std::string GenTypePointer(const Type &type) const {
151 switch (type.base_type) {
152 case BASE_TYPE_STRING: return "string";
153 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
154 case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
155 case BASE_TYPE_UNION: return "TTable";
156 default: return "Table";
160 std::string GenTypeGet(const Type &type) const {
161 return IsScalar(type.base_type)
163 : (IsArray(type) ? GenTypeGet(type.VectorType())
164 : GenTypePointer(type));
167 std::string GenOffsetType(const StructDef &struct_def) const {
168 return "Offset<" + WrapInNameSpace(struct_def) + ">";
171 std::string GenOffsetConstruct(const StructDef &struct_def,
172 const std::string &variable_name) const {
173 return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name +
177 // Casts necessary to correctly read serialized data
178 std::string DestinationCast(const Type &type) const {
179 if (IsSeries(type)) {
180 return DestinationCast(type.VectorType());
182 if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
187 // Cast statements for mutator method parameters.
188 // In Java, parameters representing unsigned numbers need to be cast down to
189 // their respective type. For example, a long holding an unsigned int value
190 // would be cast down to int before being put onto the buffer. In C#, one cast
191 // directly cast an Enum to its underlying type, which is essential before
192 // putting it onto the buffer.
193 std::string SourceCast(const Type &type) const {
194 if (IsSeries(type)) {
195 return SourceCast(type.VectorType());
197 if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
202 std::string SourceCastBasic(const Type &type) const {
203 return IsScalar(type.base_type) ? SourceCast(type) : "";
206 std::string GenEnumDefaultValue(const FieldDef &field) const {
207 auto &value = field.value;
208 FLATBUFFERS_ASSERT(value.type.enum_def);
209 auto &enum_def = *value.type.enum_def;
210 auto enum_val = enum_def.FindByValue(value.constant);
211 return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
215 std::string GenDefaultValue(const FieldDef &field,
216 bool enableLangOverrides) const {
217 auto &value = field.value;
218 if (enableLangOverrides) {
219 // handles both enum case and vector of enum case
220 if (value.type.enum_def != nullptr &&
221 value.type.base_type != BASE_TYPE_UNION) {
222 return GenEnumDefaultValue(field);
226 auto longSuffix = "";
227 switch (value.type.base_type) {
228 case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
229 case BASE_TYPE_ULONG: return value.constant;
231 case BASE_TYPE_LONG: return value.constant + longSuffix;
233 if (IsFloat(value.type.base_type))
234 return CSharpFloatGen.GenFloatConstant(field);
236 return value.constant;
240 std::string GenDefaultValue(const FieldDef &field) const {
241 return GenDefaultValue(field, true);
244 std::string GenDefaultValueBasic(const FieldDef &field,
245 bool enableLangOverrides) const {
246 auto &value = field.value;
247 if (!IsScalar(value.type.base_type)) {
248 if (enableLangOverrides) {
249 switch (value.type.base_type) {
250 case BASE_TYPE_STRING: return "default(StringOffset)";
251 case BASE_TYPE_STRUCT:
252 return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) +
254 case BASE_TYPE_VECTOR: return "default(VectorOffset)";
260 return GenDefaultValue(field, enableLangOverrides);
263 std::string GenDefaultValueBasic(const FieldDef &field) const {
264 return GenDefaultValueBasic(field, true);
267 void GenEnum(EnumDef &enum_def, std::string *code_ptr,
268 const IDLOptions &opts) const {
269 std::string &code = *code_ptr;
270 if (enum_def.generated) return;
272 // Generate enum definitions of the form:
273 // public static (final) int name = value;
274 // In Java, we use ints rather than the Enum feature, because we want them
275 // to map directly to how they're used in C/C++ and file formats.
276 // That, and Java Enums are expensive, and not universally liked.
277 GenComment(enum_def.doc_comment, code_ptr, &comment_config);
279 if (opts.cs_gen_json_serializer && opts.generate_object_based_api) {
281 "[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters."
282 "StringEnumConverter))]\n";
284 // In C# this indicates enumeration values can be treated as bit flags.
285 if (enum_def.attributes.Lookup("bit_flags")) {
286 code += "[System.FlagsAttribute]\n";
288 if (enum_def.attributes.Lookup("private")) {
293 code += "enum " + enum_def.name;
294 code += " : " + GenTypeBasic(enum_def.underlying_type, false);
296 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
298 GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
300 code += ev.name + " = ";
301 code += enum_def.ToString(ev);
307 if (opts.generate_object_based_api) {
308 GenEnum_ObjectAPI(enum_def, code_ptr, opts);
312 bool HasUnionStringValue(const EnumDef &enum_def) const {
313 if (!enum_def.is_union) return false;
314 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
316 if (IsString(val.union_type)) { return true; }
321 // Returns the function name that is able to read a value of the given type.
322 std::string GenGetter(const Type &type) const {
323 switch (type.base_type) {
324 case BASE_TYPE_STRING: return "__p.__string";
325 case BASE_TYPE_STRUCT: return "__p.__struct";
326 case BASE_TYPE_UNION: return "__p.__union";
327 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
328 case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
330 std::string getter = "__p.bb.Get";
331 if (type.base_type == BASE_TYPE_BOOL) {
332 getter = "0!=" + getter;
333 } else if (GenTypeBasic(type, false) != "byte") {
334 getter += MakeCamel(GenTypeBasic(type, false));
341 // Returns the function name that is able to read a value of the given type.
342 std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
343 const std::string &data_buffer,
344 const char *num = nullptr) const {
345 auto type = key_field->value.type;
347 auto dest_cast = DestinationCast(type);
348 auto getter = data_buffer + ".Get";
349 if (GenTypeBasic(type, false) != "byte") {
350 getter += MakeCamel(GenTypeBasic(type, false));
352 getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
357 // Direct mutation is only allowed for scalar fields.
358 // Hence a setter method will only be generated for such fields.
359 std::string GenSetter(const Type &type) const {
360 if (IsScalar(type.base_type)) {
361 std::string setter = "__p.bb.Put";
362 if (GenTypeBasic(type, false) != "byte" &&
363 type.base_type != BASE_TYPE_BOOL) {
364 setter += MakeCamel(GenTypeBasic(type, false));
372 // Returns the method name for use with add/put calls.
373 std::string GenMethod(const Type &type) const {
374 return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
375 : (IsStruct(type) ? "Struct" : "Offset");
378 // Recursively generate arguments for a constructor, to deal with nested
380 void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
381 const char *nameprefix, size_t array_count = 0) const {
382 std::string &code = *code_ptr;
383 for (auto it = struct_def.fields.vec.begin();
384 it != struct_def.fields.vec.end(); ++it) {
386 const auto &field_type = field.value.type;
387 const auto array_field = IsArray(field_type);
388 const auto &type = array_field ? field_type.VectorType() : field_type;
389 const auto array_cnt = array_field ? (array_count + 1) : array_count;
390 if (IsStruct(type)) {
391 // Generate arguments for a struct inside a struct. To ensure names
392 // don't clash, and to make it obvious these arguments are constructing
393 // a nested struct, prefix the name with the field name.
394 GenStructArgs(*field_type.struct_def, code_ptr,
395 (nameprefix + (field.name + "_")).c_str(), array_cnt);
398 code += GenTypeBasic(type);
401 for (size_t i = 1; i < array_cnt; i++) code += ",";
406 code += MakeCamel(field.name, true);
411 // Recusively generate struct construction statements of the form:
412 // builder.putType(name);
413 // and insert manual padding.
414 void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
415 const char *nameprefix, size_t index = 0,
416 bool in_array = false) const {
417 std::string &code = *code_ptr;
418 std::string indent((index + 1) * 2, ' ');
419 code += indent + " builder.Prep(";
420 code += NumToString(struct_def.minalign) + ", ";
421 code += NumToString(struct_def.bytesize) + ");\n";
422 for (auto it = struct_def.fields.vec.rbegin();
423 it != struct_def.fields.vec.rend(); ++it) {
425 const auto &field_type = field.value.type;
427 code += indent + " builder.Pad(";
428 code += NumToString(field.padding) + ");\n";
430 if (IsStruct(field_type)) {
431 GenStructBody(*field_type.struct_def, code_ptr,
432 (nameprefix + (field.name + "_")).c_str(), index,
436 IsArray(field_type) ? field_type.VectorType() : field_type;
437 const auto index_var = "_idx" + NumToString(index);
438 if (IsArray(field_type)) {
439 code += indent + " for (int " + index_var + " = ";
440 code += NumToString(field_type.fixed_length);
441 code += "; " + index_var + " > 0; " + index_var + "--) {\n";
444 if (IsStruct(type)) {
445 GenStructBody(*field_type.struct_def, code_ptr,
446 (nameprefix + (field.name + "_")).c_str(), index + 1,
449 code += IsArray(field_type) ? " " : "";
450 code += indent + " builder.Put";
451 code += GenMethod(type) + "(";
452 code += SourceCast(type);
453 auto argname = nameprefix + MakeCamel(field.name, true);
455 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
458 for (size_t i = 0; in_array && i < array_cnt; i++) {
459 code += "_idx" + NumToString(i) + "-1";
460 if (i != (array_cnt - 1)) code += ",";
466 if (IsArray(field_type)) { code += indent + " }\n"; }
470 std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
471 const char *num = nullptr) const {
472 std::string key_offset =
473 "Table.__offset(" + NumToString(key_field->value.offset) + ", ";
476 key_offset += ".Value, builder.DataBuffer)";
478 key_offset += "bb.Length";
479 key_offset += " - tableOffset, bb)";
484 std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
485 std::string key_getter = " ";
486 key_getter += "int tableOffset = Table.";
487 key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
488 key_getter += ", bb);\n ";
489 if (IsString(key_field->value.type)) {
490 key_getter += "int comp = Table.";
491 key_getter += "CompareStrings(";
492 key_getter += GenOffsetGetter(key_field);
493 key_getter += ", byteKey, bb);\n";
495 auto get_val = GenGetterForLookupByKey(key_field, "bb");
496 key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
501 std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
502 std::string key_getter = "";
503 auto data_buffer = "builder.DataBuffer";
504 if (IsString(key_field->value.type)) {
505 key_getter += "Table.CompareStrings(";
506 key_getter += GenOffsetGetter(key_field, "o1") + ", ";
507 key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
509 auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
510 key_getter += field_getter;
511 field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
512 key_getter += ".CompareTo(" + field_getter + ")";
517 void GenStruct(StructDef &struct_def, std::string *code_ptr,
518 const IDLOptions &opts) const {
519 if (struct_def.generated) return;
520 std::string &code = *code_ptr;
522 // Generate a struct accessor class, with methods of the form:
523 // public type name() { return bb.getType(i + offset); }
524 // or for tables of the form:
525 // public type name() {
526 // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
528 GenComment(struct_def.doc_comment, code_ptr, &comment_config);
529 if (struct_def.attributes.Lookup("private")) {
534 if (struct_def.attributes.Lookup("csharp_partial")) {
535 // generate a partial class for this C# struct/table
538 code += "struct " + struct_def.name;
539 code += " : IFlatbufferObject";
542 code += struct_def.fixed ? "Struct" : "Table";
545 code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
547 if (!struct_def.fixed) {
548 // Generate verson check method.
549 // Force compile time error if not using the same version runtime.
550 code += " public static void ValidateVersion() {";
551 code += " FlatBufferConstants.";
552 code += "FLATBUFFERS_1_12_0(); ";
555 // Generate a special accessor for the table that when used as the root
557 std::string method_name = "GetRootAs" + struct_def.name;
558 std::string method_signature =
559 " public static " + struct_def.name + " " + method_name;
561 // create convenience method that doesn't require an existing object
562 code += method_signature + "(ByteBuffer _bb) ";
563 code += "{ return " + method_name + "(_bb, new " + struct_def.name +
566 // create method that allows object reuse
568 method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
569 code += "return (obj.__assign(_bb.GetInt(_bb.Position";
570 code += ") + _bb.Position";
571 code += ", _bb)); }\n";
572 if (parser_.root_struct_def_ == &struct_def) {
573 if (parser_.file_identifier_.length()) {
574 // Check if a buffer has the identifier.
575 code += " public static ";
576 code += "bool " + struct_def.name;
577 code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
578 code += "Table.__has_identifier(_bb, \"";
579 code += parser_.file_identifier_;
584 // Generate the __init method that sets the field in a pre-existing
585 // accessor object. This is to allow object reuse.
586 code += " public void __init(int _i, ByteBuffer _bb) ";
588 code += "__p = new ";
589 code += struct_def.fixed ? "Struct" : "Table";
590 code += "(_i, _bb); ";
593 " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
594 code += "{ __init(_i, _bb); return this; }\n\n";
595 for (auto it = struct_def.fields.vec.begin();
596 it != struct_def.fields.vec.end(); ++it) {
598 if (field.deprecated) continue;
599 GenComment(field.doc_comment, code_ptr, &comment_config, " ");
600 std::string type_name = GenTypeGet(field.value.type);
601 std::string type_name_dest = GenTypeGet(field.value.type);
602 std::string conditional_cast = "";
603 std::string optional = "";
604 if (!struct_def.fixed &&
605 (field.value.type.base_type == BASE_TYPE_STRUCT ||
606 field.value.type.base_type == BASE_TYPE_UNION ||
607 (IsVector(field.value.type) &&
608 (field.value.type.element == BASE_TYPE_STRUCT ||
609 field.value.type.element == BASE_TYPE_UNION)))) {
611 conditional_cast = "(" + type_name_dest + optional + ")";
613 std::string dest_mask = "";
614 std::string dest_cast = DestinationCast(field.value.type);
615 std::string src_cast = SourceCast(field.value.type);
616 std::string method_start = " public " + type_name_dest + optional + " " +
617 MakeCamel(field.name, true);
618 std::string obj = "(new " + type_name + "())";
620 // Most field accessors need to retrieve and test the field offset first,
621 // this is the prefix code for that:
623 IsArray(field.value.type)
625 : (" { int o = __p.__offset(" + NumToString(field.value.offset) +
626 "); return o != 0 ? ");
627 // Generate the accessors that don't do object reuse.
628 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
629 } else if (IsVector(field.value.type) &&
630 field.value.type.element == BASE_TYPE_STRUCT) {
631 } else if (field.value.type.base_type == BASE_TYPE_UNION ||
632 (IsVector(field.value.type) &&
633 field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
634 method_start += "<TTable>";
635 type_name = type_name_dest;
637 std::string getter = dest_cast + GenGetter(field.value.type);
638 code += method_start;
639 std::string default_cast = "";
640 // only create default casts for c# scalars or vectors of scalars
641 if ((IsScalar(field.value.type.base_type) ||
642 (IsVector(field.value.type) &&
643 IsScalar(field.value.type.element)))) {
644 // For scalars, default value will be returned by GetDefaultValue().
645 // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
646 // that doesn't need to be casted. However, default values for enum
647 // elements of vectors are integer literals ("0") and are still casted
649 if (field.value.type.enum_def == nullptr ||
650 IsVector(field.value.type)) {
651 default_cast = "(" + type_name_dest + ")";
654 std::string member_suffix = "; ";
655 if (IsScalar(field.value.type.base_type)) {
657 member_suffix += "} ";
658 if (struct_def.fixed) {
659 code += " { return " + getter;
660 code += "(__p.bb_pos + ";
661 code += NumToString(field.value.offset) + ")";
664 code += offset_prefix + getter;
665 code += "(o + __p.bb_pos)" + dest_mask;
666 code += " : " + default_cast;
667 code += GenDefaultValue(field);
670 switch (field.value.type.base_type) {
671 case BASE_TYPE_STRUCT:
673 member_suffix += "} ";
674 if (struct_def.fixed) {
675 code += " { return " + obj + ".__assign(" + "__p.";
676 code += "bb_pos + " + NumToString(field.value.offset) + ", ";
679 code += offset_prefix + conditional_cast;
680 code += obj + ".__assign(";
681 code += field.value.type.struct_def->fixed
683 : "__p.__indirect(o + __p.bb_pos)";
684 code += ", __p.bb) : null";
687 case BASE_TYPE_STRING:
689 member_suffix += "} ";
690 code += offset_prefix + getter + "(o + " + "__p.";
691 code += "bb_pos) : null";
693 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
694 case BASE_TYPE_VECTOR: {
695 auto vectortype = field.value.type.VectorType();
696 if (vectortype.base_type == BASE_TYPE_UNION) {
697 conditional_cast = "(TTable?)";
698 getter += "<TTable>";
701 if (vectortype.base_type == BASE_TYPE_STRUCT) {
702 getter = obj + ".__assign";
703 } else if (vectortype.base_type == BASE_TYPE_UNION) {
706 const auto body = offset_prefix + conditional_cast + getter + "(";
707 if (vectortype.base_type == BASE_TYPE_UNION) {
708 code += " where TTable : struct, IFlatbufferObject" + body;
712 std::string index = "__p.";
713 if (IsArray(field.value.type)) {
714 index += "bb_pos + " + NumToString(field.value.offset) + " + ";
716 index += "__vector(o) + ";
718 index += "j * " + NumToString(InlineSize(vectortype));
719 if (vectortype.base_type == BASE_TYPE_STRUCT) {
720 code += vectortype.struct_def->fixed
722 : "__p.__indirect(" + index + ")";
727 code += ")" + dest_mask;
728 if (!IsArray(field.value.type)) {
731 field.value.type.element == BASE_TYPE_BOOL
733 : (IsScalar(field.value.type.element) ? default_cast + "0"
736 if (vectortype.base_type == BASE_TYPE_UNION &&
737 HasUnionStringValue(*vectortype.enum_def)) {
738 code += member_suffix;
740 code += " public string " + MakeCamel(field.name, true) +
742 code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
743 code += "(" + index + ") : null";
747 case BASE_TYPE_UNION:
748 code += "() where TTable : struct, IFlatbufferObject";
749 code += offset_prefix + "(TTable?)" + getter;
750 code += "<TTable>(o + __p.bb_pos) : null";
751 if (HasUnionStringValue(*field.value.type.enum_def)) {
752 code += member_suffix;
754 code += " public string " + MakeCamel(field.name, true) +
756 code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING));
757 code += "(o + __p.bb_pos) : null";
760 default: FLATBUFFERS_ASSERT(0);
763 code += member_suffix;
765 if (IsVector(field.value.type)) {
766 code += " public int " + MakeCamel(field.name, true);
769 code += offset_prefix;
770 code += "__p.__vector_len(o) : 0; ";
773 // See if we should generate a by-key accessor.
774 if (field.value.type.element == BASE_TYPE_STRUCT &&
775 !field.value.type.struct_def->fixed) {
776 auto &sd = *field.value.type.struct_def;
777 auto &fields = sd.fields.vec;
778 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
779 auto &key_field = **kit;
781 auto qualified_name = WrapInNameSpace(sd);
782 code += " public " + qualified_name + "? ";
783 code += MakeCamel(field.name, true) + "ByKey(";
784 code += GenTypeGet(key_field.value.type) + " key)";
785 code += offset_prefix;
786 code += qualified_name + ".__lookup_by_key(";
787 code += "__p.__vector(o), key, ";
788 code += "__p.bb) : null; ";
795 // Generate a ByteBuffer accessor for strings & vectors of scalars.
796 if ((IsVector(field.value.type) &&
797 IsScalar(field.value.type.VectorType().base_type)) ||
798 IsString(field.value.type)) {
799 code += "#if ENABLE_SPAN_T\n";
800 code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
802 code += MakeCamel(field.name, true);
803 code += "Bytes() { return ";
804 code += "__p.__vector_as_span<" +
805 GenTypeBasic(field.value.type.VectorType()) + ">(";
806 code += NumToString(field.value.offset);
808 ", " + NumToString(SizeOf(field.value.type.VectorType().base_type));
811 code += " public ArraySegment<byte>? Get";
812 code += MakeCamel(field.name, true);
813 code += "Bytes() { return ";
814 code += "__p.__vector_as_arraysegment(";
815 code += NumToString(field.value.offset);
819 // For direct blockcopying the data into a typed array
821 code += GenTypeBasic(field.value.type.VectorType());
823 code += MakeCamel(field.name, true);
824 code += "Array() { ";
825 if (IsEnum(field.value.type.VectorType())) {
826 // Since __vector_as_array does not work for enum types,
827 // fill array using an explicit loop.
828 code += "int o = __p.__offset(";
829 code += NumToString(field.value.offset);
830 code += "); if (o == 0) return null; int p = ";
831 code += "__p.__vector(o); int l = ";
832 code += "__p.__vector_len(o); ";
833 code += GenTypeBasic(field.value.type.VectorType());
834 code += "[] a = new ";
835 code += GenTypeBasic(field.value.type.VectorType());
836 code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter;
838 code += NumToString(InlineSize(field.value.type.VectorType()));
839 code += "); } return a;";
842 code += "__p.__vector_as_array<";
843 code += GenTypeBasic(field.value.type.VectorType());
845 code += NumToString(field.value.offset);
850 // generate object accessors if is nested_flatbuffer
851 if (field.nested_flatbuffer) {
852 auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
853 auto nested_method_name =
854 MakeCamel(field.name, true) + "As" + field.nested_flatbuffer->name;
855 auto get_nested_method_name = nested_method_name;
856 get_nested_method_name = "Get" + nested_method_name;
857 conditional_cast = "(" + nested_type_name + "?)";
858 obj = "(new " + nested_type_name + "())";
859 code += " public " + nested_type_name + "? ";
860 code += get_nested_method_name + "(";
861 code += ") { int o = __p.__offset(";
862 code += NumToString(field.value.offset) + "); ";
863 code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
865 code += "__indirect(__p.__vector(o)), ";
866 code += "__p.bb) : null; }\n";
868 // Generate mutators for scalar fields or vectors of scalars.
869 if (parser_.opts.mutable_buffer) {
870 auto is_series = (IsSeries(field.value.type));
871 const auto &underlying_type =
872 is_series ? field.value.type.VectorType() : field.value.type;
873 // Boolean parameters have to be explicitly converted to byte
875 auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
876 ? "(byte)(" + field.name + " ? 1 : 0)"
878 auto mutator_prefix = MakeCamel("mutate", true);
879 // A vector mutator also needs the index of the vector element it should
881 auto mutator_params = (is_series ? "(int j, " : "(") +
882 GenTypeGet(underlying_type) + " " + field.name +
887 (IsArray(field.value.type)
888 ? "bb_pos + " + NumToString(field.value.offset)
890 +" + j * " + NumToString(InlineSize(underlying_type))
892 ? "__p.bb_pos + " + NumToString(field.value.offset)
894 if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
896 code += struct_def.fixed ? "void " : "bool ";
897 code += mutator_prefix + MakeCamel(field.name, true);
898 code += mutator_params;
899 if (struct_def.fixed) {
900 code += GenSetter(underlying_type) + "(" + setter_index + ", ";
901 code += src_cast + setter_parameter + "); }\n";
903 code += "int o = __p.__offset(";
904 code += NumToString(field.value.offset) + ");";
905 code += " if (o != 0) { " + GenSetter(underlying_type);
906 code += "(" + setter_index + ", " + src_cast + setter_parameter +
907 "); return true; } else { return false; } }\n";
911 if (parser_.opts.java_primitive_has_method &&
912 IsScalar(field.value.type.base_type) && !struct_def.fixed) {
913 auto vt_offset_constant = " public static final int VT_" +
914 MakeScreamingCamel(field.name) + " = " +
915 NumToString(field.value.offset) + ";";
917 code += vt_offset_constant;
922 auto struct_has_create = false;
923 std::set<flatbuffers::FieldDef *> field_has_create_set;
924 flatbuffers::FieldDef *key_field = nullptr;
925 if (struct_def.fixed) {
926 struct_has_create = true;
927 // create a struct constructor function
928 code += " public static " + GenOffsetType(struct_def) + " ";
930 code += struct_def.name + "(FlatBufferBuilder builder";
931 GenStructArgs(struct_def, code_ptr, "");
933 GenStructBody(struct_def, code_ptr, "");
935 code += GenOffsetConstruct(struct_def, "builder.Offset");
938 // Generate a method that creates a table in one go. This is only possible
939 // when the table has no struct fields, since those have to be created
940 // inline, and there's no way to do so in Java.
941 bool has_no_struct_fields = true;
943 for (auto it = struct_def.fields.vec.begin();
944 it != struct_def.fields.vec.end(); ++it) {
946 if (field.deprecated) continue;
947 if (IsStruct(field.value.type)) {
948 has_no_struct_fields = false;
953 // JVM specifications restrict default constructor params to be < 255.
954 // Longs and doubles take up 2 units, so we set the limit to be < 127.
955 if ((has_no_struct_fields || opts.generate_object_based_api) &&
956 num_fields && num_fields < 127) {
957 struct_has_create = true;
958 // Generate a table constructor of the form:
959 // public static int createName(FlatBufferBuilder builder, args...)
960 code += " public static " + GenOffsetType(struct_def) + " ";
961 code += "Create" + struct_def.name;
962 code += "(FlatBufferBuilder builder";
963 for (auto it = struct_def.fields.vec.begin();
964 it != struct_def.fields.vec.end(); ++it) {
966 if (field.deprecated) continue;
968 if (IsStruct(field.value.type) && opts.generate_object_based_api) {
969 code += WrapInNameSpace(
970 field.value.type.struct_def->defined_namespace,
971 GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts));
976 code += GenTypeBasic(field.value.type);
979 if (!IsScalar(field.value.type.base_type)) code += "Offset";
982 code += GenDefaultValueBasic(field);
985 code += ") {\n builder.";
986 code += "StartTable(";
987 code += NumToString(struct_def.fields.vec.size()) + ");\n";
988 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
990 for (auto it = struct_def.fields.vec.rbegin();
991 it != struct_def.fields.vec.rend(); ++it) {
993 if (!field.deprecated &&
994 (!struct_def.sortbysize ||
995 size == SizeOf(field.value.type.base_type))) {
996 code += " " + struct_def.name + ".";
998 code += MakeCamel(field.name) + "(builder, ";
999 if (IsStruct(field.value.type) &&
1000 opts.generate_object_based_api) {
1001 code += GenTypePointer(field.value.type) + ".Pack(builder, " +
1005 if (!IsScalar(field.value.type.base_type)) code += "Offset";
1012 code += " return " + struct_def.name + ".";
1013 code += "End" + struct_def.name;
1014 code += "(builder);\n }\n\n";
1016 // Generate a set of static methods that allow table construction,
1018 // public static void addName(FlatBufferBuilder builder, short name)
1019 // { builder.addShort(id, name, default); }
1020 // Unlike the Create function, these always work.
1021 code += " public static void Start";
1022 code += struct_def.name;
1023 code += "(FlatBufferBuilder builder) { builder.";
1024 code += "StartTable(";
1025 code += NumToString(struct_def.fields.vec.size()) + "); }\n";
1026 for (auto it = struct_def.fields.vec.begin();
1027 it != struct_def.fields.vec.end(); ++it) {
1029 if (field.deprecated) continue;
1030 if (field.key) key_field = &field;
1031 code += " public static void Add";
1032 code += MakeCamel(field.name);
1033 code += "(FlatBufferBuilder builder, ";
1034 code += GenTypeBasic(field.value.type);
1035 auto argname = MakeCamel(field.name, false);
1036 if (!IsScalar(field.value.type.base_type)) argname += "Offset";
1037 code += " " + argname + ") { builder.Add";
1038 code += GenMethod(field.value.type) + "(";
1039 code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
1040 code += SourceCastBasic(field.value.type);
1042 if (!IsScalar(field.value.type.base_type) &&
1043 field.value.type.base_type != BASE_TYPE_UNION) {
1047 code += GenDefaultValue(field, false);
1049 if (IsVector(field.value.type)) {
1050 auto vector_type = field.value.type.VectorType();
1051 auto alignment = InlineAlignment(vector_type);
1052 auto elem_size = InlineSize(vector_type);
1053 if (!IsStruct(vector_type)) {
1054 field_has_create_set.insert(&field);
1055 code += " public static VectorOffset ";
1057 code += MakeCamel(field.name);
1058 code += "Vector(FlatBufferBuilder builder, ";
1059 code += GenTypeBasic(vector_type) + "[] data) ";
1060 code += "{ builder.StartVector(";
1061 code += NumToString(elem_size);
1062 code += ", data.Length, ";
1063 code += NumToString(alignment);
1064 code += "); for (int i = data.";
1065 code += "Length - 1; i >= 0; i--) builder.";
1067 code += GenMethod(vector_type);
1069 code += SourceCastBasic(vector_type);
1071 if (vector_type.base_type == BASE_TYPE_STRUCT ||
1072 IsString(vector_type))
1074 code += "); return ";
1075 code += "builder.EndVector(); }\n";
1077 code += " public static VectorOffset ";
1079 code += MakeCamel(field.name);
1080 code += "VectorBlock(FlatBufferBuilder builder, ";
1081 code += GenTypeBasic(vector_type) + "[] data) ";
1082 code += "{ builder.StartVector(";
1083 code += NumToString(elem_size);
1084 code += ", data.Length, ";
1085 code += NumToString(alignment);
1086 code += "); builder.Add(data); return builder.EndVector(); }\n";
1088 // Generate a method to start a vector, data to be added manually
1090 code += " public static void Start";
1091 code += MakeCamel(field.name);
1092 code += "Vector(FlatBufferBuilder builder, int numElems) ";
1093 code += "{ builder.StartVector(";
1094 code += NumToString(elem_size);
1095 code += ", numElems, " + NumToString(alignment);
1099 code += " public static " + GenOffsetType(struct_def) + " ";
1100 code += "End" + struct_def.name;
1101 code += "(FlatBufferBuilder builder) {\n int o = builder.";
1102 code += "EndTable();\n";
1103 for (auto it = struct_def.fields.vec.begin();
1104 it != struct_def.fields.vec.end(); ++it) {
1106 if (!field.deprecated && field.required) {
1107 code += " builder.Required(o, ";
1108 code += NumToString(field.value.offset);
1109 code += "); // " + field.name + "\n";
1112 code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
1113 if (parser_.root_struct_def_ == &struct_def) {
1114 std::string size_prefix[] = { "", "SizePrefixed" };
1115 for (int i = 0; i < 2; ++i) {
1116 code += " public static void ";
1117 code += "Finish" + size_prefix[i] + struct_def.name;
1119 "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def);
1120 code += " offset) {";
1121 code += " builder.Finish" + size_prefix[i] + "(offset";
1124 if (parser_.file_identifier_.length())
1125 code += ", \"" + parser_.file_identifier_ + "\"";
1130 // Only generate key compare function for table,
1131 // because `key_field` is not set for struct
1132 if (struct_def.has_key && !struct_def.fixed) {
1133 FLATBUFFERS_ASSERT(key_field);
1134 code += "\n public static VectorOffset ";
1135 code += "CreateSortedVectorOf" + struct_def.name;
1136 code += "(FlatBufferBuilder builder, ";
1137 code += "Offset<" + struct_def.name + ">";
1138 code += "[] offsets) {\n";
1139 code += " Array.Sort(offsets, (Offset<" + struct_def.name +
1140 "> o1, Offset<" + struct_def.name + "> o2) => " +
1141 GenKeyGetter(key_field);
1143 code += " return builder.CreateVectorOfTables(offsets);\n }\n";
1145 code += "\n public static " + struct_def.name + "?";
1146 code += " __lookup_by_key(";
1147 code += "int vectorLocation, ";
1148 code += GenTypeGet(key_field->value.type);
1149 code += " key, ByteBuffer bb) {\n";
1150 if (IsString(key_field->value.type)) {
1151 code += " byte[] byteKey = ";
1152 code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
1154 code += " int span = ";
1155 code += "bb.GetInt(vectorLocation - 4);\n";
1156 code += " int start = 0;\n";
1157 code += " while (span != 0) {\n";
1158 code += " int middle = span / 2;\n";
1159 code += GenLookupKeyGetter(key_field);
1160 code += " if (comp > 0) {\n";
1161 code += " span = middle;\n";
1162 code += " } else if (comp < 0) {\n";
1163 code += " middle++;\n";
1164 code += " start += middle;\n";
1165 code += " span -= middle;\n";
1166 code += " } else {\n";
1168 code += "new " + struct_def.name + "()";
1169 code += ".__assign(tableOffset, bb);\n";
1171 code += " return null;\n";
1175 if (opts.generate_object_based_api) {
1176 GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create,
1177 field_has_create_set);
1181 if (opts.generate_object_based_api) {
1182 GenStruct_ObjectAPI(struct_def, code_ptr, opts);
1186 void GenVectorAccessObject(StructDef &struct_def,
1187 std::string *code_ptr) const {
1188 auto &code = *code_ptr;
1189 // Generate a vector of structs accessor class.
1192 if (!struct_def.attributes.Lookup("private")) code += "public ";
1193 code += "static struct Vector : BaseVector\n{\n";
1195 // Generate the __assign method that sets the field in a pre-existing
1196 // accessor object. This is to allow object reuse.
1197 std::string method_indent = " ";
1198 code += method_indent + "public Vector ";
1199 code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1200 code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1202 auto type_name = struct_def.name;
1203 auto method_start = method_indent + "public " + type_name + " Get";
1204 // Generate the accessors that don't do object reuse.
1205 code += method_start + "(int j) { return Get";
1206 code += "(new " + type_name + "(), j); }\n";
1207 code += method_start + "(" + type_name + " obj, int j) { ";
1208 code += " return obj.__assign(";
1209 code += struct_def.fixed ? "__p.__element(j)"
1210 : "__p.__indirect(__p.__element(j), bb)";
1211 code += ", __p.bb); }\n";
1212 // See if we should generate a by-key accessor.
1213 if (!struct_def.fixed) {
1214 auto &fields = struct_def.fields.vec;
1215 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1216 auto &key_field = **kit;
1217 if (key_field.key) {
1218 auto nullable_annotation =
1219 parser_.opts.gen_nullable ? "@Nullable " : "";
1220 code += method_indent + nullable_annotation;
1221 code += "public " + type_name + "? ";
1222 code += "GetByKey(";
1223 code += GenTypeGet(key_field.value.type) + " key) { ";
1224 code += " return __lookup_by_key(null, ";
1225 code += "__p.__vector(), key, ";
1226 code += "__p.bb); ";
1228 code += method_indent + nullable_annotation;
1229 code += "public " + type_name + "?" + " ";
1230 code += "GetByKey(";
1231 code += type_name + "? obj, ";
1232 code += GenTypeGet(key_field.value.type) + " key) { ";
1233 code += " return __lookup_by_key(obj, ";
1234 code += "__p.__vector(), key, ";
1235 code += "__p.bb); ";
1244 void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr,
1245 const IDLOptions &opts) const {
1246 auto &code = *code_ptr;
1247 if (enum_def.generated) return;
1248 if (!enum_def.is_union) return;
1249 if (enum_def.attributes.Lookup("private")) {
1250 code += "internal ";
1254 auto union_name = enum_def.name + "Union";
1255 code += "class " + union_name + " {\n";
1257 code += " public " + enum_def.name + " Type { get; set; }\n";
1259 code += " public object Value { get; set; }\n";
1262 code += " public " + union_name + "() {\n";
1263 code += " this.Type = " + enum_def.name + "." +
1264 enum_def.Vals()[0]->name + ";\n";
1265 code += " this.Value = null;\n";
1268 code += " public T As<T>() where T : class { return this.Value as T; }\n";
1270 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1272 if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
1273 auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
1274 if (ev.union_type.base_type == BASE_TYPE_STRUCT &&
1275 ev.union_type.struct_def->attributes.Lookup("private")) {
1276 code += " internal ";
1280 code += type_name + " As" + ev.name + "() { return this.As<" + type_name +
1285 code += " public static int Pack(FlatBuffers.FlatBufferBuilder builder, " +
1286 union_name + " _o) {\n";
1287 code += " switch (_o.Type) {\n";
1288 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1290 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1291 code += " default: return 0;\n";
1293 code += " case " + enum_def.name + "." + ev.name + ": return ";
1294 if (IsString(ev.union_type)) {
1295 code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n";
1297 code += GenTypeGet(ev.union_type) + ".Pack(builder, _o.As" + ev.name +
1306 if (opts.cs_gen_json_serializer) {
1307 if (enum_def.attributes.Lookup("private")) {
1308 code += "internal ";
1312 code += "class " + union_name +
1313 "_JsonConverter : Newtonsoft.Json.JsonConverter {\n";
1314 code += " public override bool CanConvert(System.Type objectType) {\n";
1315 code += " return objectType == typeof(" + union_name +
1316 ") || objectType == typeof(System.Collections.Generic.List<" +
1317 union_name + ">);\n";
1320 " public override void WriteJson(Newtonsoft.Json.JsonWriter writer, "
1322 "Newtonsoft.Json.JsonSerializer serializer) {\n";
1323 code += " var _olist = value as System.Collections.Generic.List<" +
1324 union_name + ">;\n";
1325 code += " if (_olist != null) {\n";
1326 code += " writer.WriteStartArray();\n";
1328 " foreach (var _o in _olist) { this.WriteJson(writer, _o, "
1330 code += " writer.WriteEndArray();\n";
1331 code += " } else {\n";
1332 code += " this.WriteJson(writer, value as " + union_name +
1336 code += " public void WriteJson(Newtonsoft.Json.JsonWriter writer, " +
1339 "Newtonsoft.Json.JsonSerializer serializer) {\n";
1340 code += " if (_o == null) return;\n";
1341 code += " serializer.Serialize(writer, _o.Value);\n";
1344 " public override object ReadJson(Newtonsoft.Json.JsonReader "
1346 "System.Type objectType, "
1347 "object existingValue, Newtonsoft.Json.JsonSerializer serializer) "
1350 " var _olist = existingValue as System.Collections.Generic.List<" +
1351 union_name + ">;\n";
1352 code += " if (_olist != null) {\n";
1353 code += " for (var _j = 0; _j < _olist.Count; ++_j) {\n";
1354 code += " reader.Read();\n";
1356 " _olist[_j] = this.ReadJson(reader, _olist[_j], "
1359 code += " reader.Read();\n";
1360 code += " return _olist;\n";
1361 code += " } else {\n";
1362 code += " return this.ReadJson(reader, existingValue as " +
1363 union_name + ", serializer);\n";
1366 code += " public " + union_name +
1367 " ReadJson(Newtonsoft.Json.JsonReader reader, " + union_name +
1368 " _o, Newtonsoft.Json.JsonSerializer serializer) {\n";
1369 code += " if (_o == null) return null;\n";
1370 code += " switch (_o.Type) {\n";
1371 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1374 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1375 code += " default: break;\n";
1377 auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts);
1378 code += " case " + enum_def.name + "." + ev.name +
1379 ": _o.Value = serializer.Deserialize<" + type_name +
1380 ">(reader); break;\n";
1384 code += " return _o;\n";
1390 std::string GenTypeName_ObjectAPI(const std::string &name,
1391 const IDLOptions &opts) const {
1392 return opts.object_prefix + name + opts.object_suffix;
1395 void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string *code_ptr,
1396 const std::string &camel_name,
1397 bool is_vector) const {
1398 auto &code = *code_ptr;
1399 std::string varialbe_name = "_o." + camel_name;
1400 std::string type_suffix = "";
1401 std::string func_suffix = "()";
1402 std::string indent = " ";
1404 varialbe_name = "_o_" + camel_name;
1405 type_suffix = "(_j)";
1406 func_suffix = "(_j)";
1410 code += indent + "var " + varialbe_name + " = new ";
1412 code += indent + varialbe_name + " = new ";
1414 code += WrapInNameSpace(enum_def) + "Union();\n";
1415 code += indent + varialbe_name + ".Type = this." + camel_name + "Type" +
1416 type_suffix + ";\n";
1418 indent + "switch (this." + camel_name + "Type" + type_suffix + ") {\n";
1419 for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end();
1422 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1423 code += indent + " default: break;\n";
1425 code += indent + " case " + WrapInNameSpace(enum_def) + "." + ev.name +
1427 code += indent + " " + varialbe_name + ".Value = this." + camel_name;
1428 if (IsString(ev.union_type)) {
1429 code += "AsString" + func_suffix + ";\n";
1431 code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix;
1432 code += ".HasValue ? this." + camel_name;
1433 code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix +
1434 ".Value.UnPack() : null;\n";
1436 code += indent + " break;\n";
1439 code += indent + "}\n";
1441 code += indent + "_o." + camel_name + ".Add(" + varialbe_name + ");\n";
1445 void GenPackUnPack_ObjectAPI(
1446 StructDef &struct_def, std::string *code_ptr, const IDLOptions &opts,
1447 bool struct_has_create,
1448 const std::set<FieldDef *> &field_has_create) const {
1449 auto &code = *code_ptr;
1450 auto struct_name = GenTypeName_ObjectAPI(struct_def.name, opts);
1452 code += " public " + struct_name + " UnPack() {\n";
1453 code += " var _o = new " + struct_name + "();\n";
1454 code += " this.UnPackTo(_o);\n";
1455 code += " return _o;\n";
1458 code += " public void UnPackTo(" + struct_name + " _o) {\n";
1459 for (auto it = struct_def.fields.vec.begin();
1460 it != struct_def.fields.vec.end(); ++it) {
1462 if (field.deprecated) continue;
1463 auto camel_name = MakeCamel(field.name);
1464 auto start = " _o." + camel_name + " = ";
1465 switch (field.value.type.base_type) {
1466 case BASE_TYPE_STRUCT: {
1467 auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
1469 code += start + "this." + camel_name + ".UnPack();\n";
1471 code += start + "this." + camel_name + ".HasValue ? this." +
1472 camel_name + ".Value.UnPack() : null;\n";
1476 case BASE_TYPE_ARRAY: {
1477 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
1478 auto length_str = NumToString(field.value.type.fixed_length);
1479 auto unpack_method = field.value.type.struct_def == nullptr
1481 : field.value.type.struct_def->fixed
1484 code += start + "new " + type_name.substr(0, type_name.length() - 1) +
1485 length_str + "];\n";
1486 code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." +
1487 camel_name + "[_j] = this." + camel_name + "(_j)" +
1488 unpack_method + "; }\n";
1491 case BASE_TYPE_VECTOR:
1492 if (field.value.type.element == BASE_TYPE_UNION) {
1493 code += start + "new " +
1494 GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
1495 code += " for (var _j = 0; _j < this." + camel_name +
1496 "Length; ++_j) {\n";
1497 GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
1500 } else if (field.value.type.element != BASE_TYPE_UTYPE) {
1501 auto fixed = field.value.type.struct_def == nullptr;
1502 code += start + "new " +
1503 GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n";
1504 code += " for (var _j = 0; _j < this." + camel_name +
1506 code += "_o." + camel_name + ".Add(";
1508 code += "this." + camel_name + "(_j)";
1510 code += "this." + camel_name + "(_j).HasValue ? this." +
1511 camel_name + "(_j).Value.UnPack() : null";
1516 case BASE_TYPE_UTYPE: break;
1517 case BASE_TYPE_UNION: {
1518 GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr,
1523 code += start + "this." + camel_name + ";\n";
1530 code += " public static " + GenOffsetType(struct_def) +
1531 " Pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
1532 code += " if (_o == null) return default(" + GenOffsetType(struct_def) +
1534 for (auto it = struct_def.fields.vec.begin();
1535 it != struct_def.fields.vec.end(); ++it) {
1537 if (field.deprecated) continue;
1538 auto camel_name = MakeCamel(field.name);
1540 switch (field.value.type.base_type) {
1541 case BASE_TYPE_STRUCT: {
1542 if (!field.value.type.struct_def->fixed) {
1543 code += " var _" + field.name + " = _o." + camel_name +
1544 " == null ? default(" +
1545 GenOffsetType(*field.value.type.struct_def) +
1546 ") : " + GenTypeGet(field.value.type) +
1547 ".Pack(builder, _o." + camel_name + ");\n";
1548 } else if (struct_def.fixed && struct_has_create) {
1549 std::vector<FieldArrayLength> array_lengths;
1550 FieldArrayLength tmp_array_length = {
1552 field.value.type.fixed_length,
1554 array_lengths.push_back(tmp_array_length);
1555 GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
1560 case BASE_TYPE_STRING: {
1561 std::string create_string =
1562 field.shared ? "CreateSharedString" : "CreateString";
1563 code += " var _" + field.name + " = _o." + camel_name +
1564 " == null ? default(StringOffset) : "
1566 create_string + "(_o." + camel_name + ");\n";
1569 case BASE_TYPE_VECTOR: {
1570 if (field_has_create.find(&field) != field_has_create.end()) {
1571 auto property_name = camel_name;
1572 auto gen_for_loop = true;
1573 std::string array_name = "__" + field.name;
1574 std::string array_type = "";
1575 std::string to_array = "";
1576 switch (field.value.type.element) {
1577 case BASE_TYPE_STRING: {
1578 std::string create_string =
1579 field.shared ? "CreateSharedString" : "CreateString";
1580 array_type = "StringOffset";
1581 to_array += "builder." + create_string + "(_o." +
1582 property_name + "[_j])";
1585 case BASE_TYPE_STRUCT:
1586 array_type = "Offset<" + GenTypeGet(field.value.type) + ">";
1587 to_array = GenTypeGet(field.value.type) + ".Pack(builder, _o." +
1588 property_name + "[_j])";
1590 case BASE_TYPE_UTYPE:
1591 property_name = camel_name.substr(0, camel_name.size() - 4);
1592 array_type = WrapInNameSpace(*field.value.type.enum_def);
1593 to_array = "_o." + property_name + "[_j].Type";
1595 case BASE_TYPE_UNION:
1597 to_array = WrapInNameSpace(*field.value.type.enum_def) +
1598 "Union.Pack(builder, _o." + property_name + "[_j])";
1600 default: gen_for_loop = false; break;
1602 code += " var _" + field.name + " = default(VectorOffset);\n";
1603 code += " if (_o." + property_name + " != null) {\n";
1605 code += " var " + array_name + " = new " + array_type +
1606 "[_o." + property_name + ".Count];\n";
1607 code += " for (var _j = 0; _j < " + array_name +
1608 ".Length; ++_j) { ";
1609 code += array_name + "[_j] = " + to_array + "; }\n";
1611 code += " var " + array_name + " = _o." + property_name +
1614 code += " _" + field.name + " = Create" + camel_name +
1615 "Vector(builder, " + array_name + ");\n";
1619 field.value.type.struct_def == nullptr
1620 ? "builder.Add" + GenMethod(field.value.type.VectorType()) +
1621 "(_o." + camel_name + "[_j]);"
1622 : GenTypeGet(field.value.type) + ".Pack(builder, _o." +
1623 camel_name + "[_j]);";
1624 code += " var _" + field.name + " = default(VectorOffset);\n";
1625 code += " if (_o." + camel_name + " != null) {\n";
1626 code += " Start" + camel_name + "Vector(builder, _o." +
1627 camel_name + ".Count);\n";
1628 code += " for (var _j = _o." + camel_name +
1629 ".Count - 1; _j >= 0; --_j) { " + pack_method + " }\n";
1630 code += " _" + field.name + " = builder.EndVector();\n";
1635 case BASE_TYPE_ARRAY: {
1636 if (field.value.type.struct_def != nullptr) {
1637 std::vector<FieldArrayLength> array_lengths;
1638 FieldArrayLength tmp_array_length = {
1640 field.value.type.fixed_length,
1642 array_lengths.push_back(tmp_array_length);
1643 GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
1646 code += " var _" + field.name + " = _o." + camel_name + ";\n";
1650 case BASE_TYPE_UNION: {
1651 code += " var _" + field.name + "_type = _o." + camel_name +
1652 " == null ? " + WrapInNameSpace(*field.value.type.enum_def) +
1653 ".NONE : " + "_o." + camel_name + ".Type;\n";
1655 " var _" + field.name + " = _o." + camel_name +
1656 " == null ? 0 : " + GenTypeGet_ObjectAPI(field.value.type, opts) +
1657 ".Pack(builder, _o." + camel_name + ");\n";
1663 if (struct_has_create) {
1665 code += " return Create" + struct_def.name + "(\n";
1667 for (auto it = struct_def.fields.vec.begin();
1668 it != struct_def.fields.vec.end(); ++it) {
1670 if (field.deprecated) continue;
1671 auto camel_name = MakeCamel(field.name);
1672 switch (field.value.type.base_type) {
1673 case BASE_TYPE_STRUCT: {
1674 if (struct_def.fixed) {
1675 GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
1677 " _" + field.name + "_");
1680 if (field.value.type.struct_def->fixed) {
1681 if (opts.generate_object_based_api)
1682 code += " _o." + camel_name;
1684 code += " " + GenTypeGet(field.value.type) +
1685 ".Pack(builder, _o." + camel_name + ")";
1687 code += " _" + field.name;
1692 case BASE_TYPE_ARRAY: {
1693 if (field.value.type.struct_def != nullptr) {
1694 GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
1696 " _" + field.name + "_");
1699 code += " _" + field.name;
1703 case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // fall thru
1704 case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH(); // fall thru
1705 case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
1706 case BASE_TYPE_VECTOR: {
1708 code += " _" + field.name;
1713 code += " _o." + camel_name;
1720 code += " Start" + struct_def.name + "(builder);\n";
1721 for (auto it = struct_def.fields.vec.begin();
1722 it != struct_def.fields.vec.end(); ++it) {
1724 if (field.deprecated) continue;
1725 auto camel_name = MakeCamel(field.name);
1726 switch (field.value.type.base_type) {
1727 case BASE_TYPE_STRUCT: {
1728 if (field.value.type.struct_def->fixed) {
1729 code += " Add" + camel_name + "(builder, " +
1730 GenTypeGet(field.value.type) + ".Pack(builder, _o." +
1731 camel_name + "));\n";
1734 " Add" + camel_name + "(builder, _" + field.name + ");\n";
1738 case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru
1739 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
1740 case BASE_TYPE_VECTOR: {
1742 " Add" + camel_name + "(builder, _" + field.name + ");\n";
1745 case BASE_TYPE_UTYPE: break;
1746 case BASE_TYPE_UNION: {
1747 code += " Add" + camel_name + "Type(builder, _" + field.name +
1750 " Add" + camel_name + "(builder, _" + field.name + ");\n";
1756 " Add" + camel_name + "(builder, _o." + camel_name + ");\n";
1761 code += " return End" + struct_def.name + "(builder);\n";
1766 void GenStructPackDecl_ObjectAPI(
1767 const StructDef &struct_def, std::string *code_ptr,
1768 std::vector<FieldArrayLength> &array_lengths) const {
1769 auto &code = *code_ptr;
1770 for (auto it = struct_def.fields.vec.begin();
1771 it != struct_def.fields.vec.end(); ++it) {
1773 auto is_array = IsArray(field.value.type);
1774 const auto &field_type =
1775 is_array ? field.value.type.VectorType() : field.value.type;
1776 FieldArrayLength tmp_array_length = {
1778 field_type.fixed_length,
1780 array_lengths.push_back(tmp_array_length);
1781 if (field_type.struct_def != nullptr) {
1782 GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr,
1785 std::vector<FieldArrayLength> array_only_lengths;
1786 for (size_t i = 0; i < array_lengths.size(); ++i) {
1787 if (array_lengths[i].length > 0) {
1788 array_only_lengths.push_back(array_lengths[i]);
1792 for (size_t i = 0; i < array_lengths.size(); ++i) {
1793 name += "_" + array_lengths[i].name;
1795 code += " var " + name + " = ";
1796 if (array_only_lengths.size() > 0) {
1797 code += "new " + GenTypeBasic(field_type) + "[";
1798 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1799 if (i != 0) { code += ","; }
1800 code += NumToString(array_only_lengths[i].length);
1805 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1806 auto idx = "idx" + NumToString(i);
1807 code += "for (var " + idx + " = 0; " + idx + " < " +
1808 NumToString(array_only_lengths[i].length) + "; ++" + idx +
1811 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1812 auto idx = "idx" + NumToString(i);
1814 code += name + "[" + idx;
1820 for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
1821 code += "." + MakeCamel(array_lengths[i].name);
1822 if (array_lengths[i].length <= 0) continue;
1823 code += "[idx" + NumToString(j++) + "]";
1826 for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1831 for (size_t i = 0; i < array_lengths.size(); ++i) {
1832 code += "." + MakeCamel(array_lengths[i].name);
1838 array_lengths.pop_back();
1842 void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
1843 std::string *code_ptr,
1844 std::string prefix) const {
1845 auto &code = *code_ptr;
1846 for (auto it = struct_def.fields.vec.begin();
1847 it != struct_def.fields.vec.end(); ++it) {
1849 const auto &field_type = field.value.type;
1850 if (field_type.struct_def != nullptr) {
1851 GenStructPackCall_ObjectAPI(*field_type.struct_def, code_ptr,
1852 prefix + field.name + "_");
1855 code += prefix + field.name;
1860 std::string GenTypeGet_ObjectAPI(flatbuffers::Type type,
1861 const IDLOptions &opts) const {
1862 auto type_name = GenTypeGet(type);
1863 // Replace to ObjectBaseAPI Type Name
1864 switch (type.base_type) {
1865 case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru
1866 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
1867 case BASE_TYPE_VECTOR: {
1868 if (type.struct_def != nullptr) {
1869 auto type_name_length = type.struct_def->name.length();
1870 auto new_type_name =
1871 GenTypeName_ObjectAPI(type.struct_def->name, opts);
1872 type_name.replace(type_name.length() - type_name_length,
1873 type_name_length, new_type_name);
1874 } else if (type.element == BASE_TYPE_UNION) {
1875 type_name = WrapInNameSpace(*type.enum_def) + "Union";
1880 case BASE_TYPE_UNION: {
1881 type_name = WrapInNameSpace(*type.enum_def) + "Union";
1887 switch (type.base_type) {
1888 case BASE_TYPE_ARRAY: {
1889 type_name = type_name + "[]";
1892 case BASE_TYPE_VECTOR: {
1893 type_name = "List<" + type_name + ">";
1901 void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr,
1902 const IDLOptions &opts) const {
1903 auto &code = *code_ptr;
1904 if (struct_def.attributes.Lookup("private")) {
1905 code += "internal ";
1909 if (struct_def.attributes.Lookup("csharp_partial")) {
1910 // generate a partial class for this C# struct/table
1913 auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts);
1914 code += "class " + class_name;
1916 // Generate Properties
1917 for (auto it = struct_def.fields.vec.begin();
1918 it != struct_def.fields.vec.end(); ++it) {
1920 if (field.deprecated) continue;
1921 if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
1922 if (field.value.type.element == BASE_TYPE_UTYPE) continue;
1923 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
1924 auto camel_name = MakeCamel(field.name, true);
1925 if (opts.cs_gen_json_serializer) {
1926 if (IsUnion(field.value.type)) {
1927 auto utype_name = WrapInNameSpace(*field.value.type.enum_def);
1929 " [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n";
1930 if (IsVector(field.value.type)) {
1931 code += " private " + utype_name + "[] " + camel_name + "Type {\n";
1933 code += " if (this." + camel_name + " == null) return null;\n";
1934 code += " var _o = new " + utype_name + "[this." + camel_name +
1937 " for (var _j = 0; _j < _o.Length; ++_j) { _o[_j] = "
1939 camel_name + "[_j].Type; }\n";
1940 code += " return _o;\n";
1943 code += " this." + camel_name + " = new List<" + utype_name +
1945 code += " for (var _j = 0; _j < value.Length; ++_j) {\n";
1946 code += " var _o = new " + utype_name + "Union();\n";
1947 code += " _o.Type = value[_j];\n";
1948 code += " this." + camel_name + ".Add(_o);\n";
1953 code += " private " + utype_name + " " + camel_name + "Type {\n";
1955 code += " return this." + camel_name + " != null ? this." +
1956 camel_name + ".Type : " + utype_name + ".NONE;\n";
1959 code += " this." + camel_name + " = new " + utype_name +
1961 code += " this." + camel_name + ".Type = value;\n";
1966 code += " [Newtonsoft.Json.JsonProperty(\"" + field.name + "\")]\n";
1967 if (IsUnion(field.value.type)) {
1969 (IsVector(field.value.type))
1970 ? GenTypeGet_ObjectAPI(field.value.type.VectorType(), opts)
1972 code += " [Newtonsoft.Json.JsonConverter(typeof(" + union_name +
1973 "_JsonConverter))]\n";
1975 if (field.attributes.Lookup("hash")) {
1976 code += " [Newtonsoft.Json.JsonIgnore()]\n";
1979 code += " public " + type_name + " " + camel_name + " { get; set; }\n";
1981 // Generate Constructor
1983 code += " public " + class_name + "() {\n";
1984 for (auto it = struct_def.fields.vec.begin();
1985 it != struct_def.fields.vec.end(); ++it) {
1987 if (field.deprecated) continue;
1988 if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
1989 if (field.value.type.element == BASE_TYPE_UTYPE) continue;
1990 code += " this." + MakeCamel(field.name) + " = ";
1991 auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
1992 if (IsScalar(field.value.type.base_type)) {
1993 code += GenDefaultValue(field) + ";\n";
1995 switch (field.value.type.base_type) {
1996 case BASE_TYPE_STRUCT: {
1997 if (IsStruct(field.value.type)) {
1998 code += "new " + type_name + "();\n";
2004 case BASE_TYPE_ARRAY: {
2005 code += "new " + type_name.substr(0, type_name.length() - 1) +
2006 NumToString(field.value.type.fixed_length) + "];\n";
2017 // Generate Serialization
2018 if (opts.cs_gen_json_serializer &&
2019 parser_.root_struct_def_ == &struct_def) {
2021 code += " public static " + class_name +
2022 " DeserializeFromJson(string jsonText) {\n";
2023 code += " return Newtonsoft.Json.JsonConvert.DeserializeObject<" +
2024 class_name + ">(jsonText);\n";
2026 code += " public string SerializeToJson() {\n";
2028 " return Newtonsoft.Json.JsonConvert.SerializeObject(this, "
2029 "Newtonsoft.Json.Formatting.Indented);\n";
2032 if (parser_.root_struct_def_ == &struct_def) {
2033 code += " public static " + class_name +
2034 " DeserializeFromBinary(byte[] fbBuffer) {\n";
2035 code += " return " + struct_def.name + ".GetRootAs" + struct_def.name +
2036 "(new ByteBuffer(fbBuffer)).UnPack();\n";
2038 code += " public byte[] SerializeToBinary() {\n";
2039 code += " var fbb = new FlatBufferBuilder(0x10000);\n";
2040 code += " " + struct_def.name + ".Finish" + struct_def.name +
2041 "Buffer(fbb, " + struct_def.name + ".Pack(fbb, this));\n";
2042 code += " return fbb.DataBuffer.ToSizedArray();\n";
2048 // This tracks the current namespace used to determine if a type need to be
2049 // prefixed by its namespace
2050 const Namespace *cur_name_space_;
2052 } // namespace csharp
2054 bool GenerateCSharp(const Parser &parser, const std::string &path,
2055 const std::string &file_name) {
2056 csharp::CSharpGenerator generator(parser, path, file_name);
2057 return generator.generate();
2060 } // namespace flatbuffers