xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_swift.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2020 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker  *
4*890232f2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker  *
8*890232f2SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker  *
10*890232f2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker  * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker  */
16*890232f2SAndroid Build Coastguard Worker 
17*890232f2SAndroid Build Coastguard Worker #include <cctype>
18*890232f2SAndroid Build Coastguard Worker #include <unordered_set>
19*890232f2SAndroid Build Coastguard Worker 
20*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/code_generators.h"
21*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
23*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
24*890232f2SAndroid Build Coastguard Worker #include "idl_namer.h"
25*890232f2SAndroid Build Coastguard Worker 
26*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
27*890232f2SAndroid Build Coastguard Worker 
28*890232f2SAndroid Build Coastguard Worker namespace swift {
29*890232f2SAndroid Build Coastguard Worker 
30*890232f2SAndroid Build Coastguard Worker namespace {
31*890232f2SAndroid Build Coastguard Worker 
SwiftDefaultConfig()32*890232f2SAndroid Build Coastguard Worker static Namer::Config SwiftDefaultConfig() {
33*890232f2SAndroid Build Coastguard Worker   return { /*types=*/Case::kKeep,
34*890232f2SAndroid Build Coastguard Worker            /*constants=*/Case::kLowerCamel,
35*890232f2SAndroid Build Coastguard Worker            /*methods=*/Case::kLowerCamel,
36*890232f2SAndroid Build Coastguard Worker            /*functions=*/Case::kLowerCamel,
37*890232f2SAndroid Build Coastguard Worker            /*fields=*/Case::kLowerCamel,
38*890232f2SAndroid Build Coastguard Worker            /*variables=*/Case::kLowerCamel,
39*890232f2SAndroid Build Coastguard Worker            /*variants=*/Case::kLowerCamel,
40*890232f2SAndroid Build Coastguard Worker            /*enum_variant_seperator=*/".",
41*890232f2SAndroid Build Coastguard Worker            /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
42*890232f2SAndroid Build Coastguard Worker            /*namespaces=*/Case::kKeep,
43*890232f2SAndroid Build Coastguard Worker            /*namespace_seperator=*/"_",
44*890232f2SAndroid Build Coastguard Worker            /*object_prefix=*/"",
45*890232f2SAndroid Build Coastguard Worker            /*object_suffix=*/"T",
46*890232f2SAndroid Build Coastguard Worker            /*keyword_prefix=*/"",
47*890232f2SAndroid Build Coastguard Worker            /*keyword_suffix=*/"_",
48*890232f2SAndroid Build Coastguard Worker            /*filenames=*/Case::kKeep,
49*890232f2SAndroid Build Coastguard Worker            /*directories=*/Case::kKeep,
50*890232f2SAndroid Build Coastguard Worker            /*output_path=*/"",
51*890232f2SAndroid Build Coastguard Worker            /*filename_suffix=*/"_generated",
52*890232f2SAndroid Build Coastguard Worker            /*filename_extension=*/".swift" };
53*890232f2SAndroid Build Coastguard Worker }
54*890232f2SAndroid Build Coastguard Worker 
SwiftKeywords()55*890232f2SAndroid Build Coastguard Worker static std::set<std::string> SwiftKeywords() {
56*890232f2SAndroid Build Coastguard Worker   return {
57*890232f2SAndroid Build Coastguard Worker     "associatedtype",
58*890232f2SAndroid Build Coastguard Worker     "class",
59*890232f2SAndroid Build Coastguard Worker     "deinit",
60*890232f2SAndroid Build Coastguard Worker     "enum",
61*890232f2SAndroid Build Coastguard Worker     "extension",
62*890232f2SAndroid Build Coastguard Worker     "fileprivate",
63*890232f2SAndroid Build Coastguard Worker     "func",
64*890232f2SAndroid Build Coastguard Worker     "import",
65*890232f2SAndroid Build Coastguard Worker     "init",
66*890232f2SAndroid Build Coastguard Worker     "inout",
67*890232f2SAndroid Build Coastguard Worker     "internal",
68*890232f2SAndroid Build Coastguard Worker     "let",
69*890232f2SAndroid Build Coastguard Worker     "open",
70*890232f2SAndroid Build Coastguard Worker     "operator",
71*890232f2SAndroid Build Coastguard Worker     "private",
72*890232f2SAndroid Build Coastguard Worker     "protocol",
73*890232f2SAndroid Build Coastguard Worker     "public",
74*890232f2SAndroid Build Coastguard Worker     "rethrows",
75*890232f2SAndroid Build Coastguard Worker     "static",
76*890232f2SAndroid Build Coastguard Worker     "struct",
77*890232f2SAndroid Build Coastguard Worker     "subscript",
78*890232f2SAndroid Build Coastguard Worker     "typealias",
79*890232f2SAndroid Build Coastguard Worker     "var",
80*890232f2SAndroid Build Coastguard Worker     "break",
81*890232f2SAndroid Build Coastguard Worker     "case",
82*890232f2SAndroid Build Coastguard Worker     "continue",
83*890232f2SAndroid Build Coastguard Worker     "default",
84*890232f2SAndroid Build Coastguard Worker     "defer",
85*890232f2SAndroid Build Coastguard Worker     "do",
86*890232f2SAndroid Build Coastguard Worker     "else",
87*890232f2SAndroid Build Coastguard Worker     "fallthrough",
88*890232f2SAndroid Build Coastguard Worker     "for",
89*890232f2SAndroid Build Coastguard Worker     "guard",
90*890232f2SAndroid Build Coastguard Worker     "if",
91*890232f2SAndroid Build Coastguard Worker     "in",
92*890232f2SAndroid Build Coastguard Worker     "repeat",
93*890232f2SAndroid Build Coastguard Worker     "return",
94*890232f2SAndroid Build Coastguard Worker     "switch",
95*890232f2SAndroid Build Coastguard Worker     "where",
96*890232f2SAndroid Build Coastguard Worker     "while",
97*890232f2SAndroid Build Coastguard Worker     "Any",
98*890232f2SAndroid Build Coastguard Worker     "catch",
99*890232f2SAndroid Build Coastguard Worker     "false",
100*890232f2SAndroid Build Coastguard Worker     "is",
101*890232f2SAndroid Build Coastguard Worker     "nil",
102*890232f2SAndroid Build Coastguard Worker     "super",
103*890232f2SAndroid Build Coastguard Worker     "self",
104*890232f2SAndroid Build Coastguard Worker     "Self",
105*890232f2SAndroid Build Coastguard Worker     "throw",
106*890232f2SAndroid Build Coastguard Worker     "throws",
107*890232f2SAndroid Build Coastguard Worker     "true",
108*890232f2SAndroid Build Coastguard Worker     "try",
109*890232f2SAndroid Build Coastguard Worker     "associativity",
110*890232f2SAndroid Build Coastguard Worker     "convenience",
111*890232f2SAndroid Build Coastguard Worker     "dynamic",
112*890232f2SAndroid Build Coastguard Worker     "didSet",
113*890232f2SAndroid Build Coastguard Worker     "final",
114*890232f2SAndroid Build Coastguard Worker     "get",
115*890232f2SAndroid Build Coastguard Worker     "infix",
116*890232f2SAndroid Build Coastguard Worker     "indirect",
117*890232f2SAndroid Build Coastguard Worker     "lazy",
118*890232f2SAndroid Build Coastguard Worker     "left",
119*890232f2SAndroid Build Coastguard Worker     "mutating",
120*890232f2SAndroid Build Coastguard Worker     "none",
121*890232f2SAndroid Build Coastguard Worker     "nonmutating",
122*890232f2SAndroid Build Coastguard Worker     "optional",
123*890232f2SAndroid Build Coastguard Worker     "override",
124*890232f2SAndroid Build Coastguard Worker     "postfix",
125*890232f2SAndroid Build Coastguard Worker     "precedence",
126*890232f2SAndroid Build Coastguard Worker     "prefix",
127*890232f2SAndroid Build Coastguard Worker     "Protocol",
128*890232f2SAndroid Build Coastguard Worker     "required",
129*890232f2SAndroid Build Coastguard Worker     "right",
130*890232f2SAndroid Build Coastguard Worker     "set",
131*890232f2SAndroid Build Coastguard Worker     "Type",
132*890232f2SAndroid Build Coastguard Worker     "unowned",
133*890232f2SAndroid Build Coastguard Worker     "weak",
134*890232f2SAndroid Build Coastguard Worker     "willSet",
135*890232f2SAndroid Build Coastguard Worker     "Void",
136*890232f2SAndroid Build Coastguard Worker   };
137*890232f2SAndroid Build Coastguard Worker }
138*890232f2SAndroid Build Coastguard Worker 
GenIndirect(const std::string & reading)139*890232f2SAndroid Build Coastguard Worker static std::string GenIndirect(const std::string &reading) {
140*890232f2SAndroid Build Coastguard Worker   return "{{ACCESS}}.indirect(" + reading + ")";
141*890232f2SAndroid Build Coastguard Worker }
142*890232f2SAndroid Build Coastguard Worker 
GenArrayMainBody(const std::string & optional)143*890232f2SAndroid Build Coastguard Worker static std::string GenArrayMainBody(const std::string &optional) {
144*890232f2SAndroid Build Coastguard Worker   return "{{ACCESS_TYPE}} func {{FIELDMETHOD}}(at index: Int32) -> "
145*890232f2SAndroid Build Coastguard Worker          "{{VALUETYPE}}" +
146*890232f2SAndroid Build Coastguard Worker          optional + " { ";
147*890232f2SAndroid Build Coastguard Worker }
148*890232f2SAndroid Build Coastguard Worker 
149*890232f2SAndroid Build Coastguard Worker } // namespace
150*890232f2SAndroid Build Coastguard Worker 
151*890232f2SAndroid Build Coastguard Worker class SwiftGenerator : public BaseGenerator {
152*890232f2SAndroid Build Coastguard Worker  private:
153*890232f2SAndroid Build Coastguard Worker   CodeWriter code_;
154*890232f2SAndroid Build Coastguard Worker   std::unordered_set<std::string> keywords_;
155*890232f2SAndroid Build Coastguard Worker   int namespace_depth;
156*890232f2SAndroid Build Coastguard Worker 
157*890232f2SAndroid Build Coastguard Worker  public:
SwiftGenerator(const Parser & parser,const std::string & path,const std::string & file_name)158*890232f2SAndroid Build Coastguard Worker   SwiftGenerator(const Parser &parser, const std::string &path,
159*890232f2SAndroid Build Coastguard Worker                  const std::string &file_name)
160*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, file_name, "", "_", "swift"),
161*890232f2SAndroid Build Coastguard Worker         namer_(WithFlagOptions(SwiftDefaultConfig(), parser.opts, path),
162*890232f2SAndroid Build Coastguard Worker                SwiftKeywords()) {
163*890232f2SAndroid Build Coastguard Worker     namespace_depth = 0;
164*890232f2SAndroid Build Coastguard Worker     code_.SetPadding("  ");
165*890232f2SAndroid Build Coastguard Worker   }
166*890232f2SAndroid Build Coastguard Worker 
generate()167*890232f2SAndroid Build Coastguard Worker   bool generate() {
168*890232f2SAndroid Build Coastguard Worker     code_.Clear();
169*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ACCESS", "_accessor");
170*890232f2SAndroid Build Coastguard Worker     code_.SetValue("TABLEOFFSET", "VTOFFSET");
171*890232f2SAndroid Build Coastguard Worker     code_ += "// " + std::string(FlatBuffersGeneratedWarning());
172*890232f2SAndroid Build Coastguard Worker     code_ += "// swiftlint:disable all";
173*890232f2SAndroid Build Coastguard Worker     code_ += "// swiftformat:disable all\n";
174*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.include_dependence_headers || parser_.opts.generate_all) {
175*890232f2SAndroid Build Coastguard Worker       if (parser_.opts.swift_implementation_only)
176*890232f2SAndroid Build Coastguard Worker         code_ += "@_implementationOnly \\";
177*890232f2SAndroid Build Coastguard Worker 
178*890232f2SAndroid Build Coastguard Worker       code_ += "import FlatBuffers\n";
179*890232f2SAndroid Build Coastguard Worker     }
180*890232f2SAndroid Build Coastguard Worker 
181*890232f2SAndroid Build Coastguard Worker     // Generate code for all the enum declarations.
182*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
183*890232f2SAndroid Build Coastguard Worker          ++it) {
184*890232f2SAndroid Build Coastguard Worker       const auto &enum_def = **it;
185*890232f2SAndroid Build Coastguard Worker       if (!enum_def.generated) { GenEnum(enum_def); }
186*890232f2SAndroid Build Coastguard Worker     }
187*890232f2SAndroid Build Coastguard Worker 
188*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.structs_.vec.begin();
189*890232f2SAndroid Build Coastguard Worker          it != parser_.structs_.vec.end(); ++it) {
190*890232f2SAndroid Build Coastguard Worker       const auto &struct_def = **it;
191*890232f2SAndroid Build Coastguard Worker       if (struct_def.fixed && !struct_def.generated) {
192*890232f2SAndroid Build Coastguard Worker         GenStructReader(struct_def);
193*890232f2SAndroid Build Coastguard Worker         GenMutableStructReader(struct_def);
194*890232f2SAndroid Build Coastguard Worker       }
195*890232f2SAndroid Build Coastguard Worker     }
196*890232f2SAndroid Build Coastguard Worker 
197*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.structs_.vec.begin();
198*890232f2SAndroid Build Coastguard Worker          it != parser_.structs_.vec.end(); ++it) {
199*890232f2SAndroid Build Coastguard Worker       const auto &struct_def = **it;
200*890232f2SAndroid Build Coastguard Worker       if (!struct_def.fixed && !struct_def.generated) {
201*890232f2SAndroid Build Coastguard Worker         GenTable(struct_def);
202*890232f2SAndroid Build Coastguard Worker         if (parser_.opts.generate_object_based_api) {
203*890232f2SAndroid Build Coastguard Worker           GenObjectAPI(struct_def);
204*890232f2SAndroid Build Coastguard Worker         }
205*890232f2SAndroid Build Coastguard Worker       }
206*890232f2SAndroid Build Coastguard Worker     }
207*890232f2SAndroid Build Coastguard Worker 
208*890232f2SAndroid Build Coastguard Worker     const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
209*890232f2SAndroid Build Coastguard Worker     const auto final_code = code_.ToString();
210*890232f2SAndroid Build Coastguard Worker     return SaveFile(filename.c_str(), final_code, false);
211*890232f2SAndroid Build Coastguard Worker   }
212*890232f2SAndroid Build Coastguard Worker 
mark(const std::string & str)213*890232f2SAndroid Build Coastguard Worker   void mark(const std::string &str) {
214*890232f2SAndroid Build Coastguard Worker     code_.SetValue("MARKVALUE", str);
215*890232f2SAndroid Build Coastguard Worker     code_ += "\n// MARK: - {{MARKVALUE}}\n";
216*890232f2SAndroid Build Coastguard Worker   }
217*890232f2SAndroid Build Coastguard Worker 
218*890232f2SAndroid Build Coastguard Worker   // MARK: - Generating structs
219*890232f2SAndroid Build Coastguard Worker 
220*890232f2SAndroid Build Coastguard Worker   // Generates the reader for swift
GenStructReader(const StructDef & struct_def)221*890232f2SAndroid Build Coastguard Worker   void GenStructReader(const StructDef &struct_def) {
222*890232f2SAndroid Build Coastguard Worker     const bool is_private_access =
223*890232f2SAndroid Build Coastguard Worker         parser_.opts.swift_implementation_only ||
224*890232f2SAndroid Build Coastguard Worker         struct_def.attributes.Lookup("private") != nullptr;
225*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
226*890232f2SAndroid Build Coastguard Worker     GenComment(struct_def.doc_comment);
227*890232f2SAndroid Build Coastguard Worker     code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
228*890232f2SAndroid Build Coastguard Worker     code_ +=
229*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable, "
230*890232f2SAndroid Build Coastguard Worker         "FlatbuffersInitializable\\";
231*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\";
232*890232f2SAndroid Build Coastguard Worker     code_ += " {";
233*890232f2SAndroid Build Coastguard Worker     code_ += "";
234*890232f2SAndroid Build Coastguard Worker     Indent();
235*890232f2SAndroid Build Coastguard Worker     code_ += ValidateFunc();
236*890232f2SAndroid Build Coastguard Worker     code_ += "";
237*890232f2SAndroid Build Coastguard Worker     int padding_id = 0;
238*890232f2SAndroid Build Coastguard Worker     std::string constructor = "";
239*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> base_constructor;
240*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> main_constructor;
241*890232f2SAndroid Build Coastguard Worker 
242*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
243*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
244*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
245*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
246*890232f2SAndroid Build Coastguard Worker 
247*890232f2SAndroid Build Coastguard Worker       if (!constructor.empty()) constructor += ", ";
248*890232f2SAndroid Build Coastguard Worker 
249*890232f2SAndroid Build Coastguard Worker       const auto field_var = namer_.Variable(field);
250*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(field.value.type);
251*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", field_var);
252*890232f2SAndroid Build Coastguard Worker       if (IsEnum(field.value.type)) {
253*890232f2SAndroid Build Coastguard Worker         code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
254*890232f2SAndroid Build Coastguard Worker       }
255*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", type);
256*890232f2SAndroid Build Coastguard Worker       GenComment(field.doc_comment);
257*890232f2SAndroid Build Coastguard Worker       std::string valueType =
258*890232f2SAndroid Build Coastguard Worker           IsEnum(field.value.type) ? "{{BASEVALUE}}" : "{{VALUETYPE}}";
259*890232f2SAndroid Build Coastguard Worker       code_ += "private var _{{FIELDVAR}}: " + valueType;
260*890232f2SAndroid Build Coastguard Worker       const auto accessing_value = IsEnum(field.value.type) ? ".value" : "";
261*890232f2SAndroid Build Coastguard Worker       const auto is_bool = IsBool(field.value.type.base_type);
262*890232f2SAndroid Build Coastguard Worker       const auto base_value =
263*890232f2SAndroid Build Coastguard Worker           IsStruct(field.value.type) ? (type + "()")
264*890232f2SAndroid Build Coastguard Worker           : is_bool ? ("0" == field.value.constant ? "false" : "true")
265*890232f2SAndroid Build Coastguard Worker                     : field.value.constant;
266*890232f2SAndroid Build Coastguard Worker 
267*890232f2SAndroid Build Coastguard Worker       main_constructor.push_back("_" + field_var + " = " + field_var +
268*890232f2SAndroid Build Coastguard Worker                                  accessing_value);
269*890232f2SAndroid Build Coastguard Worker       base_constructor.push_back("_" + field_var + " = " + base_value);
270*890232f2SAndroid Build Coastguard Worker 
271*890232f2SAndroid Build Coastguard Worker       if (field.padding) { GenPadding(field, &padding_id); }
272*890232f2SAndroid Build Coastguard Worker       constructor += field_var + ": " + type;
273*890232f2SAndroid Build Coastguard Worker     }
274*890232f2SAndroid Build Coastguard Worker     code_ += "";
275*890232f2SAndroid Build Coastguard Worker     BuildStructConstructor(struct_def);
276*890232f2SAndroid Build Coastguard Worker     BuildObjectConstructor(main_constructor, constructor);
277*890232f2SAndroid Build Coastguard Worker     BuildObjectConstructor(base_constructor, "");
278*890232f2SAndroid Build Coastguard Worker 
279*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api)
280*890232f2SAndroid Build Coastguard Worker       GenerateObjectAPIStructConstructor(struct_def);
281*890232f2SAndroid Build Coastguard Worker 
282*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
283*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
284*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
285*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
286*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
287*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", GenType(field.value.type));
288*890232f2SAndroid Build Coastguard Worker       GenComment(field.doc_comment);
289*890232f2SAndroid Build Coastguard Worker       if (!IsEnum(field.value.type)) {
290*890232f2SAndroid Build Coastguard Worker         code_ += GenReaderMainBody() + "_{{FIELDVAR}} }";
291*890232f2SAndroid Build Coastguard Worker       } else if (IsEnum(field.value.type)) {
292*890232f2SAndroid Build Coastguard Worker         code_ +=
293*890232f2SAndroid Build Coastguard Worker             GenReaderMainBody() + "{{VALUETYPE}}(rawValue: _{{FIELDVAR}})! }";
294*890232f2SAndroid Build Coastguard Worker       }
295*890232f2SAndroid Build Coastguard Worker     }
296*890232f2SAndroid Build Coastguard Worker     code_ += "";
297*890232f2SAndroid Build Coastguard Worker     code_ +=
298*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func verify<T>(_ verifier: inout Verifier, at "
299*890232f2SAndroid Build Coastguard Worker         "position: "
300*890232f2SAndroid Build Coastguard Worker         "Int, of type: T.Type) throws where T: Verifiable {";
301*890232f2SAndroid Build Coastguard Worker     Indent();
302*890232f2SAndroid Build Coastguard Worker     code_ +=
303*890232f2SAndroid Build Coastguard Worker         "try verifier.inBuffer(position: position, of: {{STRUCTNAME}}.self)";
304*890232f2SAndroid Build Coastguard Worker     Outdent();
305*890232f2SAndroid Build Coastguard Worker     code_ += "}";
306*890232f2SAndroid Build Coastguard Worker     Outdent();
307*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
308*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
309*890232f2SAndroid Build Coastguard Worker   }
310*890232f2SAndroid Build Coastguard Worker 
BuildStructConstructor(const StructDef & struct_def)311*890232f2SAndroid Build Coastguard Worker   void BuildStructConstructor(const StructDef &struct_def) {
312*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) {";
313*890232f2SAndroid Build Coastguard Worker     Indent();
314*890232f2SAndroid Build Coastguard Worker     code_ += "let {{ACCESS}} = Struct(bb: bb, position: o)";
315*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
316*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
317*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
318*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
319*890232f2SAndroid Build Coastguard Worker       const auto type = field.value.type;
320*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
321*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", GenType(type));
322*890232f2SAndroid Build Coastguard Worker       code_.SetValue("OFFSET", NumToString(field.value.offset));
323*890232f2SAndroid Build Coastguard Worker       if (IsScalar(type.base_type)) {
324*890232f2SAndroid Build Coastguard Worker         if (IsEnum(type))
325*890232f2SAndroid Build Coastguard Worker           code_.SetValue("VALUETYPE", GenTypeBasic(field.value.type, false));
326*890232f2SAndroid Build Coastguard Worker         code_ +=
327*890232f2SAndroid Build Coastguard Worker             "_{{FIELDVAR}} = {{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, "
328*890232f2SAndroid Build Coastguard Worker             "at: {{OFFSET}})";
329*890232f2SAndroid Build Coastguard Worker       } else {
330*890232f2SAndroid Build Coastguard Worker         code_ +=
331*890232f2SAndroid Build Coastguard Worker             "_{{FIELDVAR}} = {{VALUETYPE}}({{ACCESS}}.bb, o: "
332*890232f2SAndroid Build Coastguard Worker             "{{ACCESS}}.postion + {{OFFSET}})";
333*890232f2SAndroid Build Coastguard Worker       }
334*890232f2SAndroid Build Coastguard Worker     }
335*890232f2SAndroid Build Coastguard Worker     Outdent();
336*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
337*890232f2SAndroid Build Coastguard Worker   }
338*890232f2SAndroid Build Coastguard Worker 
GenMutableStructReader(const StructDef & struct_def)339*890232f2SAndroid Build Coastguard Worker   void GenMutableStructReader(const StructDef &struct_def) {
340*890232f2SAndroid Build Coastguard Worker     GenObjectHeader(struct_def);
341*890232f2SAndroid Build Coastguard Worker 
342*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
343*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
344*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
345*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
346*890232f2SAndroid Build Coastguard Worker       const auto offset = NumToString(field.value.offset);
347*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(field.value.type);
348*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
349*890232f2SAndroid Build Coastguard Worker       if (IsEnum(field.value.type)) {
350*890232f2SAndroid Build Coastguard Worker         code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
351*890232f2SAndroid Build Coastguard Worker       }
352*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", type);
353*890232f2SAndroid Build Coastguard Worker       code_.SetValue("OFFSET", offset);
354*890232f2SAndroid Build Coastguard Worker       if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
355*890232f2SAndroid Build Coastguard Worker         code_ +=
356*890232f2SAndroid Build Coastguard Worker             GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
357*890232f2SAndroid Build Coastguard Worker       } else if (IsEnum(field.value.type)) {
358*890232f2SAndroid Build Coastguard Worker         code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
359*890232f2SAndroid Build Coastguard Worker         code_ += GenReaderMainBody() + "return " +
360*890232f2SAndroid Build Coastguard Worker                  GenEnumConstructor("{{OFFSET}}") + "?? " +
361*890232f2SAndroid Build Coastguard Worker                  GenEnumDefaultValue(field) + " }";
362*890232f2SAndroid Build Coastguard Worker       } else if (IsStruct(field.value.type)) {
363*890232f2SAndroid Build Coastguard Worker         code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
364*890232f2SAndroid Build Coastguard Worker         code_ += GenReaderMainBody() + "return " +
365*890232f2SAndroid Build Coastguard Worker                  GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
366*890232f2SAndroid Build Coastguard Worker       }
367*890232f2SAndroid Build Coastguard Worker       if (parser_.opts.mutable_buffer && !IsStruct(field.value.type))
368*890232f2SAndroid Build Coastguard Worker         code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type));
369*890232f2SAndroid Build Coastguard Worker     }
370*890232f2SAndroid Build Coastguard Worker 
371*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api) {
372*890232f2SAndroid Build Coastguard Worker       GenerateObjectAPIExtensionHeader(namer_.NamespacedType(struct_def));
373*890232f2SAndroid Build Coastguard Worker       code_ += "return builder.create(struct: obj)";
374*890232f2SAndroid Build Coastguard Worker       Outdent();
375*890232f2SAndroid Build Coastguard Worker       code_ += "}";
376*890232f2SAndroid Build Coastguard Worker     }
377*890232f2SAndroid Build Coastguard Worker     Outdent();
378*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
379*890232f2SAndroid Build Coastguard Worker   }
380*890232f2SAndroid Build Coastguard Worker 
381*890232f2SAndroid Build Coastguard Worker   // Generates the create function for swift
GenStructWriter(const StructDef & struct_def)382*890232f2SAndroid Build Coastguard Worker   void GenStructWriter(const StructDef &struct_def) {
383*890232f2SAndroid Build Coastguard Worker     const bool is_private_access =
384*890232f2SAndroid Build Coastguard Worker         parser_.opts.swift_implementation_only ||
385*890232f2SAndroid Build Coastguard Worker         struct_def.attributes.Lookup("private") != nullptr;
386*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
387*890232f2SAndroid Build Coastguard Worker     code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
388*890232f2SAndroid Build Coastguard Worker     code_.SetValue("SHORT_STRUCTNAME", namer_.Method(struct_def));
389*890232f2SAndroid Build Coastguard Worker     code_ += "extension {{STRUCTNAME}} {";
390*890232f2SAndroid Build Coastguard Worker     Indent();
391*890232f2SAndroid Build Coastguard Worker     code_ += "@discardableResult";
392*890232f2SAndroid Build Coastguard Worker     code_ +=
393*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout "
394*890232f2SAndroid Build Coastguard Worker         "FlatBufferBuilder, \\";
395*890232f2SAndroid Build Coastguard Worker     std::string func_header = "";
396*890232f2SAndroid Build Coastguard Worker     GenerateStructArgs(struct_def, &func_header, "", "");
397*890232f2SAndroid Build Coastguard Worker     code_ += func_header.substr(0, func_header.size() - 2) + "\\";
398*890232f2SAndroid Build Coastguard Worker     code_ += ") -> Offset {";
399*890232f2SAndroid Build Coastguard Worker     Indent();
400*890232f2SAndroid Build Coastguard Worker     code_ +=
401*890232f2SAndroid Build Coastguard Worker         "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
402*890232f2SAndroid Build Coastguard Worker         "{{STRUCTNAME}}.alignment)";
403*890232f2SAndroid Build Coastguard Worker     code_ += "return builder.endStruct()";
404*890232f2SAndroid Build Coastguard Worker     Outdent();
405*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
406*890232f2SAndroid Build Coastguard Worker     Outdent();
407*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
408*890232f2SAndroid Build Coastguard Worker   }
409*890232f2SAndroid Build Coastguard Worker 
GenerateStructArgs(const StructDef & struct_def,std::string * code_ptr,const std::string & nameprefix,const std::string & object_name,const std::string & obj_api_named="",bool is_obj_api=false)410*890232f2SAndroid Build Coastguard Worker   void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
411*890232f2SAndroid Build Coastguard Worker                           const std::string &nameprefix,
412*890232f2SAndroid Build Coastguard Worker                           const std::string &object_name,
413*890232f2SAndroid Build Coastguard Worker                           const std::string &obj_api_named = "",
414*890232f2SAndroid Build Coastguard Worker                           bool is_obj_api = false) {
415*890232f2SAndroid Build Coastguard Worker     auto &code = *code_ptr;
416*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
417*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
418*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
419*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
420*890232f2SAndroid Build Coastguard Worker       const auto &field_type = field.value.type;
421*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
422*890232f2SAndroid Build Coastguard Worker         GenerateStructArgs(
423*890232f2SAndroid Build Coastguard Worker             *field_type.struct_def, code_ptr, (nameprefix + field.name),
424*890232f2SAndroid Build Coastguard Worker             (object_name + "." + field.name), obj_api_named, is_obj_api);
425*890232f2SAndroid Build Coastguard Worker       } else {
426*890232f2SAndroid Build Coastguard Worker         const auto field_var = namer_.Variable(field);
427*890232f2SAndroid Build Coastguard Worker         const auto field_field = namer_.Field(field);
428*890232f2SAndroid Build Coastguard Worker         const auto type = GenType(field.value.type);
429*890232f2SAndroid Build Coastguard Worker         if (!is_obj_api) {
430*890232f2SAndroid Build Coastguard Worker           code += nameprefix + field_var + ": " + type;
431*890232f2SAndroid Build Coastguard Worker           if (!IsEnum(field.value.type)) {
432*890232f2SAndroid Build Coastguard Worker             code += " = ";
433*890232f2SAndroid Build Coastguard Worker             const auto is_bool = IsBool(field.value.type.base_type);
434*890232f2SAndroid Build Coastguard Worker             const auto constant =
435*890232f2SAndroid Build Coastguard Worker                 is_bool ? ("0" == field.value.constant ? "false" : "true")
436*890232f2SAndroid Build Coastguard Worker                         : field.value.constant;
437*890232f2SAndroid Build Coastguard Worker             code += constant;
438*890232f2SAndroid Build Coastguard Worker           }
439*890232f2SAndroid Build Coastguard Worker           code += ", ";
440*890232f2SAndroid Build Coastguard Worker           continue;
441*890232f2SAndroid Build Coastguard Worker         }
442*890232f2SAndroid Build Coastguard Worker         code += nameprefix + field_var + ": " + obj_api_named + object_name +
443*890232f2SAndroid Build Coastguard Worker                 "." + field_field;
444*890232f2SAndroid Build Coastguard Worker         code += ", ";
445*890232f2SAndroid Build Coastguard Worker       }
446*890232f2SAndroid Build Coastguard Worker     }
447*890232f2SAndroid Build Coastguard Worker   }
448*890232f2SAndroid Build Coastguard Worker 
449*890232f2SAndroid Build Coastguard Worker   // MARK: - Table Generator
450*890232f2SAndroid Build Coastguard Worker 
451*890232f2SAndroid Build Coastguard Worker   // Generates the reader for swift
GenTable(const StructDef & struct_def)452*890232f2SAndroid Build Coastguard Worker   void GenTable(const StructDef &struct_def) {
453*890232f2SAndroid Build Coastguard Worker     const bool is_private_access =
454*890232f2SAndroid Build Coastguard Worker         parser_.opts.swift_implementation_only ||
455*890232f2SAndroid Build Coastguard Worker         struct_def.attributes.Lookup("private") != nullptr;
456*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
457*890232f2SAndroid Build Coastguard Worker     GenObjectHeader(struct_def);
458*890232f2SAndroid Build Coastguard Worker     GenTableAccessors(struct_def);
459*890232f2SAndroid Build Coastguard Worker     GenTableReader(struct_def);
460*890232f2SAndroid Build Coastguard Worker     GenTableWriter(struct_def);
461*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api)
462*890232f2SAndroid Build Coastguard Worker       GenerateObjectAPITableExtension(struct_def);
463*890232f2SAndroid Build Coastguard Worker     code_ += "";
464*890232f2SAndroid Build Coastguard Worker     GenerateVerifier(struct_def);
465*890232f2SAndroid Build Coastguard Worker     Outdent();
466*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
467*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
468*890232f2SAndroid Build Coastguard Worker   }
469*890232f2SAndroid Build Coastguard Worker 
470*890232f2SAndroid Build Coastguard Worker   // Generates the reader for swift
GenTableAccessors(const StructDef & struct_def)471*890232f2SAndroid Build Coastguard Worker   void GenTableAccessors(const StructDef &struct_def) {
472*890232f2SAndroid Build Coastguard Worker     // Generate field id constants.
473*890232f2SAndroid Build Coastguard Worker     if (struct_def.fields.vec.size() > 0) {
474*890232f2SAndroid Build Coastguard Worker       code_ += "private enum {{TABLEOFFSET}}: VOffset {";
475*890232f2SAndroid Build Coastguard Worker       Indent();
476*890232f2SAndroid Build Coastguard Worker       for (auto it = struct_def.fields.vec.begin();
477*890232f2SAndroid Build Coastguard Worker            it != struct_def.fields.vec.end(); ++it) {
478*890232f2SAndroid Build Coastguard Worker         const auto &field = **it;
479*890232f2SAndroid Build Coastguard Worker         if (field.deprecated) { continue; }
480*890232f2SAndroid Build Coastguard Worker         code_.SetValue("OFFSET_NAME", namer_.Variable(field));
481*890232f2SAndroid Build Coastguard Worker         code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
482*890232f2SAndroid Build Coastguard Worker         code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
483*890232f2SAndroid Build Coastguard Worker       }
484*890232f2SAndroid Build Coastguard Worker       code_ += "var v: Int32 { Int32(self.rawValue) }";
485*890232f2SAndroid Build Coastguard Worker       code_ += "var p: VOffset { self.rawValue }";
486*890232f2SAndroid Build Coastguard Worker       Outdent();
487*890232f2SAndroid Build Coastguard Worker       code_ += "}";
488*890232f2SAndroid Build Coastguard Worker       code_ += "";
489*890232f2SAndroid Build Coastguard Worker     }
490*890232f2SAndroid Build Coastguard Worker   }
491*890232f2SAndroid Build Coastguard Worker 
GenObjectHeader(const StructDef & struct_def)492*890232f2SAndroid Build Coastguard Worker   void GenObjectHeader(const StructDef &struct_def) {
493*890232f2SAndroid Build Coastguard Worker     GenComment(struct_def.doc_comment);
494*890232f2SAndroid Build Coastguard Worker 
495*890232f2SAndroid Build Coastguard Worker     code_.SetValue("SHORT_STRUCTNAME", namer_.Type(struct_def));
496*890232f2SAndroid Build Coastguard Worker     code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
497*890232f2SAndroid Build Coastguard Worker     code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
498*890232f2SAndroid Build Coastguard Worker     code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : "");
499*890232f2SAndroid Build Coastguard Worker     code_ +=
500*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\";
501*890232f2SAndroid Build Coastguard Worker     if (!struct_def.fixed) code_ += ", Verifiable\\";
502*890232f2SAndroid Build Coastguard Worker     if (!struct_def.fixed && parser_.opts.generate_object_based_api)
503*890232f2SAndroid Build Coastguard Worker       code_ += ", ObjectAPIPacker\\";
504*890232f2SAndroid Build Coastguard Worker     code_ += " {\n";
505*890232f2SAndroid Build Coastguard Worker     Indent();
506*890232f2SAndroid Build Coastguard Worker     code_ += ValidateFunc();
507*890232f2SAndroid Build Coastguard Worker     code_ +=
508*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
509*890232f2SAndroid Build Coastguard Worker     code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
510*890232f2SAndroid Build Coastguard Worker     if (!struct_def.fixed) {
511*890232f2SAndroid Build Coastguard Worker       if (parser_.file_identifier_.length()) {
512*890232f2SAndroid Build Coastguard Worker         code_.SetValue("FILENAME", parser_.file_identifier_);
513*890232f2SAndroid Build Coastguard Worker         code_ += "{{ACCESS_TYPE}} static var id: String { \"{{FILENAME}}\" } ";
514*890232f2SAndroid Build Coastguard Worker         code_ +=
515*890232f2SAndroid Build Coastguard Worker             "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
516*890232f2SAndroid Build Coastguard Worker             "FlatBufferBuilder, end: "
517*890232f2SAndroid Build Coastguard Worker             "Offset, prefix: Bool = false) { fbb.finish(offset: end, "
518*890232f2SAndroid Build Coastguard Worker             "fileId: "
519*890232f2SAndroid Build Coastguard Worker             "{{STRUCTNAME}}.id, addPrefix: prefix) }";
520*890232f2SAndroid Build Coastguard Worker       }
521*890232f2SAndroid Build Coastguard Worker       code_ +=
522*890232f2SAndroid Build Coastguard Worker           "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
523*890232f2SAndroid Build Coastguard Worker           "ByteBuffer) -> "
524*890232f2SAndroid Build Coastguard Worker           "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
525*890232f2SAndroid Build Coastguard Worker           "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
526*890232f2SAndroid Build Coastguard Worker           "Int32(bb.reader))) }\n";
527*890232f2SAndroid Build Coastguard Worker       code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
528*890232f2SAndroid Build Coastguard Worker     }
529*890232f2SAndroid Build Coastguard Worker     code_ +=
530*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
531*890232f2SAndroid Build Coastguard Worker         "{{OBJECTTYPE}}(bb: "
532*890232f2SAndroid Build Coastguard Worker         "bb, position: o) }";
533*890232f2SAndroid Build Coastguard Worker     code_ += "";
534*890232f2SAndroid Build Coastguard Worker   }
535*890232f2SAndroid Build Coastguard Worker 
GenTableWriter(const StructDef & struct_def)536*890232f2SAndroid Build Coastguard Worker   void GenTableWriter(const StructDef &struct_def) {
537*890232f2SAndroid Build Coastguard Worker     flatbuffers::FieldDef *key_field = nullptr;
538*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> require_fields;
539*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> create_func_body;
540*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> create_func_header;
541*890232f2SAndroid Build Coastguard Worker     const auto should_generate_create = struct_def.fields.vec.size() != 0;
542*890232f2SAndroid Build Coastguard Worker 
543*890232f2SAndroid Build Coastguard Worker     code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
544*890232f2SAndroid Build Coastguard Worker     code_ +=
545*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout "
546*890232f2SAndroid Build Coastguard Worker         "FlatBufferBuilder) -> "
547*890232f2SAndroid Build Coastguard Worker         "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
548*890232f2SAndroid Build Coastguard Worker 
549*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
550*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
551*890232f2SAndroid Build Coastguard Worker       auto &field = **it;
552*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
553*890232f2SAndroid Build Coastguard Worker       if (field.key) key_field = &field;
554*890232f2SAndroid Build Coastguard Worker       if (field.IsRequired())
555*890232f2SAndroid Build Coastguard Worker         require_fields.push_back(NumToString(field.value.offset));
556*890232f2SAndroid Build Coastguard Worker 
557*890232f2SAndroid Build Coastguard Worker       GenTableWriterFields(field, &create_func_body, &create_func_header);
558*890232f2SAndroid Build Coastguard Worker     }
559*890232f2SAndroid Build Coastguard Worker     code_ +=
560*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
561*890232f2SAndroid Build Coastguard Worker         "FlatBufferBuilder, "
562*890232f2SAndroid Build Coastguard Worker         "start: "
563*890232f2SAndroid Build Coastguard Worker         "UOffset) -> Offset { let end = Offset(offset: "
564*890232f2SAndroid Build Coastguard Worker         "fbb.endTable(at: start))\\";
565*890232f2SAndroid Build Coastguard Worker     if (require_fields.capacity() != 0) {
566*890232f2SAndroid Build Coastguard Worker       std::string fields = "";
567*890232f2SAndroid Build Coastguard Worker       for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
568*890232f2SAndroid Build Coastguard Worker         fields += *it + ", ";
569*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
570*890232f2SAndroid Build Coastguard Worker       code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
571*890232f2SAndroid Build Coastguard Worker     }
572*890232f2SAndroid Build Coastguard Worker     code_ += "; return end }";
573*890232f2SAndroid Build Coastguard Worker 
574*890232f2SAndroid Build Coastguard Worker     if (should_generate_create) {
575*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
576*890232f2SAndroid Build Coastguard Worker       Indent();
577*890232f2SAndroid Build Coastguard Worker       code_ += "_ fbb: inout FlatBufferBuilder,";
578*890232f2SAndroid Build Coastguard Worker       for (auto it = create_func_header.begin(); it < create_func_header.end();
579*890232f2SAndroid Build Coastguard Worker            ++it) {
580*890232f2SAndroid Build Coastguard Worker         code_ += *it + "\\";
581*890232f2SAndroid Build Coastguard Worker         if (it < create_func_header.end() - 1) code_ += ",";
582*890232f2SAndroid Build Coastguard Worker       }
583*890232f2SAndroid Build Coastguard Worker       code_ += "";
584*890232f2SAndroid Build Coastguard Worker       Outdent();
585*890232f2SAndroid Build Coastguard Worker       code_ += ") -> Offset {";
586*890232f2SAndroid Build Coastguard Worker       Indent();
587*890232f2SAndroid Build Coastguard Worker       code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
588*890232f2SAndroid Build Coastguard Worker       for (auto it = create_func_body.begin(); it < create_func_body.end();
589*890232f2SAndroid Build Coastguard Worker            ++it) {
590*890232f2SAndroid Build Coastguard Worker         code_ += *it;
591*890232f2SAndroid Build Coastguard Worker       }
592*890232f2SAndroid Build Coastguard Worker       code_ +=
593*890232f2SAndroid Build Coastguard Worker           "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)";
594*890232f2SAndroid Build Coastguard Worker       Outdent();
595*890232f2SAndroid Build Coastguard Worker       code_ += "}";
596*890232f2SAndroid Build Coastguard Worker     }
597*890232f2SAndroid Build Coastguard Worker 
598*890232f2SAndroid Build Coastguard Worker     std::string spacing = "";
599*890232f2SAndroid Build Coastguard Worker 
600*890232f2SAndroid Build Coastguard Worker     if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
601*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
602*890232f2SAndroid Build Coastguard Worker 
603*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} static func " +
604*890232f2SAndroid Build Coastguard Worker                namer_.Method("sort_vector_of", struct_def) +
605*890232f2SAndroid Build Coastguard Worker                "(offsets:[Offset], "
606*890232f2SAndroid Build Coastguard Worker                "_ fbb: inout FlatBufferBuilder) -> Offset {";
607*890232f2SAndroid Build Coastguard Worker       Indent();
608*890232f2SAndroid Build Coastguard Worker       code_ += spacing + "var off = offsets";
609*890232f2SAndroid Build Coastguard Worker       code_ +=
610*890232f2SAndroid Build Coastguard Worker           spacing +
611*890232f2SAndroid Build Coastguard Worker           "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
612*890232f2SAndroid Build Coastguard Worker           "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
613*890232f2SAndroid Build Coastguard Worker           "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
614*890232f2SAndroid Build Coastguard Worker       code_ += spacing + "return fbb.createVector(ofOffsets: off)";
615*890232f2SAndroid Build Coastguard Worker       Outdent();
616*890232f2SAndroid Build Coastguard Worker       code_ += "}";
617*890232f2SAndroid Build Coastguard Worker       GenLookup(*key_field, namer_.NamespacedType(struct_def));
618*890232f2SAndroid Build Coastguard Worker     }
619*890232f2SAndroid Build Coastguard Worker   }
620*890232f2SAndroid Build Coastguard Worker 
GenTableWriterFields(const FieldDef & field,std::vector<std::string> * create_body,std::vector<std::string> * create_header)621*890232f2SAndroid Build Coastguard Worker   void GenTableWriterFields(const FieldDef &field,
622*890232f2SAndroid Build Coastguard Worker                             std::vector<std::string> *create_body,
623*890232f2SAndroid Build Coastguard Worker                             std::vector<std::string> *create_header) {
624*890232f2SAndroid Build Coastguard Worker     std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { ";
625*890232f2SAndroid Build Coastguard Worker     auto &create_func_body = *create_body;
626*890232f2SAndroid Build Coastguard Worker     auto &create_func_header = *create_header;
627*890232f2SAndroid Build Coastguard Worker     const auto field_field = namer_.Field(field);
628*890232f2SAndroid Build Coastguard Worker     const auto field_var = namer_.Variable(field);
629*890232f2SAndroid Build Coastguard Worker     const auto type = GenType(field.value.type);
630*890232f2SAndroid Build Coastguard Worker     const auto opt_scalar =
631*890232f2SAndroid Build Coastguard Worker         field.IsOptional() && IsScalar(field.value.type.base_type);
632*890232f2SAndroid Build Coastguard Worker     const auto nullable_type = opt_scalar ? type + "?" : type;
633*890232f2SAndroid Build Coastguard Worker     code_.SetValue("FIELDVAR", namer_.Variable(field));
634*890232f2SAndroid Build Coastguard Worker     code_.SetValue("VALUETYPE", nullable_type);
635*890232f2SAndroid Build Coastguard Worker     code_.SetValue("OFFSET", namer_.Field(field));
636*890232f2SAndroid Build Coastguard Worker     code_.SetValue("CONSTANT", field.value.constant);
637*890232f2SAndroid Build Coastguard Worker     std::string check_if_vector =
638*890232f2SAndroid Build Coastguard Worker         (IsVector(field.value.type) || IsArray(field.value.type)) ? "VectorOf("
639*890232f2SAndroid Build Coastguard Worker                                                                   : "(";
640*890232f2SAndroid Build Coastguard Worker     const auto body = "add" + check_if_vector + field_field + ": ";
641*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
642*890232f2SAndroid Build Coastguard Worker 
643*890232f2SAndroid Build Coastguard Worker     create_func_body.push_back("{{STRUCTNAME}}." + body + field_field +
644*890232f2SAndroid Build Coastguard Worker                                ", &fbb)");
645*890232f2SAndroid Build Coastguard Worker 
646*890232f2SAndroid Build Coastguard Worker     if (IsScalar(field.value.type.base_type) &&
647*890232f2SAndroid Build Coastguard Worker         !IsBool(field.value.type.base_type)) {
648*890232f2SAndroid Build Coastguard Worker       const std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
649*890232f2SAndroid Build Coastguard Worker       const std::string optional_enum =
650*890232f2SAndroid Build Coastguard Worker           IsEnum(field.value.type) ? ("?" + is_enum) : "";
651*890232f2SAndroid Build Coastguard Worker       code_ +=
652*890232f2SAndroid Build Coastguard Worker           "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{FIELDVAR}}\\";
653*890232f2SAndroid Build Coastguard Worker 
654*890232f2SAndroid Build Coastguard Worker       code_ += field.IsOptional() ? (optional_enum + "\\")
655*890232f2SAndroid Build Coastguard Worker                                   : (is_enum + ", def: {{CONSTANT}}\\");
656*890232f2SAndroid Build Coastguard Worker 
657*890232f2SAndroid Build Coastguard Worker       code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
658*890232f2SAndroid Build Coastguard Worker 
659*890232f2SAndroid Build Coastguard Worker       const auto default_value =
660*890232f2SAndroid Build Coastguard Worker           IsEnum(field.value.type)
661*890232f2SAndroid Build Coastguard Worker               ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field))
662*890232f2SAndroid Build Coastguard Worker               : field.value.constant;
663*890232f2SAndroid Build Coastguard Worker       create_func_header.push_back(
664*890232f2SAndroid Build Coastguard Worker           "" + field_field + ": " + nullable_type + " = " +
665*890232f2SAndroid Build Coastguard Worker           (field.IsOptional() ? "nil" : default_value));
666*890232f2SAndroid Build Coastguard Worker       return;
667*890232f2SAndroid Build Coastguard Worker     }
668*890232f2SAndroid Build Coastguard Worker 
669*890232f2SAndroid Build Coastguard Worker     if (IsBool(field.value.type.base_type)) {
670*890232f2SAndroid Build Coastguard Worker       std::string default_value =
671*890232f2SAndroid Build Coastguard Worker           "0" == field.value.constant ? "false" : "true";
672*890232f2SAndroid Build Coastguard Worker 
673*890232f2SAndroid Build Coastguard Worker       code_.SetValue("CONSTANT", default_value);
674*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", field.IsOptional() ? "Bool?" : "Bool");
675*890232f2SAndroid Build Coastguard Worker       code_ +=
676*890232f2SAndroid Build Coastguard Worker           "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{FIELDVAR}},\\";
677*890232f2SAndroid Build Coastguard Worker       code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},";
678*890232f2SAndroid Build Coastguard Worker       code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
679*890232f2SAndroid Build Coastguard Worker       create_func_header.push_back(
680*890232f2SAndroid Build Coastguard Worker           field_var + ": " + nullable_type + " = " +
681*890232f2SAndroid Build Coastguard Worker           (field.IsOptional() ? "nil" : default_value));
682*890232f2SAndroid Build Coastguard Worker       return;
683*890232f2SAndroid Build Coastguard Worker     }
684*890232f2SAndroid Build Coastguard Worker 
685*890232f2SAndroid Build Coastguard Worker     if (IsStruct(field.value.type)) {
686*890232f2SAndroid Build Coastguard Worker       const auto create_struct =
687*890232f2SAndroid Build Coastguard Worker           "guard let {{FIELDVAR}} = {{FIELDVAR}} else { return };"
688*890232f2SAndroid Build Coastguard Worker           " fbb.create(struct: {{FIELDVAR}}, position: "
689*890232f2SAndroid Build Coastguard Worker           "{{TABLEOFFSET}}.{{OFFSET}}.p) }";
690*890232f2SAndroid Build Coastguard Worker       code_ += type + "?" + builder_string + create_struct;
691*890232f2SAndroid Build Coastguard Worker       /// Optional hard coded since structs are always optional
692*890232f2SAndroid Build Coastguard Worker       create_func_header.push_back(field_var + ": " + type +
693*890232f2SAndroid Build Coastguard Worker                                    (field.IsOptional() ? "? = nil" : ""));
694*890232f2SAndroid Build Coastguard Worker       return;
695*890232f2SAndroid Build Coastguard Worker     }
696*890232f2SAndroid Build Coastguard Worker 
697*890232f2SAndroid Build Coastguard Worker     const auto arg_label =
698*890232f2SAndroid Build Coastguard Worker         namer_.Variable(field) +
699*890232f2SAndroid Build Coastguard Worker         (IsVector(field.value.type) || IsArray(field.value.type)
700*890232f2SAndroid Build Coastguard Worker              ? "VectorOffset"
701*890232f2SAndroid Build Coastguard Worker              : "Offset");
702*890232f2SAndroid Build Coastguard Worker     create_func_header.push_back(arg_label + " " + field_var + ": " + "Offset" +
703*890232f2SAndroid Build Coastguard Worker                                  (field.IsRequired() ? "" : " = Offset()"));
704*890232f2SAndroid Build Coastguard Worker     const auto reader_type =
705*890232f2SAndroid Build Coastguard Worker         IsStruct(field.value.type) && field.value.type.struct_def->fixed
706*890232f2SAndroid Build Coastguard Worker             ? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
707*890232f2SAndroid Build Coastguard Worker             : "offset: {{FIELDVAR}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
708*890232f2SAndroid Build Coastguard Worker     code_ += "Offset" + builder_string + "fbb.add(" + reader_type;
709*890232f2SAndroid Build Coastguard Worker 
710*890232f2SAndroid Build Coastguard Worker     const auto vectortype = field.value.type.VectorType();
711*890232f2SAndroid Build Coastguard Worker 
712*890232f2SAndroid Build Coastguard Worker     if ((vectortype.base_type == BASE_TYPE_STRUCT &&
713*890232f2SAndroid Build Coastguard Worker          field.value.type.struct_def->fixed) &&
714*890232f2SAndroid Build Coastguard Worker         (IsVector(field.value.type) || IsArray(field.value.type))) {
715*890232f2SAndroid Build Coastguard Worker       const auto field_name = namer_.NamespacedType(*vectortype.struct_def);
716*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} static func " +
717*890232f2SAndroid Build Coastguard Worker                namer_.Method("start_vector_of", field_var) +
718*890232f2SAndroid Build Coastguard Worker                "(_ size: Int, in builder: inout "
719*890232f2SAndroid Build Coastguard Worker                "FlatBufferBuilder) {";
720*890232f2SAndroid Build Coastguard Worker       Indent();
721*890232f2SAndroid Build Coastguard Worker       code_ += "builder.startVector(size * MemoryLayout<" + field_name +
722*890232f2SAndroid Build Coastguard Worker                ">.size, elementSize: MemoryLayout<" + field_name +
723*890232f2SAndroid Build Coastguard Worker                ">.alignment)";
724*890232f2SAndroid Build Coastguard Worker       Outdent();
725*890232f2SAndroid Build Coastguard Worker       code_ += "}";
726*890232f2SAndroid Build Coastguard Worker     }
727*890232f2SAndroid Build Coastguard Worker   }
728*890232f2SAndroid Build Coastguard Worker 
GenTableReader(const StructDef & struct_def)729*890232f2SAndroid Build Coastguard Worker   void GenTableReader(const StructDef &struct_def) {
730*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
731*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
732*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
733*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
734*890232f2SAndroid Build Coastguard Worker       GenTableReaderFields(field);
735*890232f2SAndroid Build Coastguard Worker     }
736*890232f2SAndroid Build Coastguard Worker   }
737*890232f2SAndroid Build Coastguard Worker 
GenTableReaderFields(const FieldDef & field)738*890232f2SAndroid Build Coastguard Worker   void GenTableReaderFields(const FieldDef &field) {
739*890232f2SAndroid Build Coastguard Worker     const auto offset = NumToString(field.value.offset);
740*890232f2SAndroid Build Coastguard Worker     const auto field_field = namer_.Field(field);
741*890232f2SAndroid Build Coastguard Worker     const auto type = GenType(field.value.type);
742*890232f2SAndroid Build Coastguard Worker     code_.SetValue("FIELDVAR", namer_.Variable(field));
743*890232f2SAndroid Build Coastguard Worker     code_.SetValue("FIELDMETHOD", namer_.Method(field));
744*890232f2SAndroid Build Coastguard Worker     code_.SetValue("VALUETYPE", type);
745*890232f2SAndroid Build Coastguard Worker     code_.SetValue("OFFSET", namer_.Constant(field.name));
746*890232f2SAndroid Build Coastguard Worker     code_.SetValue("CONSTANT", field.value.constant);
747*890232f2SAndroid Build Coastguard Worker     bool opt_scalar =
748*890232f2SAndroid Build Coastguard Worker         field.IsOptional() && IsScalar(field.value.type.base_type);
749*890232f2SAndroid Build Coastguard Worker     std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}";
750*890232f2SAndroid Build Coastguard Worker     std::string optional = opt_scalar ? "?" : "";
751*890232f2SAndroid Build Coastguard Worker     const auto const_string = "return o == 0 ? " + def_Val + " : ";
752*890232f2SAndroid Build Coastguard Worker     GenComment(field.doc_comment);
753*890232f2SAndroid Build Coastguard Worker     if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
754*890232f2SAndroid Build Coastguard Worker         !IsBool(field.value.type.base_type)) {
755*890232f2SAndroid Build Coastguard Worker       code_ += GenReaderMainBody(optional) + GenOffset() + const_string +
756*890232f2SAndroid Build Coastguard Worker                GenReader("VALUETYPE", "o") + " }";
757*890232f2SAndroid Build Coastguard Worker       if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
758*890232f2SAndroid Build Coastguard Worker       return;
759*890232f2SAndroid Build Coastguard Worker     }
760*890232f2SAndroid Build Coastguard Worker 
761*890232f2SAndroid Build Coastguard Worker     if (IsBool(field.value.type.base_type)) {
762*890232f2SAndroid Build Coastguard Worker       std::string default_value =
763*890232f2SAndroid Build Coastguard Worker           field.IsOptional() ? "nil"
764*890232f2SAndroid Build Coastguard Worker                              : ("0" == field.value.constant ? "false" : "true");
765*890232f2SAndroid Build Coastguard Worker       code_.SetValue("CONSTANT", default_value);
766*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", "Bool");
767*890232f2SAndroid Build Coastguard Worker       code_ += GenReaderMainBody(optional) + "\\";
768*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", "Byte");
769*890232f2SAndroid Build Coastguard Worker       code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " +
770*890232f2SAndroid Build Coastguard Worker                GenReader("VALUETYPE", "o") + " }";
771*890232f2SAndroid Build Coastguard Worker       if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
772*890232f2SAndroid Build Coastguard Worker       return;
773*890232f2SAndroid Build Coastguard Worker     }
774*890232f2SAndroid Build Coastguard Worker 
775*890232f2SAndroid Build Coastguard Worker     if (IsEnum(field.value.type)) {
776*890232f2SAndroid Build Coastguard Worker       const auto default_value =
777*890232f2SAndroid Build Coastguard Worker           field.IsOptional() ? "nil" : GenEnumDefaultValue(field);
778*890232f2SAndroid Build Coastguard Worker       code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
779*890232f2SAndroid Build Coastguard Worker       code_ += GenReaderMainBody(optional) + "\\";
780*890232f2SAndroid Build Coastguard Worker       code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
781*890232f2SAndroid Build Coastguard Worker                GenEnumConstructor("o") + "?? " + default_value + " }";
782*890232f2SAndroid Build Coastguard Worker       if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
783*890232f2SAndroid Build Coastguard Worker         code_ += GenMutate("o", GenOffset(), true);
784*890232f2SAndroid Build Coastguard Worker       return;
785*890232f2SAndroid Build Coastguard Worker     }
786*890232f2SAndroid Build Coastguard Worker 
787*890232f2SAndroid Build Coastguard Worker     const std::string is_required = field.IsRequired() ? "!" : "?";
788*890232f2SAndroid Build Coastguard Worker     const auto required_reader = field.IsRequired() ? "return " : const_string;
789*890232f2SAndroid Build Coastguard Worker 
790*890232f2SAndroid Build Coastguard Worker     if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
791*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", GenType(field.value.type));
792*890232f2SAndroid Build Coastguard Worker       code_.SetValue("CONSTANT", "nil");
793*890232f2SAndroid Build Coastguard Worker       code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
794*890232f2SAndroid Build Coastguard Worker                "{{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, at: o) }";
795*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable("mutable", field_field));
796*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
797*890232f2SAndroid Build Coastguard Worker       code_.SetValue("CONSTANT", "nil");
798*890232f2SAndroid Build Coastguard Worker       code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
799*890232f2SAndroid Build Coastguard Worker                GenConstructor("o + {{ACCESS}}.postion");
800*890232f2SAndroid Build Coastguard Worker       return;
801*890232f2SAndroid Build Coastguard Worker     }
802*890232f2SAndroid Build Coastguard Worker     switch (field.value.type.base_type) {
803*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT:
804*890232f2SAndroid Build Coastguard Worker         code_.SetValue("VALUETYPE", GenType(field.value.type));
805*890232f2SAndroid Build Coastguard Worker         code_.SetValue("CONSTANT", "nil");
806*890232f2SAndroid Build Coastguard Worker         code_ += GenReaderMainBody(is_required) + GenOffset() +
807*890232f2SAndroid Build Coastguard Worker                  required_reader +
808*890232f2SAndroid Build Coastguard Worker                  GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
809*890232f2SAndroid Build Coastguard Worker         break;
810*890232f2SAndroid Build Coastguard Worker 
811*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING: {
812*890232f2SAndroid Build Coastguard Worker         const auto default_string = "\"" + field.value.constant + "\"";
813*890232f2SAndroid Build Coastguard Worker         code_.SetValue("VALUETYPE", GenType(field.value.type));
814*890232f2SAndroid Build Coastguard Worker         code_.SetValue("CONSTANT", field.IsDefault() ? default_string : "nil");
815*890232f2SAndroid Build Coastguard Worker         code_ += GenReaderMainBody(is_required) + GenOffset() +
816*890232f2SAndroid Build Coastguard Worker                  required_reader + "{{ACCESS}}.string(at: o) }";
817*890232f2SAndroid Build Coastguard Worker         code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}SegmentArray: [UInt8]" +
818*890232f2SAndroid Build Coastguard Worker                  is_required +
819*890232f2SAndroid Build Coastguard Worker                  " { return "
820*890232f2SAndroid Build Coastguard Worker                  "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
821*890232f2SAndroid Build Coastguard Worker         break;
822*890232f2SAndroid Build Coastguard Worker       }
823*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
824*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break;
825*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION:
826*890232f2SAndroid Build Coastguard Worker         code_.SetValue("CONSTANT", "nil");
827*890232f2SAndroid Build Coastguard Worker         code_ +=
828*890232f2SAndroid Build Coastguard Worker             "{{ACCESS_TYPE}} func {{FIELDVAR}}<T: "
829*890232f2SAndroid Build Coastguard Worker             "FlatbuffersInitializable>(type: "
830*890232f2SAndroid Build Coastguard Worker             "T.Type) -> T" +
831*890232f2SAndroid Build Coastguard Worker             is_required + " { " + GenOffset() + required_reader +
832*890232f2SAndroid Build Coastguard Worker             "{{ACCESS}}.union(o) }";
833*890232f2SAndroid Build Coastguard Worker         break;
834*890232f2SAndroid Build Coastguard Worker       default: FLATBUFFERS_ASSERT(0);
835*890232f2SAndroid Build Coastguard Worker     }
836*890232f2SAndroid Build Coastguard Worker   }
837*890232f2SAndroid Build Coastguard Worker 
GenTableReaderVectorFields(const FieldDef & field)838*890232f2SAndroid Build Coastguard Worker   void GenTableReaderVectorFields(const FieldDef &field) {
839*890232f2SAndroid Build Coastguard Worker     std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
840*890232f2SAndroid Build Coastguard Worker     const auto vectortype = field.value.type.VectorType();
841*890232f2SAndroid Build Coastguard Worker     code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
842*890232f2SAndroid Build Coastguard Worker     code_.SetValue("HAS_FIELDVAR", namer_.Variable("has", field));
843*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} var {{HAS_FIELDVAR}}: Bool { " + GenOffset() +
844*890232f2SAndroid Build Coastguard Worker              "return o == 0 ? false : true }";
845*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}Count: Int32 { " + GenOffset() +
846*890232f2SAndroid Build Coastguard Worker              "return o == 0 ? 0 : {{ACCESS}}.vector(count: o) }";
847*890232f2SAndroid Build Coastguard Worker     code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) ? "0" : "nil");
848*890232f2SAndroid Build Coastguard Worker     const auto nullable =
849*890232f2SAndroid Build Coastguard Worker         IsScalar(vectortype.base_type) && !IsEnum(vectortype) ? "" : "?";
850*890232f2SAndroid Build Coastguard Worker 
851*890232f2SAndroid Build Coastguard Worker     if (vectortype.base_type != BASE_TYPE_UNION) {
852*890232f2SAndroid Build Coastguard Worker       code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
853*890232f2SAndroid Build Coastguard Worker     } else {
854*890232f2SAndroid Build Coastguard Worker       code_ +=
855*890232f2SAndroid Build Coastguard Worker           "{{ACCESS_TYPE}} func {{FIELDVAR}}<T: FlatbuffersInitializable>(at "
856*890232f2SAndroid Build Coastguard Worker           "index: "
857*890232f2SAndroid Build Coastguard Worker           "Int32, type: T.Type) -> T? { " +
858*890232f2SAndroid Build Coastguard Worker           GenOffset() + "\\";
859*890232f2SAndroid Build Coastguard Worker     }
860*890232f2SAndroid Build Coastguard Worker 
861*890232f2SAndroid Build Coastguard Worker     if (IsBool(vectortype.base_type)) {
862*890232f2SAndroid Build Coastguard Worker       code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
863*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", "Bool");
864*890232f2SAndroid Build Coastguard Worker     }
865*890232f2SAndroid Build Coastguard Worker 
866*890232f2SAndroid Build Coastguard Worker     if (!IsEnum(vectortype)) code_ += const_string + "\\";
867*890232f2SAndroid Build Coastguard Worker 
868*890232f2SAndroid Build Coastguard Worker     if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
869*890232f2SAndroid Build Coastguard Worker         !IsBool(field.value.type.base_type)) {
870*890232f2SAndroid Build Coastguard Worker       code_ +=
871*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
872*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
873*890232f2SAndroid Build Coastguard Worker       code_ +=
874*890232f2SAndroid Build Coastguard Worker           "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}] { return "
875*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }";
876*890232f2SAndroid Build Coastguard Worker       if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
877*890232f2SAndroid Build Coastguard Worker       return;
878*890232f2SAndroid Build Coastguard Worker     }
879*890232f2SAndroid Build Coastguard Worker 
880*890232f2SAndroid Build Coastguard Worker     if (vectortype.base_type == BASE_TYPE_STRUCT &&
881*890232f2SAndroid Build Coastguard Worker         field.value.type.struct_def->fixed) {
882*890232f2SAndroid Build Coastguard Worker       code_ +=
883*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
884*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
885*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDMETHOD", namer_.Method("mutable", field));
886*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
887*890232f2SAndroid Build Coastguard Worker       code_ += GenArrayMainBody(nullable) + GenOffset() + const_string +
888*890232f2SAndroid Build Coastguard Worker                GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
889*890232f2SAndroid Build Coastguard Worker 
890*890232f2SAndroid Build Coastguard Worker       return;
891*890232f2SAndroid Build Coastguard Worker     }
892*890232f2SAndroid Build Coastguard Worker 
893*890232f2SAndroid Build Coastguard Worker     if (IsString(vectortype)) {
894*890232f2SAndroid Build Coastguard Worker       code_ +=
895*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
896*890232f2SAndroid Build Coastguard Worker           "index * {{SIZE}}) }";
897*890232f2SAndroid Build Coastguard Worker       return;
898*890232f2SAndroid Build Coastguard Worker     }
899*890232f2SAndroid Build Coastguard Worker 
900*890232f2SAndroid Build Coastguard Worker     if (IsEnum(vectortype)) {
901*890232f2SAndroid Build Coastguard Worker       code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
902*890232f2SAndroid Build Coastguard Worker       code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
903*890232f2SAndroid Build Coastguard Worker                " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
904*890232f2SAndroid Build Coastguard Worker                "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
905*890232f2SAndroid Build Coastguard Worker                "index * {{SIZE}})) }";
906*890232f2SAndroid Build Coastguard Worker       return;
907*890232f2SAndroid Build Coastguard Worker     }
908*890232f2SAndroid Build Coastguard Worker     if (vectortype.base_type == BASE_TYPE_UNION) {
909*890232f2SAndroid Build Coastguard Worker       code_ +=
910*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
911*890232f2SAndroid Build Coastguard Worker           "index * {{SIZE}}) }";
912*890232f2SAndroid Build Coastguard Worker       return;
913*890232f2SAndroid Build Coastguard Worker     }
914*890232f2SAndroid Build Coastguard Worker 
915*890232f2SAndroid Build Coastguard Worker     if (vectortype.base_type == BASE_TYPE_STRUCT &&
916*890232f2SAndroid Build Coastguard Worker         !field.value.type.struct_def->fixed) {
917*890232f2SAndroid Build Coastguard Worker       code_ += GenConstructor(
918*890232f2SAndroid Build Coastguard Worker           "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
919*890232f2SAndroid Build Coastguard Worker           "{{SIZE}})");
920*890232f2SAndroid Build Coastguard Worker       const auto &sd = *field.value.type.struct_def;
921*890232f2SAndroid Build Coastguard Worker       const auto &fields = sd.fields.vec;
922*890232f2SAndroid Build Coastguard Worker       for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
923*890232f2SAndroid Build Coastguard Worker         const auto &key_field = **kit;
924*890232f2SAndroid Build Coastguard Worker         if (key_field.key) {
925*890232f2SAndroid Build Coastguard Worker           GenByKeyFunctions(key_field);
926*890232f2SAndroid Build Coastguard Worker           break;
927*890232f2SAndroid Build Coastguard Worker         }
928*890232f2SAndroid Build Coastguard Worker       }
929*890232f2SAndroid Build Coastguard Worker     }
930*890232f2SAndroid Build Coastguard Worker   }
931*890232f2SAndroid Build Coastguard Worker 
GenerateCodingKeys(const StructDef & struct_def)932*890232f2SAndroid Build Coastguard Worker   void GenerateCodingKeys(const StructDef &struct_def) {
933*890232f2SAndroid Build Coastguard Worker     code_ += "enum CodingKeys: String, CodingKey {";
934*890232f2SAndroid Build Coastguard Worker     Indent();
935*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
936*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
937*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
938*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
939*890232f2SAndroid Build Coastguard Worker 
940*890232f2SAndroid Build Coastguard Worker       code_.SetValue("RAWVALUENAME", field.name);
941*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
942*890232f2SAndroid Build Coastguard Worker       code_ += "case {{FIELDVAR}} = \"{{RAWVALUENAME}}\"";
943*890232f2SAndroid Build Coastguard Worker     }
944*890232f2SAndroid Build Coastguard Worker     Outdent();
945*890232f2SAndroid Build Coastguard Worker     code_ += "}";
946*890232f2SAndroid Build Coastguard Worker   }
947*890232f2SAndroid Build Coastguard Worker 
GenerateEncoderUnionBody(const FieldDef & field)948*890232f2SAndroid Build Coastguard Worker   void GenerateEncoderUnionBody(const FieldDef &field) {
949*890232f2SAndroid Build Coastguard Worker     EnumDef &union_def = *field.value.type.enum_def;
950*890232f2SAndroid Build Coastguard Worker     const auto is_vector = field.value.type.base_type == BASE_TYPE_VECTOR ||
951*890232f2SAndroid Build Coastguard Worker                            field.value.type.base_type == BASE_TYPE_ARRAY;
952*890232f2SAndroid Build Coastguard Worker     if (field.value.type.base_type == BASE_TYPE_UTYPE ||
953*890232f2SAndroid Build Coastguard Worker         (is_vector &&
954*890232f2SAndroid Build Coastguard Worker          field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
955*890232f2SAndroid Build Coastguard Worker       return;
956*890232f2SAndroid Build Coastguard Worker     if (is_vector) {
957*890232f2SAndroid Build Coastguard Worker       code_ +=
958*890232f2SAndroid Build Coastguard Worker           "var enumsEncoder = container.nestedUnkeyedContainer(forKey: "
959*890232f2SAndroid Build Coastguard Worker           ".{{FIELDVAR}}Type)";
960*890232f2SAndroid Build Coastguard Worker       code_ +=
961*890232f2SAndroid Build Coastguard Worker           "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
962*890232f2SAndroid Build Coastguard Worker           ".{{FIELDVAR}})";
963*890232f2SAndroid Build Coastguard Worker       code_ += "for index in 0..<{{FIELDVAR}}Count {";
964*890232f2SAndroid Build Coastguard Worker       Indent();
965*890232f2SAndroid Build Coastguard Worker       code_ += "guard let type = {{FIELDVAR}}Type(at: index) else { continue }";
966*890232f2SAndroid Build Coastguard Worker       code_ += "try enumsEncoder.encode(type)";
967*890232f2SAndroid Build Coastguard Worker       code_ += "switch type {";
968*890232f2SAndroid Build Coastguard Worker       for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
969*890232f2SAndroid Build Coastguard Worker            ++it) {
970*890232f2SAndroid Build Coastguard Worker         const auto &ev = **it;
971*890232f2SAndroid Build Coastguard Worker         const auto type = GenType(ev.union_type);
972*890232f2SAndroid Build Coastguard Worker         code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
973*890232f2SAndroid Build Coastguard Worker         code_.SetValue("VALUETYPE", type);
974*890232f2SAndroid Build Coastguard Worker         if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
975*890232f2SAndroid Build Coastguard Worker         code_ += "case .{{KEY}}:";
976*890232f2SAndroid Build Coastguard Worker         Indent();
977*890232f2SAndroid Build Coastguard Worker         code_ += "let _v = {{FIELDVAR}}(at: index, type: {{VALUETYPE}}.self)";
978*890232f2SAndroid Build Coastguard Worker         code_ += "try contentEncoder.encode(_v)";
979*890232f2SAndroid Build Coastguard Worker         Outdent();
980*890232f2SAndroid Build Coastguard Worker       }
981*890232f2SAndroid Build Coastguard Worker       code_ += "default: break;";
982*890232f2SAndroid Build Coastguard Worker       code_ += "}";
983*890232f2SAndroid Build Coastguard Worker       Outdent();
984*890232f2SAndroid Build Coastguard Worker       code_ += "}";
985*890232f2SAndroid Build Coastguard Worker       return;
986*890232f2SAndroid Build Coastguard Worker     }
987*890232f2SAndroid Build Coastguard Worker 
988*890232f2SAndroid Build Coastguard Worker     code_ += "switch {{FIELDVAR}}Type {";
989*890232f2SAndroid Build Coastguard Worker     for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
990*890232f2SAndroid Build Coastguard Worker          ++it) {
991*890232f2SAndroid Build Coastguard Worker       const auto &ev = **it;
992*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(ev.union_type);
993*890232f2SAndroid Build Coastguard Worker       code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
994*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", type);
995*890232f2SAndroid Build Coastguard Worker       if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
996*890232f2SAndroid Build Coastguard Worker       code_ += "case .{{KEY}}:";
997*890232f2SAndroid Build Coastguard Worker       Indent();
998*890232f2SAndroid Build Coastguard Worker       code_ += "let _v = {{FIELDVAR}}(type: {{VALUETYPE}}.self)";
999*890232f2SAndroid Build Coastguard Worker       code_ += "try container.encodeIfPresent(_v, forKey: .{{FIELDVAR}})";
1000*890232f2SAndroid Build Coastguard Worker       Outdent();
1001*890232f2SAndroid Build Coastguard Worker     }
1002*890232f2SAndroid Build Coastguard Worker     code_ += "default: break;";
1003*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1004*890232f2SAndroid Build Coastguard Worker   }
1005*890232f2SAndroid Build Coastguard Worker 
GenerateEncoderBody(const StructDef & struct_def)1006*890232f2SAndroid Build Coastguard Worker   void GenerateEncoderBody(const StructDef &struct_def) {
1007*890232f2SAndroid Build Coastguard Worker     code_ += "var container = encoder.container(keyedBy: CodingKeys.self)";
1008*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
1009*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
1010*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
1011*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
1012*890232f2SAndroid Build Coastguard Worker       const auto type = field.value.type;
1013*890232f2SAndroid Build Coastguard Worker 
1014*890232f2SAndroid Build Coastguard Worker       const auto is_non_union_vector =
1015*890232f2SAndroid Build Coastguard Worker           (field.value.type.base_type == BASE_TYPE_ARRAY ||
1016*890232f2SAndroid Build Coastguard Worker            field.value.type.base_type == BASE_TYPE_VECTOR) &&
1017*890232f2SAndroid Build Coastguard Worker           field.value.type.VectorType().base_type != BASE_TYPE_UTYPE;
1018*890232f2SAndroid Build Coastguard Worker 
1019*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
1020*890232f2SAndroid Build Coastguard Worker       code_.SetValue("CONSTANT", field.value.constant);
1021*890232f2SAndroid Build Coastguard Worker       bool should_indent = true;
1022*890232f2SAndroid Build Coastguard Worker       if (is_non_union_vector) {
1023*890232f2SAndroid Build Coastguard Worker         code_ += "if {{FIELDVAR}}Count > 0 {";
1024*890232f2SAndroid Build Coastguard Worker       } else if (IsEnum(type) && !field.IsOptional()) {
1025*890232f2SAndroid Build Coastguard Worker         code_.SetValue("CONSTANT", GenEnumDefaultValue(field));
1026*890232f2SAndroid Build Coastguard Worker         code_ += "if {{FIELDVAR}} != {{CONSTANT}} {";
1027*890232f2SAndroid Build Coastguard Worker       } else if (IsScalar(type.base_type) && !IsEnum(type) &&
1028*890232f2SAndroid Build Coastguard Worker                  !IsBool(type.base_type) && !field.IsOptional()) {
1029*890232f2SAndroid Build Coastguard Worker         code_ += "if {{FIELDVAR}} != {{CONSTANT}} {";
1030*890232f2SAndroid Build Coastguard Worker       } else if (IsBool(type.base_type) && !field.IsOptional()) {
1031*890232f2SAndroid Build Coastguard Worker         std::string default_value =
1032*890232f2SAndroid Build Coastguard Worker             "0" == field.value.constant ? "false" : "true";
1033*890232f2SAndroid Build Coastguard Worker         code_.SetValue("CONSTANT", default_value);
1034*890232f2SAndroid Build Coastguard Worker         code_ += "if {{FIELDVAR}} != {{CONSTANT}} {";
1035*890232f2SAndroid Build Coastguard Worker       } else {
1036*890232f2SAndroid Build Coastguard Worker         should_indent = false;
1037*890232f2SAndroid Build Coastguard Worker       }
1038*890232f2SAndroid Build Coastguard Worker       if (should_indent) Indent();
1039*890232f2SAndroid Build Coastguard Worker 
1040*890232f2SAndroid Build Coastguard Worker       if (IsUnion(type) && !IsEnum(type)) {
1041*890232f2SAndroid Build Coastguard Worker         GenerateEncoderUnionBody(field);
1042*890232f2SAndroid Build Coastguard Worker       } else if (is_non_union_vector &&
1043*890232f2SAndroid Build Coastguard Worker                  (!IsScalar(type.VectorType().base_type) ||
1044*890232f2SAndroid Build Coastguard Worker                   IsEnum(type.VectorType()))) {
1045*890232f2SAndroid Build Coastguard Worker         code_ +=
1046*890232f2SAndroid Build Coastguard Worker             "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
1047*890232f2SAndroid Build Coastguard Worker             ".{{FIELDVAR}})";
1048*890232f2SAndroid Build Coastguard Worker         code_ += "for index in 0..<{{FIELDVAR}}Count {";
1049*890232f2SAndroid Build Coastguard Worker         Indent();
1050*890232f2SAndroid Build Coastguard Worker         code_ += "guard let type = {{FIELDVAR}}(at: index) else { continue }";
1051*890232f2SAndroid Build Coastguard Worker         code_ += "try contentEncoder.encode(type)";
1052*890232f2SAndroid Build Coastguard Worker         Outdent();
1053*890232f2SAndroid Build Coastguard Worker         code_ += "}";
1054*890232f2SAndroid Build Coastguard Worker       } else {
1055*890232f2SAndroid Build Coastguard Worker         code_ +=
1056*890232f2SAndroid Build Coastguard Worker             "try container.encodeIfPresent({{FIELDVAR}}, forKey: "
1057*890232f2SAndroid Build Coastguard Worker             ".{{FIELDVAR}})";
1058*890232f2SAndroid Build Coastguard Worker       }
1059*890232f2SAndroid Build Coastguard Worker       if (should_indent) Outdent();
1060*890232f2SAndroid Build Coastguard Worker 
1061*890232f2SAndroid Build Coastguard Worker       if (is_non_union_vector ||
1062*890232f2SAndroid Build Coastguard Worker           (IsScalar(type.base_type) && !field.IsOptional())) {
1063*890232f2SAndroid Build Coastguard Worker         code_ += "}";
1064*890232f2SAndroid Build Coastguard Worker       }
1065*890232f2SAndroid Build Coastguard Worker     }
1066*890232f2SAndroid Build Coastguard Worker   }
1067*890232f2SAndroid Build Coastguard Worker 
GenerateJSONEncodingAPIs(const StructDef & struct_def)1068*890232f2SAndroid Build Coastguard Worker   void GenerateJSONEncodingAPIs(const StructDef &struct_def) {
1069*890232f2SAndroid Build Coastguard Worker     code_ += "extension {{STRUCTNAME}}: Encodable {";
1070*890232f2SAndroid Build Coastguard Worker     Indent();
1071*890232f2SAndroid Build Coastguard Worker     code_ += "";
1072*890232f2SAndroid Build Coastguard Worker     if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def);
1073*890232f2SAndroid Build Coastguard Worker 
1074*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
1075*890232f2SAndroid Build Coastguard Worker     Indent();
1076*890232f2SAndroid Build Coastguard Worker     if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def);
1077*890232f2SAndroid Build Coastguard Worker     Outdent();
1078*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1079*890232f2SAndroid Build Coastguard Worker     Outdent();
1080*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1081*890232f2SAndroid Build Coastguard Worker     code_ += "";
1082*890232f2SAndroid Build Coastguard Worker   }
1083*890232f2SAndroid Build Coastguard Worker 
GenerateVerifier(const StructDef & struct_def)1084*890232f2SAndroid Build Coastguard Worker   void GenerateVerifier(const StructDef &struct_def) {
1085*890232f2SAndroid Build Coastguard Worker     code_ +=
1086*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func verify<T>(_ verifier: inout Verifier, at "
1087*890232f2SAndroid Build Coastguard Worker         "position: "
1088*890232f2SAndroid Build Coastguard Worker         "Int, of type: T.Type) throws where T: Verifiable {";
1089*890232f2SAndroid Build Coastguard Worker     Indent();
1090*890232f2SAndroid Build Coastguard Worker     code_ += "var _v = try verifier.visitTable(at: position)";
1091*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
1092*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
1093*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
1094*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
1095*890232f2SAndroid Build Coastguard Worker       const auto offset = NumToString(field.value.offset);
1096*890232f2SAndroid Build Coastguard Worker 
1097*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
1098*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", GenerateVerifierType(field));
1099*890232f2SAndroid Build Coastguard Worker       code_.SetValue("OFFSET", namer_.Field(field));
1100*890232f2SAndroid Build Coastguard Worker       code_.SetValue("ISREQUIRED", field.IsRequired() ? "true" : "false");
1101*890232f2SAndroid Build Coastguard Worker 
1102*890232f2SAndroid Build Coastguard Worker       if (IsUnion(field.value.type)) {
1103*890232f2SAndroid Build Coastguard Worker         GenerateUnionTypeVerifier(field);
1104*890232f2SAndroid Build Coastguard Worker         continue;
1105*890232f2SAndroid Build Coastguard Worker       }
1106*890232f2SAndroid Build Coastguard Worker 
1107*890232f2SAndroid Build Coastguard Worker       code_ +=
1108*890232f2SAndroid Build Coastguard Worker           "try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: "
1109*890232f2SAndroid Build Coastguard Worker           "\"{{FIELDVAR}}\", required: {{ISREQUIRED}}, type: "
1110*890232f2SAndroid Build Coastguard Worker           "{{VALUETYPE}}.self)";
1111*890232f2SAndroid Build Coastguard Worker     }
1112*890232f2SAndroid Build Coastguard Worker     code_ += "_v.finish()";
1113*890232f2SAndroid Build Coastguard Worker     Outdent();
1114*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1115*890232f2SAndroid Build Coastguard Worker   }
1116*890232f2SAndroid Build Coastguard Worker 
GenerateUnionTypeVerifier(const FieldDef & field)1117*890232f2SAndroid Build Coastguard Worker   void GenerateUnionTypeVerifier(const FieldDef &field) {
1118*890232f2SAndroid Build Coastguard Worker     const auto is_vector =
1119*890232f2SAndroid Build Coastguard Worker         IsVector(field.value.type) || IsArray(field.value.type);
1120*890232f2SAndroid Build Coastguard Worker     if (field.value.type.base_type == BASE_TYPE_UTYPE ||
1121*890232f2SAndroid Build Coastguard Worker         (is_vector &&
1122*890232f2SAndroid Build Coastguard Worker          field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
1123*890232f2SAndroid Build Coastguard Worker       return;
1124*890232f2SAndroid Build Coastguard Worker     EnumDef &union_def = *field.value.type.enum_def;
1125*890232f2SAndroid Build Coastguard Worker     code_.SetValue("VALUETYPE", namer_.NamespacedType(union_def));
1126*890232f2SAndroid Build Coastguard Worker     code_.SetValue("FUNCTION_NAME", is_vector ? "visitUnionVector" : "visit");
1127*890232f2SAndroid Build Coastguard Worker     code_ +=
1128*890232f2SAndroid Build Coastguard Worker         "try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, "
1129*890232f2SAndroid Build Coastguard Worker         "unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: "
1130*890232f2SAndroid Build Coastguard Worker         "\"{{FIELDVAR}}Type\", fieldName: \"{{FIELDVAR}}\", required: "
1131*890232f2SAndroid Build Coastguard Worker         "{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in";
1132*890232f2SAndroid Build Coastguard Worker     Indent();
1133*890232f2SAndroid Build Coastguard Worker     code_ += "switch key {";
1134*890232f2SAndroid Build Coastguard Worker     for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
1135*890232f2SAndroid Build Coastguard Worker          ++it) {
1136*890232f2SAndroid Build Coastguard Worker       const auto &ev = **it;
1137*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(ev.union_type);
1138*890232f2SAndroid Build Coastguard Worker       code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
1139*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUETYPE", type);
1140*890232f2SAndroid Build Coastguard Worker       code_ += "case .{{KEY}}:";
1141*890232f2SAndroid Build Coastguard Worker       Indent();
1142*890232f2SAndroid Build Coastguard Worker       if (ev.union_type.base_type == BASE_TYPE_NONE) {
1143*890232f2SAndroid Build Coastguard Worker         code_ += "break // NOTE - SWIFT doesnt support none";
1144*890232f2SAndroid Build Coastguard Worker       } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1145*890232f2SAndroid Build Coastguard Worker         code_ +=
1146*890232f2SAndroid Build Coastguard Worker             "try ForwardOffset<String>.verify(&verifier, at: pos, of: "
1147*890232f2SAndroid Build Coastguard Worker             "String.self)";
1148*890232f2SAndroid Build Coastguard Worker       } else {
1149*890232f2SAndroid Build Coastguard Worker         code_.SetValue("MAINTYPE", ev.union_type.struct_def->fixed
1150*890232f2SAndroid Build Coastguard Worker                                        ? type
1151*890232f2SAndroid Build Coastguard Worker                                        : "ForwardOffset<" + type + ">");
1152*890232f2SAndroid Build Coastguard Worker         code_ +=
1153*890232f2SAndroid Build Coastguard Worker             "try {{MAINTYPE}}.verify(&verifier, at: pos, of: "
1154*890232f2SAndroid Build Coastguard Worker             "{{VALUETYPE}}.self)";
1155*890232f2SAndroid Build Coastguard Worker       }
1156*890232f2SAndroid Build Coastguard Worker       Outdent();
1157*890232f2SAndroid Build Coastguard Worker     }
1158*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1159*890232f2SAndroid Build Coastguard Worker     Outdent();
1160*890232f2SAndroid Build Coastguard Worker     code_ += "})";
1161*890232f2SAndroid Build Coastguard Worker   }
1162*890232f2SAndroid Build Coastguard Worker 
GenerateVerifierType(const FieldDef & field)1163*890232f2SAndroid Build Coastguard Worker   std::string GenerateVerifierType(const FieldDef &field) {
1164*890232f2SAndroid Build Coastguard Worker     const auto type = field.value.type;
1165*890232f2SAndroid Build Coastguard Worker     const auto is_vector = IsVector(type) || IsArray(type);
1166*890232f2SAndroid Build Coastguard Worker 
1167*890232f2SAndroid Build Coastguard Worker     if (is_vector) {
1168*890232f2SAndroid Build Coastguard Worker       const auto vector_type = field.value.type.VectorType();
1169*890232f2SAndroid Build Coastguard Worker       return "ForwardOffset<Vector<" +
1170*890232f2SAndroid Build Coastguard Worker              GenerateNestedVerifierTypes(vector_type) + ", " +
1171*890232f2SAndroid Build Coastguard Worker              GenType(vector_type) + ">>";
1172*890232f2SAndroid Build Coastguard Worker     }
1173*890232f2SAndroid Build Coastguard Worker 
1174*890232f2SAndroid Build Coastguard Worker     return GenerateNestedVerifierTypes(field.value.type);
1175*890232f2SAndroid Build Coastguard Worker   }
1176*890232f2SAndroid Build Coastguard Worker 
GenerateNestedVerifierTypes(const Type & type)1177*890232f2SAndroid Build Coastguard Worker   std::string GenerateNestedVerifierTypes(const Type &type) {
1178*890232f2SAndroid Build Coastguard Worker     const auto string_type = GenType(type);
1179*890232f2SAndroid Build Coastguard Worker 
1180*890232f2SAndroid Build Coastguard Worker     if (IsScalar(type.base_type)) { return string_type; }
1181*890232f2SAndroid Build Coastguard Worker 
1182*890232f2SAndroid Build Coastguard Worker     if (IsString(type)) { return "ForwardOffset<" + string_type + ">"; }
1183*890232f2SAndroid Build Coastguard Worker 
1184*890232f2SAndroid Build Coastguard Worker     if (type.struct_def && type.struct_def->fixed) { return string_type; }
1185*890232f2SAndroid Build Coastguard Worker 
1186*890232f2SAndroid Build Coastguard Worker     return "ForwardOffset<" + string_type + ">";
1187*890232f2SAndroid Build Coastguard Worker   }
1188*890232f2SAndroid Build Coastguard Worker 
GenByKeyFunctions(const FieldDef & key_field)1189*890232f2SAndroid Build Coastguard Worker   void GenByKeyFunctions(const FieldDef &key_field) {
1190*890232f2SAndroid Build Coastguard Worker     code_.SetValue("TYPE", GenType(key_field.value.type));
1191*890232f2SAndroid Build Coastguard Worker     code_ +=
1192*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} func {{FIELDVAR}}By(key: {{TYPE}}) -> {{VALUETYPE}}? "
1193*890232f2SAndroid Build Coastguard Worker         "{ \\";
1194*890232f2SAndroid Build Coastguard Worker     code_ += GenOffset() +
1195*890232f2SAndroid Build Coastguard Worker              "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
1196*890232f2SAndroid Build Coastguard Worker              "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
1197*890232f2SAndroid Build Coastguard Worker   }
1198*890232f2SAndroid Build Coastguard Worker 
GenEnum(const EnumDef & enum_def)1199*890232f2SAndroid Build Coastguard Worker   void GenEnum(const EnumDef &enum_def) {
1200*890232f2SAndroid Build Coastguard Worker     if (enum_def.generated) return;
1201*890232f2SAndroid Build Coastguard Worker     const auto is_private_access = enum_def.attributes.Lookup("private");
1202*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ENUM_TYPE",
1203*890232f2SAndroid Build Coastguard Worker                    enum_def.is_union ? "UnionEnum" : "Enum, Verifiable");
1204*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
1205*890232f2SAndroid Build Coastguard Worker     code_.SetValue("ENUM_NAME", namer_.NamespacedType(enum_def));
1206*890232f2SAndroid Build Coastguard Worker     code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1207*890232f2SAndroid Build Coastguard Worker     GenComment(enum_def.doc_comment);
1208*890232f2SAndroid Build Coastguard Worker     code_ +=
1209*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {";
1210*890232f2SAndroid Build Coastguard Worker     Indent();
1211*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
1212*890232f2SAndroid Build Coastguard Worker     if (enum_def.is_union) {
1213*890232f2SAndroid Build Coastguard Worker       code_ += "";
1214*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} init?(value: T) {";
1215*890232f2SAndroid Build Coastguard Worker       Indent();
1216*890232f2SAndroid Build Coastguard Worker       code_ += "self.init(rawValue: value)";
1217*890232f2SAndroid Build Coastguard Worker       Outdent();
1218*890232f2SAndroid Build Coastguard Worker       code_ += "}\n";
1219*890232f2SAndroid Build Coastguard Worker     }
1220*890232f2SAndroid Build Coastguard Worker     code_ +=
1221*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static var byteSize: Int { return "
1222*890232f2SAndroid Build Coastguard Worker         "MemoryLayout<{{BASE_TYPE}}>.size "
1223*890232f2SAndroid Build Coastguard Worker         "}";
1224*890232f2SAndroid Build Coastguard Worker     code_ +=
1225*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
1226*890232f2SAndroid Build Coastguard Worker     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1227*890232f2SAndroid Build Coastguard Worker       const auto &ev = **it;
1228*890232f2SAndroid Build Coastguard Worker       code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
1229*890232f2SAndroid Build Coastguard Worker       code_.SetValue("VALUE", enum_def.ToString(ev));
1230*890232f2SAndroid Build Coastguard Worker       GenComment(ev.doc_comment);
1231*890232f2SAndroid Build Coastguard Worker       code_ += "case {{KEY}} = {{VALUE}}";
1232*890232f2SAndroid Build Coastguard Worker     }
1233*890232f2SAndroid Build Coastguard Worker     code_ += "";
1234*890232f2SAndroid Build Coastguard Worker     AddMinOrMaxEnumValue(namer_.LegacySwiftVariant(*enum_def.MaxValue()),
1235*890232f2SAndroid Build Coastguard Worker                          "max");
1236*890232f2SAndroid Build Coastguard Worker     AddMinOrMaxEnumValue(namer_.LegacySwiftVariant(*enum_def.MinValue()),
1237*890232f2SAndroid Build Coastguard Worker                          "min");
1238*890232f2SAndroid Build Coastguard Worker     Outdent();
1239*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
1240*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.gen_json_coders) EnumEncoder(enum_def);
1241*890232f2SAndroid Build Coastguard Worker     code_ += "";
1242*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api && enum_def.is_union) {
1243*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
1244*890232f2SAndroid Build Coastguard Worker       Indent();
1245*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
1246*890232f2SAndroid Build Coastguard Worker       code_ += "{{ACCESS_TYPE}} var value: NativeObject?";
1247*890232f2SAndroid Build Coastguard Worker       code_ +=
1248*890232f2SAndroid Build Coastguard Worker           "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {";
1249*890232f2SAndroid Build Coastguard Worker       Indent();
1250*890232f2SAndroid Build Coastguard Worker       code_ += "self.type = type";
1251*890232f2SAndroid Build Coastguard Worker       code_ += "self.value = v";
1252*890232f2SAndroid Build Coastguard Worker       Outdent();
1253*890232f2SAndroid Build Coastguard Worker       code_ += "}";
1254*890232f2SAndroid Build Coastguard Worker       code_ +=
1255*890232f2SAndroid Build Coastguard Worker           "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
1256*890232f2SAndroid Build Coastguard Worker           "Offset {";
1257*890232f2SAndroid Build Coastguard Worker       Indent();
1258*890232f2SAndroid Build Coastguard Worker       BuildUnionEnumSwitchCaseWritter(enum_def);
1259*890232f2SAndroid Build Coastguard Worker       Outdent();
1260*890232f2SAndroid Build Coastguard Worker       code_ += "}";
1261*890232f2SAndroid Build Coastguard Worker       Outdent();
1262*890232f2SAndroid Build Coastguard Worker       code_ += "}";
1263*890232f2SAndroid Build Coastguard Worker     }
1264*890232f2SAndroid Build Coastguard Worker   }
1265*890232f2SAndroid Build Coastguard Worker 
EnumEncoder(const EnumDef & enum_def)1266*890232f2SAndroid Build Coastguard Worker   void EnumEncoder(const EnumDef &enum_def) {
1267*890232f2SAndroid Build Coastguard Worker     code_ += "extension {{ENUM_NAME}}: Encodable {";
1268*890232f2SAndroid Build Coastguard Worker     Indent();
1269*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
1270*890232f2SAndroid Build Coastguard Worker     Indent();
1271*890232f2SAndroid Build Coastguard Worker     code_ += "var container = encoder.singleValueContainer()";
1272*890232f2SAndroid Build Coastguard Worker     code_ += "switch self {";
1273*890232f2SAndroid Build Coastguard Worker     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1274*890232f2SAndroid Build Coastguard Worker       const auto &ev = **it;
1275*890232f2SAndroid Build Coastguard Worker       code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
1276*890232f2SAndroid Build Coastguard Worker       code_.SetValue("RAWKEY", ev.name);
1277*890232f2SAndroid Build Coastguard Worker       code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")";
1278*890232f2SAndroid Build Coastguard Worker     }
1279*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1280*890232f2SAndroid Build Coastguard Worker     Outdent();
1281*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1282*890232f2SAndroid Build Coastguard Worker     Outdent();
1283*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1284*890232f2SAndroid Build Coastguard Worker   }
1285*890232f2SAndroid Build Coastguard Worker 
1286*890232f2SAndroid Build Coastguard Worker   // MARK: - Object API
1287*890232f2SAndroid Build Coastguard Worker 
GenerateObjectAPIExtensionHeader(std::string type_name)1288*890232f2SAndroid Build Coastguard Worker   void GenerateObjectAPIExtensionHeader(std::string type_name) {
1289*890232f2SAndroid Build Coastguard Worker     code_ += "\n";
1290*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + type_name + " {";
1291*890232f2SAndroid Build Coastguard Worker     Indent();
1292*890232f2SAndroid Build Coastguard Worker     code_ += "return " + type_name + "(&self)";
1293*890232f2SAndroid Build Coastguard Worker     Outdent();
1294*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1295*890232f2SAndroid Build Coastguard Worker     code_ +=
1296*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1297*890232f2SAndroid Build Coastguard Worker         "obj: "
1298*890232f2SAndroid Build Coastguard Worker         "inout " +
1299*890232f2SAndroid Build Coastguard Worker         type_name + "?) -> Offset {";
1300*890232f2SAndroid Build Coastguard Worker     Indent();
1301*890232f2SAndroid Build Coastguard Worker     code_ += "guard var obj = obj else { return Offset() }";
1302*890232f2SAndroid Build Coastguard Worker     code_ += "return pack(&builder, obj: &obj)";
1303*890232f2SAndroid Build Coastguard Worker     Outdent();
1304*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1305*890232f2SAndroid Build Coastguard Worker     code_ += "";
1306*890232f2SAndroid Build Coastguard Worker     code_ +=
1307*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1308*890232f2SAndroid Build Coastguard Worker         "obj: "
1309*890232f2SAndroid Build Coastguard Worker         "inout " +
1310*890232f2SAndroid Build Coastguard Worker         type_name + ") -> Offset {";
1311*890232f2SAndroid Build Coastguard Worker     Indent();
1312*890232f2SAndroid Build Coastguard Worker   }
1313*890232f2SAndroid Build Coastguard Worker 
GenerateObjectAPIStructConstructor(const StructDef & struct_def)1314*890232f2SAndroid Build Coastguard Worker   void GenerateObjectAPIStructConstructor(const StructDef &struct_def) {
1315*890232f2SAndroid Build Coastguard Worker     code_ +=
1316*890232f2SAndroid Build Coastguard Worker         "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {";
1317*890232f2SAndroid Build Coastguard Worker     Indent();
1318*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
1319*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
1320*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
1321*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
1322*890232f2SAndroid Build Coastguard Worker 
1323*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(field.value.type);
1324*890232f2SAndroid Build Coastguard Worker       code_.SetValue("FIELDVAR", namer_.Variable(field));
1325*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
1326*890232f2SAndroid Build Coastguard Worker         code_ += "var _v{{FIELDVAR}} = _t.{{FIELDVAR}}";
1327*890232f2SAndroid Build Coastguard Worker         code_ += "_{{FIELDVAR}} = _v{{FIELDVAR}}.unpack()";
1328*890232f2SAndroid Build Coastguard Worker         continue;
1329*890232f2SAndroid Build Coastguard Worker       }
1330*890232f2SAndroid Build Coastguard Worker       std::string is_enum = IsEnum(field.value.type) ? ".value" : "";
1331*890232f2SAndroid Build Coastguard Worker       code_ += "_{{FIELDVAR}} = _t.{{FIELDVAR}}" + is_enum;
1332*890232f2SAndroid Build Coastguard Worker     }
1333*890232f2SAndroid Build Coastguard Worker     Outdent();
1334*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
1335*890232f2SAndroid Build Coastguard Worker   }
1336*890232f2SAndroid Build Coastguard Worker 
GenObjectAPI(const StructDef & struct_def)1337*890232f2SAndroid Build Coastguard Worker   void GenObjectAPI(const StructDef &struct_def) {
1338*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} class " +
1339*890232f2SAndroid Build Coastguard Worker              namer_.NamespacedObjectType(struct_def) + ": NativeObject {\n";
1340*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> buffer_constructor;
1341*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> base_constructor;
1342*890232f2SAndroid Build Coastguard Worker     Indent();
1343*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
1344*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
1345*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
1346*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
1347*890232f2SAndroid Build Coastguard Worker       BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
1348*890232f2SAndroid Build Coastguard Worker                                     base_constructor);
1349*890232f2SAndroid Build Coastguard Worker     }
1350*890232f2SAndroid Build Coastguard Worker     code_ += "";
1351*890232f2SAndroid Build Coastguard Worker     BuildObjectConstructor(buffer_constructor,
1352*890232f2SAndroid Build Coastguard Worker                            "_ _t: inout " + namer_.NamespacedType(struct_def));
1353*890232f2SAndroid Build Coastguard Worker     BuildObjectConstructor(base_constructor);
1354*890232f2SAndroid Build Coastguard Worker     if (!struct_def.fixed)
1355*890232f2SAndroid Build Coastguard Worker       code_ +=
1356*890232f2SAndroid Build Coastguard Worker           "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
1357*890232f2SAndroid Build Coastguard Worker           "serialize(type: "
1358*890232f2SAndroid Build Coastguard Worker           "{{STRUCTNAME}}.self) }\n";
1359*890232f2SAndroid Build Coastguard Worker     Outdent();
1360*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1361*890232f2SAndroid Build Coastguard Worker   }
1362*890232f2SAndroid Build Coastguard Worker 
GenerateObjectAPITableExtension(const StructDef & struct_def)1363*890232f2SAndroid Build Coastguard Worker   void GenerateObjectAPITableExtension(const StructDef &struct_def) {
1364*890232f2SAndroid Build Coastguard Worker     GenerateObjectAPIExtensionHeader(namer_.NamespacedObjectType(struct_def));
1365*890232f2SAndroid Build Coastguard Worker     std::vector<std::string> unpack_body;
1366*890232f2SAndroid Build Coastguard Worker     std::string builder = ", &builder)";
1367*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
1368*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
1369*890232f2SAndroid Build Coastguard Worker       const auto &field = **it;
1370*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
1371*890232f2SAndroid Build Coastguard Worker       const auto field_var = namer_.Variable(field);
1372*890232f2SAndroid Build Coastguard Worker       const auto field_field = namer_.Field(field);
1373*890232f2SAndroid Build Coastguard Worker       const auto field_method = namer_.Method(field);
1374*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(field.value.type);
1375*890232f2SAndroid Build Coastguard Worker       std::string check_if_vector =
1376*890232f2SAndroid Build Coastguard Worker           (IsVector(field.value.type) || IsArray(field.value.type))
1377*890232f2SAndroid Build Coastguard Worker               ? "VectorOf("
1378*890232f2SAndroid Build Coastguard Worker               : "(";
1379*890232f2SAndroid Build Coastguard Worker       std::string body = "add" + check_if_vector + field_method + ": ";
1380*890232f2SAndroid Build Coastguard Worker       switch (field.value.type.base_type) {
1381*890232f2SAndroid Build Coastguard Worker         case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1382*890232f2SAndroid Build Coastguard Worker         case BASE_TYPE_VECTOR: {
1383*890232f2SAndroid Build Coastguard Worker           GenerateVectorObjectAPITableExtension(field);
1384*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
1385*890232f2SAndroid Build Coastguard Worker                                 builder);
1386*890232f2SAndroid Build Coastguard Worker           break;
1387*890232f2SAndroid Build Coastguard Worker         }
1388*890232f2SAndroid Build Coastguard Worker         case BASE_TYPE_UNION: {
1389*890232f2SAndroid Build Coastguard Worker           code_ += "let __" + field_var + " = obj." + field_var +
1390*890232f2SAndroid Build Coastguard Worker                    "?.pack(builder: &builder) ?? Offset()";
1391*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("if let o = obj." + field_var + "?.type {");
1392*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("  {{STRUCTNAME}}.add(" + field_var +
1393*890232f2SAndroid Build Coastguard Worker                                 "Type: o" + builder);
1394*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("  {{STRUCTNAME}}." + body + "__" + field_var +
1395*890232f2SAndroid Build Coastguard Worker                                 builder);
1396*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("}\n");
1397*890232f2SAndroid Build Coastguard Worker           break;
1398*890232f2SAndroid Build Coastguard Worker         }
1399*890232f2SAndroid Build Coastguard Worker         case BASE_TYPE_STRUCT: {
1400*890232f2SAndroid Build Coastguard Worker           if (field.value.type.struct_def &&
1401*890232f2SAndroid Build Coastguard Worker               field.value.type.struct_def->fixed) {
1402*890232f2SAndroid Build Coastguard Worker             // This is a Struct (IsStruct), not a table. We create
1403*890232f2SAndroid Build Coastguard Worker             // a native swift object in this case.
1404*890232f2SAndroid Build Coastguard Worker             std::string code;
1405*890232f2SAndroid Build Coastguard Worker             GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
1406*890232f2SAndroid Build Coastguard Worker                                "$0", true);
1407*890232f2SAndroid Build Coastguard Worker             code = code.substr(0, code.size() - 2);
1408*890232f2SAndroid Build Coastguard Worker             unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." +
1409*890232f2SAndroid Build Coastguard Worker                                   field_field + builder);
1410*890232f2SAndroid Build Coastguard Worker           } else {
1411*890232f2SAndroid Build Coastguard Worker             code_ += "let __" + field_var + " = " + type +
1412*890232f2SAndroid Build Coastguard Worker                      ".pack(&builder, obj: &obj." + field_field + ")";
1413*890232f2SAndroid Build Coastguard Worker             unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
1414*890232f2SAndroid Build Coastguard Worker                                   builder);
1415*890232f2SAndroid Build Coastguard Worker           }
1416*890232f2SAndroid Build Coastguard Worker           break;
1417*890232f2SAndroid Build Coastguard Worker         }
1418*890232f2SAndroid Build Coastguard Worker         case BASE_TYPE_STRING: {
1419*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
1420*890232f2SAndroid Build Coastguard Worker                                 builder);
1421*890232f2SAndroid Build Coastguard Worker           if (field.IsRequired()) {
1422*890232f2SAndroid Build Coastguard Worker             code_ += "let __" + field_var + " = builder.create(string: obj." +
1423*890232f2SAndroid Build Coastguard Worker                      field_field + ")";
1424*890232f2SAndroid Build Coastguard Worker           } else {
1425*890232f2SAndroid Build Coastguard Worker             BuildingOptionalObjects(field_field, "builder.create(string: s)");
1426*890232f2SAndroid Build Coastguard Worker           }
1427*890232f2SAndroid Build Coastguard Worker           break;
1428*890232f2SAndroid Build Coastguard Worker         }
1429*890232f2SAndroid Build Coastguard Worker         case BASE_TYPE_UTYPE: break;
1430*890232f2SAndroid Build Coastguard Worker         default:
1431*890232f2SAndroid Build Coastguard Worker           unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." +
1432*890232f2SAndroid Build Coastguard Worker                                 field_field + builder);
1433*890232f2SAndroid Build Coastguard Worker       }
1434*890232f2SAndroid Build Coastguard Worker     }
1435*890232f2SAndroid Build Coastguard Worker     code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
1436*890232f2SAndroid Build Coastguard Worker     for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
1437*890232f2SAndroid Build Coastguard Worker       code_ += *it;
1438*890232f2SAndroid Build Coastguard Worker     code_ +=
1439*890232f2SAndroid Build Coastguard Worker         "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
1440*890232f2SAndroid Build Coastguard Worker         "__root)";
1441*890232f2SAndroid Build Coastguard Worker     Outdent();
1442*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1443*890232f2SAndroid Build Coastguard Worker   }
1444*890232f2SAndroid Build Coastguard Worker 
GenerateVectorObjectAPITableExtension(const FieldDef & field_def)1445*890232f2SAndroid Build Coastguard Worker   void GenerateVectorObjectAPITableExtension(const FieldDef &field_def) {
1446*890232f2SAndroid Build Coastguard Worker     const Type &field_type = field_def.value.type;
1447*890232f2SAndroid Build Coastguard Worker     const auto type = GenType(field_type);
1448*890232f2SAndroid Build Coastguard Worker     const auto var = namer_.Variable(field_def);
1449*890232f2SAndroid Build Coastguard Worker     const auto field = namer_.Field(field_def);
1450*890232f2SAndroid Build Coastguard Worker 
1451*890232f2SAndroid Build Coastguard Worker     const auto vectortype = field_type.VectorType();
1452*890232f2SAndroid Build Coastguard Worker     switch (vectortype.base_type) {
1453*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION: {
1454*890232f2SAndroid Build Coastguard Worker         code_ += "var __" + var + "__: [Offset] = []";
1455*890232f2SAndroid Build Coastguard Worker         code_ += "for i in obj." + var + " {";
1456*890232f2SAndroid Build Coastguard Worker         Indent();
1457*890232f2SAndroid Build Coastguard Worker         code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
1458*890232f2SAndroid Build Coastguard Worker         code_ += "__" + var + "__.append(off)";
1459*890232f2SAndroid Build Coastguard Worker         Outdent();
1460*890232f2SAndroid Build Coastguard Worker         code_ += "}";
1461*890232f2SAndroid Build Coastguard Worker         code_ += "let __" + var + " = builder.createVector(ofOffsets: __" +
1462*890232f2SAndroid Build Coastguard Worker                  var + "__)";
1463*890232f2SAndroid Build Coastguard Worker         code_ += "let __" + var + "Type = builder.createVector(obj." + field +
1464*890232f2SAndroid Build Coastguard Worker                  ".compactMap { $0?.type })";
1465*890232f2SAndroid Build Coastguard Worker         break;
1466*890232f2SAndroid Build Coastguard Worker       }
1467*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UTYPE: break;
1468*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT: {
1469*890232f2SAndroid Build Coastguard Worker         if (field_type.struct_def && !field_type.struct_def->fixed) {
1470*890232f2SAndroid Build Coastguard Worker           code_ += "var __" + var + "__: [Offset] = []";
1471*890232f2SAndroid Build Coastguard Worker           code_ += "for var i in obj." + var + " {";
1472*890232f2SAndroid Build Coastguard Worker           Indent();
1473*890232f2SAndroid Build Coastguard Worker           code_ +=
1474*890232f2SAndroid Build Coastguard Worker               "__" + var + "__.append(" + type + ".pack(&builder, obj: &i))";
1475*890232f2SAndroid Build Coastguard Worker           Outdent();
1476*890232f2SAndroid Build Coastguard Worker           code_ += "}";
1477*890232f2SAndroid Build Coastguard Worker           code_ += "let __" + var + " = builder.createVector(ofOffsets: __" +
1478*890232f2SAndroid Build Coastguard Worker                    var + "__)";
1479*890232f2SAndroid Build Coastguard Worker         } else {
1480*890232f2SAndroid Build Coastguard Worker           code_ += "{{STRUCTNAME}}." + namer_.Method("start_vector_of", var) +
1481*890232f2SAndroid Build Coastguard Worker                    "(obj." + field + ".count, in: &builder)";
1482*890232f2SAndroid Build Coastguard Worker           std::string code;
1483*890232f2SAndroid Build Coastguard Worker           GenerateStructArgs(*field_type.struct_def, &code, "", "", "_o", true);
1484*890232f2SAndroid Build Coastguard Worker           code = code.substr(0, code.size() - 2);
1485*890232f2SAndroid Build Coastguard Worker           code_ += "for i in obj." + field + " {";
1486*890232f2SAndroid Build Coastguard Worker           Indent();
1487*890232f2SAndroid Build Coastguard Worker           code_ += "guard let _o = i else { continue }";
1488*890232f2SAndroid Build Coastguard Worker           code_ += "builder.create(struct: _o)";
1489*890232f2SAndroid Build Coastguard Worker           Outdent();
1490*890232f2SAndroid Build Coastguard Worker           code_ += "}";
1491*890232f2SAndroid Build Coastguard Worker           code_ += "let __" + var + " = builder.endVector(len: obj." + field +
1492*890232f2SAndroid Build Coastguard Worker                    ".count)";
1493*890232f2SAndroid Build Coastguard Worker         }
1494*890232f2SAndroid Build Coastguard Worker         break;
1495*890232f2SAndroid Build Coastguard Worker       }
1496*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING: {
1497*890232f2SAndroid Build Coastguard Worker         code_ += "let __" + var + " = builder.createVector(ofStrings: obj." +
1498*890232f2SAndroid Build Coastguard Worker                  var + ".compactMap({ $0 }) )";
1499*890232f2SAndroid Build Coastguard Worker         break;
1500*890232f2SAndroid Build Coastguard Worker       }
1501*890232f2SAndroid Build Coastguard Worker       default: {
1502*890232f2SAndroid Build Coastguard Worker         code_ += "let __" + var + " = builder.createVector(obj." + field + ")";
1503*890232f2SAndroid Build Coastguard Worker         break;
1504*890232f2SAndroid Build Coastguard Worker       }
1505*890232f2SAndroid Build Coastguard Worker     }
1506*890232f2SAndroid Build Coastguard Worker   }
1507*890232f2SAndroid Build Coastguard Worker 
BuildingOptionalObjects(const std::string & var,const std::string & body_front)1508*890232f2SAndroid Build Coastguard Worker   void BuildingOptionalObjects(const std::string &var,
1509*890232f2SAndroid Build Coastguard Worker                                const std::string &body_front) {
1510*890232f2SAndroid Build Coastguard Worker     code_ += "let __" + var + ": Offset";
1511*890232f2SAndroid Build Coastguard Worker     code_ += "if let s = obj." + var + " {";
1512*890232f2SAndroid Build Coastguard Worker     Indent();
1513*890232f2SAndroid Build Coastguard Worker     code_ += "__" + var + " = " + body_front;
1514*890232f2SAndroid Build Coastguard Worker     Outdent();
1515*890232f2SAndroid Build Coastguard Worker     code_ += "} else {";
1516*890232f2SAndroid Build Coastguard Worker     Indent();
1517*890232f2SAndroid Build Coastguard Worker     code_ += "__" + var + " = Offset()";
1518*890232f2SAndroid Build Coastguard Worker     Outdent();
1519*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1520*890232f2SAndroid Build Coastguard Worker     code_ += "";
1521*890232f2SAndroid Build Coastguard Worker   }
1522*890232f2SAndroid Build Coastguard Worker 
BuildObjectConstructor(const std::vector<std::string> & body,const std::string & header="")1523*890232f2SAndroid Build Coastguard Worker   void BuildObjectConstructor(const std::vector<std::string> &body,
1524*890232f2SAndroid Build Coastguard Worker                               const std::string &header = "") {
1525*890232f2SAndroid Build Coastguard Worker     code_.SetValue("HEADER", header);
1526*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
1527*890232f2SAndroid Build Coastguard Worker     Indent();
1528*890232f2SAndroid Build Coastguard Worker     for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
1529*890232f2SAndroid Build Coastguard Worker     Outdent();
1530*890232f2SAndroid Build Coastguard Worker     code_ += "}\n";
1531*890232f2SAndroid Build Coastguard Worker   }
1532*890232f2SAndroid Build Coastguard Worker 
BuildObjectAPIConstructorBody(const FieldDef & field,bool is_fixed,std::vector<std::string> & buffer_constructor,std::vector<std::string> & base_constructor)1533*890232f2SAndroid Build Coastguard Worker   void BuildObjectAPIConstructorBody(
1534*890232f2SAndroid Build Coastguard Worker       const FieldDef &field, bool is_fixed,
1535*890232f2SAndroid Build Coastguard Worker       std::vector<std::string> &buffer_constructor,
1536*890232f2SAndroid Build Coastguard Worker       std::vector<std::string> &base_constructor) {
1537*890232f2SAndroid Build Coastguard Worker     const auto field_field = namer_.Field(field);
1538*890232f2SAndroid Build Coastguard Worker     const auto field_var = namer_.Variable(field);
1539*890232f2SAndroid Build Coastguard Worker     const auto type = GenType(field.value.type);
1540*890232f2SAndroid Build Coastguard Worker     code_.SetValue("FIELDVAR", field_field);
1541*890232f2SAndroid Build Coastguard Worker     code_.SetValue("VALUETYPE", type);
1542*890232f2SAndroid Build Coastguard Worker     std::string is_required = field.IsRequired() ? "" : "?";
1543*890232f2SAndroid Build Coastguard Worker 
1544*890232f2SAndroid Build Coastguard Worker     switch (field.value.type.base_type) {
1545*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT: {
1546*890232f2SAndroid Build Coastguard Worker         const auto objtype = GenType(field.value.type, true);
1547*890232f2SAndroid Build Coastguard Worker         code_.SetValue("VALUETYPE", objtype);
1548*890232f2SAndroid Build Coastguard Worker         const auto optional =
1549*890232f2SAndroid Build Coastguard Worker             (field.value.type.struct_def && field.value.type.struct_def->fixed);
1550*890232f2SAndroid Build Coastguard Worker         std::string question_mark =
1551*890232f2SAndroid Build Coastguard Worker             (field.IsRequired() || (optional && is_fixed) ? "" : "?");
1552*890232f2SAndroid Build Coastguard Worker 
1553*890232f2SAndroid Build Coastguard Worker         code_ +=
1554*890232f2SAndroid Build Coastguard Worker             "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + question_mark;
1555*890232f2SAndroid Build Coastguard Worker         base_constructor.push_back("" + field_var + " = " + objtype + "()");
1556*890232f2SAndroid Build Coastguard Worker 
1557*890232f2SAndroid Build Coastguard Worker         if (field.value.type.struct_def->fixed) {
1558*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back("" + field_var + " = _t." + field_field);
1559*890232f2SAndroid Build Coastguard Worker         } else {
1560*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back("var __" + field_var + " = _t." +
1561*890232f2SAndroid Build Coastguard Worker                                        field_field);
1562*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back(
1563*890232f2SAndroid Build Coastguard Worker               "" + field_var + " = __" + field_var +
1564*890232f2SAndroid Build Coastguard Worker               (field.IsRequired() ? "!" : question_mark) + ".unpack()");
1565*890232f2SAndroid Build Coastguard Worker         }
1566*890232f2SAndroid Build Coastguard Worker         break;
1567*890232f2SAndroid Build Coastguard Worker       }
1568*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1569*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR: {
1570*890232f2SAndroid Build Coastguard Worker         BuildObjectAPIConstructorBodyVectors(field, buffer_constructor,
1571*890232f2SAndroid Build Coastguard Worker                                              base_constructor, "    ");
1572*890232f2SAndroid Build Coastguard Worker         break;
1573*890232f2SAndroid Build Coastguard Worker       }
1574*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING: {
1575*890232f2SAndroid Build Coastguard Worker         code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: String" + is_required;
1576*890232f2SAndroid Build Coastguard Worker         buffer_constructor.push_back(field_var + " = _t." + field_field);
1577*890232f2SAndroid Build Coastguard Worker 
1578*890232f2SAndroid Build Coastguard Worker         if (field.IsRequired()) {
1579*890232f2SAndroid Build Coastguard Worker           std::string default_value =
1580*890232f2SAndroid Build Coastguard Worker               field.IsDefault() ? field.value.constant : "";
1581*890232f2SAndroid Build Coastguard Worker           base_constructor.push_back(field_var + " = \"" + default_value +
1582*890232f2SAndroid Build Coastguard Worker                                      "\"");
1583*890232f2SAndroid Build Coastguard Worker           break;
1584*890232f2SAndroid Build Coastguard Worker         }
1585*890232f2SAndroid Build Coastguard Worker         if (field.IsDefault() && !field.IsRequired()) {
1586*890232f2SAndroid Build Coastguard Worker           std::string value = field.IsDefault() ? field.value.constant : "nil";
1587*890232f2SAndroid Build Coastguard Worker           base_constructor.push_back(field_var + " = \"" + value + "\"");
1588*890232f2SAndroid Build Coastguard Worker         }
1589*890232f2SAndroid Build Coastguard Worker         break;
1590*890232f2SAndroid Build Coastguard Worker       }
1591*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UTYPE: break;
1592*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION: {
1593*890232f2SAndroid Build Coastguard Worker         BuildUnionEnumSwitchCase(*field.value.type.enum_def, field_var,
1594*890232f2SAndroid Build Coastguard Worker                                  buffer_constructor);
1595*890232f2SAndroid Build Coastguard Worker         break;
1596*890232f2SAndroid Build Coastguard Worker       }
1597*890232f2SAndroid Build Coastguard Worker       default: {
1598*890232f2SAndroid Build Coastguard Worker         buffer_constructor.push_back(field_var + " = _t." + field_field);
1599*890232f2SAndroid Build Coastguard Worker         std::string nullable = field.IsOptional() ? "?" : "";
1600*890232f2SAndroid Build Coastguard Worker         if (IsScalar(field.value.type.base_type) &&
1601*890232f2SAndroid Build Coastguard Worker             !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
1602*890232f2SAndroid Build Coastguard Worker           code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + nullable;
1603*890232f2SAndroid Build Coastguard Worker           if (!field.IsOptional())
1604*890232f2SAndroid Build Coastguard Worker             base_constructor.push_back(field_var + " = " +
1605*890232f2SAndroid Build Coastguard Worker                                        field.value.constant);
1606*890232f2SAndroid Build Coastguard Worker           break;
1607*890232f2SAndroid Build Coastguard Worker         }
1608*890232f2SAndroid Build Coastguard Worker 
1609*890232f2SAndroid Build Coastguard Worker         if (IsEnum(field.value.type)) {
1610*890232f2SAndroid Build Coastguard Worker           const auto default_value = IsEnum(field.value.type)
1611*890232f2SAndroid Build Coastguard Worker                                          ? GenEnumDefaultValue(field)
1612*890232f2SAndroid Build Coastguard Worker                                          : field.value.constant;
1613*890232f2SAndroid Build Coastguard Worker           code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}";
1614*890232f2SAndroid Build Coastguard Worker           base_constructor.push_back(field_var + " = " + default_value);
1615*890232f2SAndroid Build Coastguard Worker           break;
1616*890232f2SAndroid Build Coastguard Worker         }
1617*890232f2SAndroid Build Coastguard Worker 
1618*890232f2SAndroid Build Coastguard Worker         if (IsBool(field.value.type.base_type)) {
1619*890232f2SAndroid Build Coastguard Worker           code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: Bool" + nullable;
1620*890232f2SAndroid Build Coastguard Worker           std::string default_value =
1621*890232f2SAndroid Build Coastguard Worker               "0" == field.value.constant ? "false" : "true";
1622*890232f2SAndroid Build Coastguard Worker           if (!field.IsOptional())
1623*890232f2SAndroid Build Coastguard Worker             base_constructor.push_back(field_var + " = " + default_value);
1624*890232f2SAndroid Build Coastguard Worker         }
1625*890232f2SAndroid Build Coastguard Worker       }
1626*890232f2SAndroid Build Coastguard Worker     }
1627*890232f2SAndroid Build Coastguard Worker   }
1628*890232f2SAndroid Build Coastguard Worker 
BuildObjectAPIConstructorBodyVectors(const FieldDef & field,std::vector<std::string> & buffer_constructor,std::vector<std::string> & base_constructor,const std::string & indentation)1629*890232f2SAndroid Build Coastguard Worker   void BuildObjectAPIConstructorBodyVectors(
1630*890232f2SAndroid Build Coastguard Worker       const FieldDef &field, std::vector<std::string> &buffer_constructor,
1631*890232f2SAndroid Build Coastguard Worker       std::vector<std::string> &base_constructor,
1632*890232f2SAndroid Build Coastguard Worker       const std::string &indentation) {
1633*890232f2SAndroid Build Coastguard Worker     const auto vectortype = field.value.type.VectorType();
1634*890232f2SAndroid Build Coastguard Worker     const auto field_var = namer_.Field(field);
1635*890232f2SAndroid Build Coastguard Worker     const auto field_field = namer_.Field(field);
1636*890232f2SAndroid Build Coastguard Worker 
1637*890232f2SAndroid Build Coastguard Worker     if (vectortype.base_type != BASE_TYPE_UTYPE) {
1638*890232f2SAndroid Build Coastguard Worker       buffer_constructor.push_back(field_var + " = []");
1639*890232f2SAndroid Build Coastguard Worker       buffer_constructor.push_back("for index in 0..<_t." + field_field +
1640*890232f2SAndroid Build Coastguard Worker                                    "Count {");
1641*890232f2SAndroid Build Coastguard Worker       base_constructor.push_back(field_var + " = []");
1642*890232f2SAndroid Build Coastguard Worker     }
1643*890232f2SAndroid Build Coastguard Worker 
1644*890232f2SAndroid Build Coastguard Worker     switch (vectortype.base_type) {
1645*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT: {
1646*890232f2SAndroid Build Coastguard Worker         code_.SetValue("VALUETYPE", GenType(vectortype, true));
1647*890232f2SAndroid Build Coastguard Worker         code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}?]";
1648*890232f2SAndroid Build Coastguard Worker         if (!vectortype.struct_def->fixed) {
1649*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back(indentation + "var __v_ = _t." +
1650*890232f2SAndroid Build Coastguard Worker                                        field_field + "(at: index)");
1651*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back(indentation + field_var +
1652*890232f2SAndroid Build Coastguard Worker                                        ".append(__v_?.unpack())");
1653*890232f2SAndroid Build Coastguard Worker         } else {
1654*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1655*890232f2SAndroid Build Coastguard Worker                                        field_var + "(at: index))");
1656*890232f2SAndroid Build Coastguard Worker         }
1657*890232f2SAndroid Build Coastguard Worker         break;
1658*890232f2SAndroid Build Coastguard Worker       }
1659*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1660*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR: {
1661*890232f2SAndroid Build Coastguard Worker         break;
1662*890232f2SAndroid Build Coastguard Worker       }
1663*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION: {
1664*890232f2SAndroid Build Coastguard Worker         BuildUnionEnumSwitchCase(*field.value.type.enum_def, field_var,
1665*890232f2SAndroid Build Coastguard Worker                                  buffer_constructor, indentation, true);
1666*890232f2SAndroid Build Coastguard Worker         break;
1667*890232f2SAndroid Build Coastguard Worker       }
1668*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UTYPE: break;
1669*890232f2SAndroid Build Coastguard Worker       default: {
1670*890232f2SAndroid Build Coastguard Worker         code_.SetValue(
1671*890232f2SAndroid Build Coastguard Worker             "VALUETYPE",
1672*890232f2SAndroid Build Coastguard Worker             (IsString(vectortype) ? "String?" : GenType(vectortype)));
1673*890232f2SAndroid Build Coastguard Worker         code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}]";
1674*890232f2SAndroid Build Coastguard Worker 
1675*890232f2SAndroid Build Coastguard Worker         if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
1676*890232f2SAndroid Build Coastguard Worker           const auto default_value = IsEnum(field.value.type)
1677*890232f2SAndroid Build Coastguard Worker                                          ? GenEnumDefaultValue(field)
1678*890232f2SAndroid Build Coastguard Worker                                          : field.value.constant;
1679*890232f2SAndroid Build Coastguard Worker           buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1680*890232f2SAndroid Build Coastguard Worker                                        field_field + "(at: index)!)");
1681*890232f2SAndroid Build Coastguard Worker           break;
1682*890232f2SAndroid Build Coastguard Worker         }
1683*890232f2SAndroid Build Coastguard Worker         buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1684*890232f2SAndroid Build Coastguard Worker                                      field_field + "(at: index))");
1685*890232f2SAndroid Build Coastguard Worker         break;
1686*890232f2SAndroid Build Coastguard Worker       }
1687*890232f2SAndroid Build Coastguard Worker     }
1688*890232f2SAndroid Build Coastguard Worker     if (vectortype.base_type != BASE_TYPE_UTYPE)
1689*890232f2SAndroid Build Coastguard Worker       buffer_constructor.push_back("}");
1690*890232f2SAndroid Build Coastguard Worker   }
1691*890232f2SAndroid Build Coastguard Worker 
BuildUnionEnumSwitchCaseWritter(const EnumDef & ed)1692*890232f2SAndroid Build Coastguard Worker   void BuildUnionEnumSwitchCaseWritter(const EnumDef &ed) {
1693*890232f2SAndroid Build Coastguard Worker     code_ += "switch type {";
1694*890232f2SAndroid Build Coastguard Worker     for (auto it = ed.Vals().begin(); it < ed.Vals().end(); ++it) {
1695*890232f2SAndroid Build Coastguard Worker       const auto ev = **it;
1696*890232f2SAndroid Build Coastguard Worker       const auto variant = namer_.LegacySwiftVariant(ev);
1697*890232f2SAndroid Build Coastguard Worker       const auto type = GenType(ev.union_type);
1698*890232f2SAndroid Build Coastguard Worker       const auto is_struct = IsStruct(ev.union_type) ? type + Mutable() : type;
1699*890232f2SAndroid Build Coastguard Worker       if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1700*890232f2SAndroid Build Coastguard Worker       code_ += "case ." + variant + ":";
1701*890232f2SAndroid Build Coastguard Worker       Indent();
1702*890232f2SAndroid Build Coastguard Worker       code_ += "var __obj = value as? " + GenType(ev.union_type, true);
1703*890232f2SAndroid Build Coastguard Worker       code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)";
1704*890232f2SAndroid Build Coastguard Worker       Outdent();
1705*890232f2SAndroid Build Coastguard Worker     }
1706*890232f2SAndroid Build Coastguard Worker     code_ += "default: return Offset()";
1707*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1708*890232f2SAndroid Build Coastguard Worker   }
1709*890232f2SAndroid Build Coastguard Worker 
BuildUnionEnumSwitchCase(const EnumDef & ed,const std::string & field,std::vector<std::string> & buffer_constructor,const std::string & indentation="",const bool is_vector=false)1710*890232f2SAndroid Build Coastguard Worker   void BuildUnionEnumSwitchCase(const EnumDef &ed, const std::string &field,
1711*890232f2SAndroid Build Coastguard Worker                                 std::vector<std::string> &buffer_constructor,
1712*890232f2SAndroid Build Coastguard Worker                                 const std::string &indentation = "",
1713*890232f2SAndroid Build Coastguard Worker                                 const bool is_vector = false) {
1714*890232f2SAndroid Build Coastguard Worker     const auto ns_type = namer_.NamespacedType(ed);
1715*890232f2SAndroid Build Coastguard Worker     code_.SetValue("VALUETYPE", ns_type);
1716*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: \\";
1717*890232f2SAndroid Build Coastguard Worker     code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
1718*890232f2SAndroid Build Coastguard Worker 
1719*890232f2SAndroid Build Coastguard Worker     const auto vector_reader = is_vector ? "(at: index" : "";
1720*890232f2SAndroid Build Coastguard Worker     buffer_constructor.push_back(indentation + "switch _t." + field + "Type" +
1721*890232f2SAndroid Build Coastguard Worker                                  vector_reader + (is_vector ? ")" : "") + " {");
1722*890232f2SAndroid Build Coastguard Worker 
1723*890232f2SAndroid Build Coastguard Worker     for (auto it = ed.Vals().begin(); it < ed.Vals().end(); ++it) {
1724*890232f2SAndroid Build Coastguard Worker       const auto ev = **it;
1725*890232f2SAndroid Build Coastguard Worker       const auto variant = namer_.LegacySwiftVariant(ev);
1726*890232f2SAndroid Build Coastguard Worker       if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1727*890232f2SAndroid Build Coastguard Worker       const auto type = IsStruct(ev.union_type)
1728*890232f2SAndroid Build Coastguard Worker                             ? GenType(ev.union_type) + Mutable()
1729*890232f2SAndroid Build Coastguard Worker                             : GenType(ev.union_type);
1730*890232f2SAndroid Build Coastguard Worker       buffer_constructor.push_back(indentation + "case ." + variant + ":");
1731*890232f2SAndroid Build Coastguard Worker       buffer_constructor.push_back(
1732*890232f2SAndroid Build Coastguard Worker           indentation + "  var _v = _t." + field + (is_vector ? "" : "(") +
1733*890232f2SAndroid Build Coastguard Worker           vector_reader + (is_vector ? ", " : "") + "type: " + type + ".self)");
1734*890232f2SAndroid Build Coastguard Worker       const auto constructor =
1735*890232f2SAndroid Build Coastguard Worker           ns_type + "Union(_v?.unpack(), type: ." + variant + ")";
1736*890232f2SAndroid Build Coastguard Worker       buffer_constructor.push_back(
1737*890232f2SAndroid Build Coastguard Worker           indentation + "  " + field +
1738*890232f2SAndroid Build Coastguard Worker           (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
1739*890232f2SAndroid Build Coastguard Worker     }
1740*890232f2SAndroid Build Coastguard Worker     buffer_constructor.push_back(indentation + "default: break");
1741*890232f2SAndroid Build Coastguard Worker     buffer_constructor.push_back(indentation + "}");
1742*890232f2SAndroid Build Coastguard Worker   }
1743*890232f2SAndroid Build Coastguard Worker 
AddMinOrMaxEnumValue(const std::string & str,const std::string & type)1744*890232f2SAndroid Build Coastguard Worker   void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
1745*890232f2SAndroid Build Coastguard Worker     const auto current_value = str;
1746*890232f2SAndroid Build Coastguard Worker     code_.SetValue(type, current_value);
1747*890232f2SAndroid Build Coastguard Worker     code_ += "{{ACCESS_TYPE}} static var " + type +
1748*890232f2SAndroid Build Coastguard Worker              ": {{ENUM_NAME}} { return .{{" + type + "}} }";
1749*890232f2SAndroid Build Coastguard Worker   }
1750*890232f2SAndroid Build Coastguard Worker 
GenLookup(const FieldDef & key_field,const std::string & struct_type)1751*890232f2SAndroid Build Coastguard Worker   void GenLookup(const FieldDef &key_field, const std::string &struct_type) {
1752*890232f2SAndroid Build Coastguard Worker     code_.SetValue("STRUCTTYPE", struct_type);
1753*890232f2SAndroid Build Coastguard Worker     code_.SetValue("OFFSET", NumToString(key_field.value.offset));
1754*890232f2SAndroid Build Coastguard Worker     std::string offset_reader =
1755*890232f2SAndroid Build Coastguard Worker         "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
1756*890232f2SAndroid Build Coastguard Worker         "fbb: fbb)";
1757*890232f2SAndroid Build Coastguard Worker 
1758*890232f2SAndroid Build Coastguard Worker     code_.SetValue("TYPE", GenType(key_field.value.type));
1759*890232f2SAndroid Build Coastguard Worker     code_ +=
1760*890232f2SAndroid Build Coastguard Worker         "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
1761*890232f2SAndroid Build Coastguard Worker         "fbb: "
1762*890232f2SAndroid Build Coastguard Worker         "ByteBuffer) -> {{STRUCTTYPE}}? {";
1763*890232f2SAndroid Build Coastguard Worker     Indent();
1764*890232f2SAndroid Build Coastguard Worker     if (IsString(key_field.value.type))
1765*890232f2SAndroid Build Coastguard Worker       code_ += "let key = key.utf8.map { $0 }";
1766*890232f2SAndroid Build Coastguard Worker     code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
1767*890232f2SAndroid Build Coastguard Worker     code_ += "var start: Int32 = 0";
1768*890232f2SAndroid Build Coastguard Worker     code_ += "while span != 0 {";
1769*890232f2SAndroid Build Coastguard Worker     Indent();
1770*890232f2SAndroid Build Coastguard Worker     code_ += "var middle = span / 2";
1771*890232f2SAndroid Build Coastguard Worker     code_ +=
1772*890232f2SAndroid Build Coastguard Worker         "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
1773*890232f2SAndroid Build Coastguard Worker     if (IsString(key_field.value.type)) {
1774*890232f2SAndroid Build Coastguard Worker       code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
1775*890232f2SAndroid Build Coastguard Worker     } else {
1776*890232f2SAndroid Build Coastguard Worker       code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
1777*890232f2SAndroid Build Coastguard Worker                offset_reader + "))";
1778*890232f2SAndroid Build Coastguard Worker     }
1779*890232f2SAndroid Build Coastguard Worker 
1780*890232f2SAndroid Build Coastguard Worker     code_ += "if comp > 0 {";
1781*890232f2SAndroid Build Coastguard Worker     Indent();
1782*890232f2SAndroid Build Coastguard Worker     code_ += "span = middle";
1783*890232f2SAndroid Build Coastguard Worker     Outdent();
1784*890232f2SAndroid Build Coastguard Worker     code_ += "} else if comp < 0 {";
1785*890232f2SAndroid Build Coastguard Worker     Indent();
1786*890232f2SAndroid Build Coastguard Worker     code_ += "middle += 1";
1787*890232f2SAndroid Build Coastguard Worker     code_ += "start += middle";
1788*890232f2SAndroid Build Coastguard Worker     code_ += "span -= middle";
1789*890232f2SAndroid Build Coastguard Worker     Outdent();
1790*890232f2SAndroid Build Coastguard Worker     code_ += "} else {";
1791*890232f2SAndroid Build Coastguard Worker     Indent();
1792*890232f2SAndroid Build Coastguard Worker     code_ += "return {{STRUCTTYPE}}(fbb, o: tableOffset)";
1793*890232f2SAndroid Build Coastguard Worker     Outdent();
1794*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1795*890232f2SAndroid Build Coastguard Worker     Outdent();
1796*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1797*890232f2SAndroid Build Coastguard Worker     code_ += "return nil";
1798*890232f2SAndroid Build Coastguard Worker     Outdent();
1799*890232f2SAndroid Build Coastguard Worker     code_ += "}";
1800*890232f2SAndroid Build Coastguard Worker   }
1801*890232f2SAndroid Build Coastguard Worker 
GenPadding(const FieldDef & field,int * id)1802*890232f2SAndroid Build Coastguard Worker   inline void GenPadding(const FieldDef &field, int *id) {
1803*890232f2SAndroid Build Coastguard Worker     if (field.padding) {
1804*890232f2SAndroid Build Coastguard Worker       for (int i = 0; i < 4; i++) {
1805*890232f2SAndroid Build Coastguard Worker         if (static_cast<int>(field.padding) & (1 << i)) {
1806*890232f2SAndroid Build Coastguard Worker           const auto bits = (1 << i) * 8;
1807*890232f2SAndroid Build Coastguard Worker           code_ += "private let padding" + NumToString((*id)++) + "__: UInt" +
1808*890232f2SAndroid Build Coastguard Worker                    NumToString(bits) + " = 0";
1809*890232f2SAndroid Build Coastguard Worker         }
1810*890232f2SAndroid Build Coastguard Worker       }
1811*890232f2SAndroid Build Coastguard Worker       FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
1812*890232f2SAndroid Build Coastguard Worker     }
1813*890232f2SAndroid Build Coastguard Worker   }
1814*890232f2SAndroid Build Coastguard Worker 
GenComment(const std::vector<std::string> & dc)1815*890232f2SAndroid Build Coastguard Worker   void GenComment(const std::vector<std::string> &dc) {
1816*890232f2SAndroid Build Coastguard Worker     if (dc.begin() == dc.end()) {
1817*890232f2SAndroid Build Coastguard Worker       // Don't output empty comment blocks with 0 lines of comment content.
1818*890232f2SAndroid Build Coastguard Worker       return;
1819*890232f2SAndroid Build Coastguard Worker     }
1820*890232f2SAndroid Build Coastguard Worker     for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
1821*890232f2SAndroid Build Coastguard Worker   }
1822*890232f2SAndroid Build Coastguard Worker 
GenOffset()1823*890232f2SAndroid Build Coastguard Worker   std::string GenOffset() {
1824*890232f2SAndroid Build Coastguard Worker     return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
1825*890232f2SAndroid Build Coastguard Worker   }
1826*890232f2SAndroid Build Coastguard Worker 
GenReaderMainBody(const std::string & optional="")1827*890232f2SAndroid Build Coastguard Worker   std::string GenReaderMainBody(const std::string &optional = "") {
1828*890232f2SAndroid Build Coastguard Worker     return "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + optional + " { ";
1829*890232f2SAndroid Build Coastguard Worker   }
1830*890232f2SAndroid Build Coastguard Worker 
GenReader(const std::string & type,const std::string & at="{{OFFSET}}")1831*890232f2SAndroid Build Coastguard Worker   std::string GenReader(const std::string &type,
1832*890232f2SAndroid Build Coastguard Worker                         const std::string &at = "{{OFFSET}}") {
1833*890232f2SAndroid Build Coastguard Worker     return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
1834*890232f2SAndroid Build Coastguard Worker   }
1835*890232f2SAndroid Build Coastguard Worker 
GenConstructor(const std::string & offset)1836*890232f2SAndroid Build Coastguard Worker   std::string GenConstructor(const std::string &offset) {
1837*890232f2SAndroid Build Coastguard Worker     return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
1838*890232f2SAndroid Build Coastguard Worker   }
1839*890232f2SAndroid Build Coastguard Worker 
GenMutate(const std::string & offset,const std::string & get_offset,bool isRaw=false)1840*890232f2SAndroid Build Coastguard Worker   std::string GenMutate(const std::string &offset,
1841*890232f2SAndroid Build Coastguard Worker                         const std::string &get_offset, bool isRaw = false) {
1842*890232f2SAndroid Build Coastguard Worker     return "@discardableResult {{ACCESS_TYPE}} func mutate({{FIELDVAR}}: "
1843*890232f2SAndroid Build Coastguard Worker            "{{VALUETYPE}}) -> Bool {" +
1844*890232f2SAndroid Build Coastguard Worker            get_offset + " return {{ACCESS}}.mutate({{FIELDVAR}}" +
1845*890232f2SAndroid Build Coastguard Worker            (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
1846*890232f2SAndroid Build Coastguard Worker   }
1847*890232f2SAndroid Build Coastguard Worker 
GenMutateArray()1848*890232f2SAndroid Build Coastguard Worker   std::string GenMutateArray() {
1849*890232f2SAndroid Build Coastguard Worker     return "{{ACCESS_TYPE}} func mutate({{FIELDVAR}}: {{VALUETYPE}}, at "
1850*890232f2SAndroid Build Coastguard Worker            "index: Int32) -> Bool { " +
1851*890232f2SAndroid Build Coastguard Worker            GenOffset() +
1852*890232f2SAndroid Build Coastguard Worker            "return {{ACCESS}}.directMutate({{FIELDVAR}}, index: "
1853*890232f2SAndroid Build Coastguard Worker            "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
1854*890232f2SAndroid Build Coastguard Worker   }
1855*890232f2SAndroid Build Coastguard Worker 
GenEnumDefaultValue(const FieldDef & field)1856*890232f2SAndroid Build Coastguard Worker   std::string GenEnumDefaultValue(const FieldDef &field) {
1857*890232f2SAndroid Build Coastguard Worker     const auto &value = field.value;
1858*890232f2SAndroid Build Coastguard Worker     FLATBUFFERS_ASSERT(value.type.enum_def);
1859*890232f2SAndroid Build Coastguard Worker     const auto &enum_def = *value.type.enum_def;
1860*890232f2SAndroid Build Coastguard Worker     // Vector of enum defaults are always "[]" which never works.
1861*890232f2SAndroid Build Coastguard Worker     const std::string constant = IsVector(value.type) ? "0" : value.constant;
1862*890232f2SAndroid Build Coastguard Worker     const auto enum_val = enum_def.FindByValue(constant);
1863*890232f2SAndroid Build Coastguard Worker     if (enum_val) {
1864*890232f2SAndroid Build Coastguard Worker       return "." + namer_.LegacySwiftVariant(*enum_val);
1865*890232f2SAndroid Build Coastguard Worker     } else {
1866*890232f2SAndroid Build Coastguard Worker       const auto &ev = **enum_def.Vals().begin();
1867*890232f2SAndroid Build Coastguard Worker       return "." + namer_.LegacySwiftVariant(ev);
1868*890232f2SAndroid Build Coastguard Worker     }
1869*890232f2SAndroid Build Coastguard Worker   }
1870*890232f2SAndroid Build Coastguard Worker 
GenEnumConstructor(const std::string & at)1871*890232f2SAndroid Build Coastguard Worker   std::string GenEnumConstructor(const std::string &at) {
1872*890232f2SAndroid Build Coastguard Worker     return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
1873*890232f2SAndroid Build Coastguard Worker   }
1874*890232f2SAndroid Build Coastguard Worker 
ValidateFunc()1875*890232f2SAndroid Build Coastguard Worker   std::string ValidateFunc() {
1876*890232f2SAndroid Build Coastguard Worker     return "static func validateVersion() { FlatBuffersVersion_2_0_0() }";
1877*890232f2SAndroid Build Coastguard Worker   }
1878*890232f2SAndroid Build Coastguard Worker 
GenType(const Type & type,const bool should_consider_suffix=false) const1879*890232f2SAndroid Build Coastguard Worker   std::string GenType(const Type &type,
1880*890232f2SAndroid Build Coastguard Worker                       const bool should_consider_suffix = false) const {
1881*890232f2SAndroid Build Coastguard Worker     return IsScalar(type.base_type) ? GenTypeBasic(type)
1882*890232f2SAndroid Build Coastguard Worker            : IsArray(type)          ? GenType(type.VectorType())
1883*890232f2SAndroid Build Coastguard Worker                            : GenTypePointer(type, should_consider_suffix);
1884*890232f2SAndroid Build Coastguard Worker   }
1885*890232f2SAndroid Build Coastguard Worker 
GenTypePointer(const Type & type,const bool should_consider_suffix) const1886*890232f2SAndroid Build Coastguard Worker   std::string GenTypePointer(const Type &type,
1887*890232f2SAndroid Build Coastguard Worker                              const bool should_consider_suffix) const {
1888*890232f2SAndroid Build Coastguard Worker     switch (type.base_type) {
1889*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING: return "String";
1890*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR: return GenType(type.VectorType());
1891*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT: {
1892*890232f2SAndroid Build Coastguard Worker         const auto &sd = *type.struct_def;
1893*890232f2SAndroid Build Coastguard Worker         if (should_consider_suffix && !sd.fixed) {
1894*890232f2SAndroid Build Coastguard Worker           return namer_.NamespacedObjectType(sd);
1895*890232f2SAndroid Build Coastguard Worker         }
1896*890232f2SAndroid Build Coastguard Worker         return namer_.NamespacedType(sd);
1897*890232f2SAndroid Build Coastguard Worker       }
1898*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION:
1899*890232f2SAndroid Build Coastguard Worker       default: return "FlatbuffersInitializable";
1900*890232f2SAndroid Build Coastguard Worker     }
1901*890232f2SAndroid Build Coastguard Worker   }
1902*890232f2SAndroid Build Coastguard Worker 
GenTypeBasic(const Type & type) const1903*890232f2SAndroid Build Coastguard Worker   std::string GenTypeBasic(const Type &type) const {
1904*890232f2SAndroid Build Coastguard Worker     return GenTypeBasic(type, true);
1905*890232f2SAndroid Build Coastguard Worker   }
1906*890232f2SAndroid Build Coastguard Worker 
Indent()1907*890232f2SAndroid Build Coastguard Worker   void Indent() { code_.IncrementIdentLevel(); }
1908*890232f2SAndroid Build Coastguard Worker 
Outdent()1909*890232f2SAndroid Build Coastguard Worker   void Outdent() { code_.DecrementIdentLevel(); }
1910*890232f2SAndroid Build Coastguard Worker 
GenTypeBasic(const Type & type,bool can_override) const1911*890232f2SAndroid Build Coastguard Worker   std::string GenTypeBasic(const Type &type, bool can_override) const {
1912*890232f2SAndroid Build Coastguard Worker     // clang-format off
1913*890232f2SAndroid Build Coastguard Worker     static const char * const swift_type[] = {
1914*890232f2SAndroid Build Coastguard Worker       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1915*890232f2SAndroid Build Coastguard Worker               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
1916*890232f2SAndroid Build Coastguard Worker         #STYPE,
1917*890232f2SAndroid Build Coastguard Worker         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1918*890232f2SAndroid Build Coastguard Worker       #undef FLATBUFFERS_TD
1919*890232f2SAndroid Build Coastguard Worker     };
1920*890232f2SAndroid Build Coastguard Worker     // clang-format on
1921*890232f2SAndroid Build Coastguard Worker     if (can_override) {
1922*890232f2SAndroid Build Coastguard Worker       if (type.enum_def) return namer_.NamespacedType(*type.enum_def);
1923*890232f2SAndroid Build Coastguard Worker       if (type.base_type == BASE_TYPE_BOOL) return "Bool";
1924*890232f2SAndroid Build Coastguard Worker     }
1925*890232f2SAndroid Build Coastguard Worker     return swift_type[static_cast<int>(type.base_type)];
1926*890232f2SAndroid Build Coastguard Worker   }
1927*890232f2SAndroid Build Coastguard Worker 
Mutable() const1928*890232f2SAndroid Build Coastguard Worker   std::string Mutable() const { return "_Mutable"; }
1929*890232f2SAndroid Build Coastguard Worker 
1930*890232f2SAndroid Build Coastguard Worker   IdlNamer namer_;
1931*890232f2SAndroid Build Coastguard Worker };
1932*890232f2SAndroid Build Coastguard Worker }  // namespace swift
GenerateSwift(const Parser & parser,const std::string & path,const std::string & file_name)1933*890232f2SAndroid Build Coastguard Worker bool GenerateSwift(const Parser &parser, const std::string &path,
1934*890232f2SAndroid Build Coastguard Worker                    const std::string &file_name) {
1935*890232f2SAndroid Build Coastguard Worker   swift::SwiftGenerator generator(parser, path, file_name);
1936*890232f2SAndroid Build Coastguard Worker   return generator.generate();
1937*890232f2SAndroid Build Coastguard Worker }
1938*890232f2SAndroid Build Coastguard Worker }  // namespace flatbuffers
1939