blob: b3baa281a55692808dd4dc5e59592eb0555b1eff [file] [log] [blame]
Austin Schuh272c6132020-11-14 16:37:52 -08001/*
2 * Copyright 2020 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <cctype>
18#include <unordered_set>
19
20#include "flatbuffers/code_generators.h"
21#include "flatbuffers/flatbuffers.h"
22#include "flatbuffers/idl.h"
23#include "flatbuffers/util.h"
Austin Schuh2dd86a92022-09-14 21:19:23 -070024#include "idl_namer.h"
Austin Schuh272c6132020-11-14 16:37:52 -080025
26namespace flatbuffers {
27
28namespace swift {
29
Austin Schuh2dd86a92022-09-14 21:19:23 -070030namespace {
31
32static Namer::Config SwiftDefaultConfig() {
33 return { /*types=*/Case::kKeep,
34 /*constants=*/Case::kLowerCamel,
35 /*methods=*/Case::kLowerCamel,
36 /*functions=*/Case::kLowerCamel,
37 /*fields=*/Case::kLowerCamel,
38 /*variables=*/Case::kLowerCamel,
39 /*variants=*/Case::kLowerCamel,
40 /*enum_variant_seperator=*/".",
41 /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
42 /*namespaces=*/Case::kKeep,
43 /*namespace_seperator=*/"_",
44 /*object_prefix=*/"",
45 /*object_suffix=*/"T",
46 /*keyword_prefix=*/"",
47 /*keyword_suffix=*/"_",
48 /*filenames=*/Case::kKeep,
49 /*directories=*/Case::kKeep,
50 /*output_path=*/"",
51 /*filename_suffix=*/"_generated",
52 /*filename_extension=*/".swift" };
53}
54
55static std::set<std::string> SwiftKeywords() {
56 return {
57 "associatedtype",
58 "class",
59 "deinit",
60 "enum",
61 "extension",
62 "fileprivate",
63 "func",
64 "import",
65 "init",
66 "inout",
67 "internal",
68 "let",
69 "open",
70 "operator",
71 "private",
72 "protocol",
73 "public",
74 "rethrows",
75 "static",
76 "struct",
77 "subscript",
78 "typealias",
79 "var",
80 "break",
81 "case",
82 "continue",
83 "default",
84 "defer",
85 "do",
86 "else",
87 "fallthrough",
88 "for",
89 "guard",
90 "if",
91 "in",
92 "repeat",
93 "return",
94 "switch",
95 "where",
96 "while",
97 "Any",
98 "catch",
99 "false",
100 "is",
101 "nil",
102 "super",
103 "self",
104 "Self",
105 "throw",
106 "throws",
107 "true",
108 "try",
109 "associativity",
110 "convenience",
111 "dynamic",
112 "didSet",
113 "final",
114 "get",
115 "infix",
116 "indirect",
117 "lazy",
118 "left",
119 "mutating",
120 "none",
121 "nonmutating",
122 "optional",
123 "override",
124 "postfix",
125 "precedence",
126 "prefix",
127 "Protocol",
128 "required",
129 "right",
130 "set",
131 "Type",
132 "unowned",
133 "weak",
134 "willSet",
135 "Void",
136 };
137}
138
139static std::string GenIndirect(const std::string &reading) {
Austin Schuh272c6132020-11-14 16:37:52 -0800140 return "{{ACCESS}}.indirect(" + reading + ")";
141}
142
Austin Schuh2dd86a92022-09-14 21:19:23 -0700143static std::string GenArrayMainBody(const std::string &optional) {
144 return "{{ACCESS_TYPE}} func {{FIELDMETHOD}}(at index: Int32) -> "
Austin Schuh272c6132020-11-14 16:37:52 -0800145 "{{VALUETYPE}}" +
146 optional + " { ";
147}
148
Austin Schuh2dd86a92022-09-14 21:19:23 -0700149} // namespace
150
Austin Schuh272c6132020-11-14 16:37:52 -0800151class SwiftGenerator : public BaseGenerator {
152 private:
153 CodeWriter code_;
154 std::unordered_set<std::string> keywords_;
155 int namespace_depth;
156
157 public:
158 SwiftGenerator(const Parser &parser, const std::string &path,
159 const std::string &file_name)
Austin Schuh2dd86a92022-09-14 21:19:23 -0700160 : BaseGenerator(parser, path, file_name, "", "_", "swift"),
161 namer_(WithFlagOptions(SwiftDefaultConfig(), parser.opts, path),
162 SwiftKeywords()) {
Austin Schuh272c6132020-11-14 16:37:52 -0800163 namespace_depth = 0;
Austin Schuh58b9b472020-11-25 19:12:44 -0800164 code_.SetPadding(" ");
Austin Schuh272c6132020-11-14 16:37:52 -0800165 }
166
167 bool generate() {
168 code_.Clear();
169 code_.SetValue("ACCESS", "_accessor");
170 code_.SetValue("TABLEOFFSET", "VTOFFSET");
171 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
Austin Schuh58b9b472020-11-25 19:12:44 -0800172 code_ += "// swiftlint:disable all";
173 code_ += "// swiftformat:disable all\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700174 if (parser_.opts.include_dependence_headers || parser_.opts.generate_all) {
175 if (parser_.opts.swift_implementation_only)
176 code_ += "@_implementationOnly \\";
Austin Schuh272c6132020-11-14 16:37:52 -0800177
Austin Schuh2dd86a92022-09-14 21:19:23 -0700178 code_ += "import FlatBuffers\n";
179 }
180
181 // Generate code for all the enum declarations.
Austin Schuh272c6132020-11-14 16:37:52 -0800182 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
183 ++it) {
184 const auto &enum_def = **it;
185 if (!enum_def.generated) { GenEnum(enum_def); }
186 }
187
188 for (auto it = parser_.structs_.vec.begin();
189 it != parser_.structs_.vec.end(); ++it) {
190 const auto &struct_def = **it;
191 if (struct_def.fixed && !struct_def.generated) {
192 GenStructReader(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700193 GenMutableStructReader(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800194 }
195 }
196
197 for (auto it = parser_.structs_.vec.begin();
198 it != parser_.structs_.vec.end(); ++it) {
199 const auto &struct_def = **it;
200 if (!struct_def.fixed && !struct_def.generated) {
201 GenTable(struct_def);
202 if (parser_.opts.generate_object_based_api) {
203 GenObjectAPI(struct_def);
204 }
205 }
206 }
207
208 const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
209 const auto final_code = code_.ToString();
210 return SaveFile(filename.c_str(), final_code, false);
211 }
212
213 void mark(const std::string &str) {
214 code_.SetValue("MARKVALUE", str);
215 code_ += "\n// MARK: - {{MARKVALUE}}\n";
216 }
217
James Kuszmaul8e62b022022-03-22 09:33:25 -0700218 // MARK: - Generating structs
219
220 // Generates the reader for swift
221 void GenStructReader(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700222 const bool is_private_access =
223 parser_.opts.swift_implementation_only ||
224 struct_def.attributes.Lookup("private") != nullptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700225 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
226 GenComment(struct_def.doc_comment);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700227 code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700228 code_ +=
229 "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable, "
230 "FlatbuffersInitializable\\";
231 if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\";
232 code_ += " {";
233 code_ += "";
234 Indent();
235 code_ += ValidateFunc();
236 code_ += "";
237 int padding_id = 0;
238 std::string constructor = "";
239 std::vector<std::string> base_constructor;
240 std::vector<std::string> main_constructor;
241
242 for (auto it = struct_def.fields.vec.begin();
243 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700244 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700245 if (field.deprecated) continue;
246
247 if (!constructor.empty()) constructor += ", ";
248
Austin Schuh2dd86a92022-09-14 21:19:23 -0700249 const auto field_var = namer_.Variable(field);
250 const auto type = GenType(field.value.type);
251 code_.SetValue("FIELDVAR", field_var);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700252 if (IsEnum(field.value.type)) {
253 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
254 }
255 code_.SetValue("VALUETYPE", type);
256 GenComment(field.doc_comment);
257 std::string valueType =
258 IsEnum(field.value.type) ? "{{BASEVALUE}}" : "{{VALUETYPE}}";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700259 code_ += "private var _{{FIELDVAR}}: " + valueType;
260 const auto accessing_value = IsEnum(field.value.type) ? ".value" : "";
261 const auto is_bool = IsBool(field.value.type.base_type);
262 const auto base_value =
263 IsStruct(field.value.type) ? (type + "()")
264 : is_bool ? ("0" == field.value.constant ? "false" : "true")
265 : field.value.constant;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700266
Austin Schuh2dd86a92022-09-14 21:19:23 -0700267 main_constructor.push_back("_" + field_var + " = " + field_var +
268 accessing_value);
269 base_constructor.push_back("_" + field_var + " = " + base_value);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700270
271 if (field.padding) { GenPadding(field, &padding_id); }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700272 constructor += field_var + ": " + type;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700273 }
274 code_ += "";
275 BuildStructConstructor(struct_def);
276 BuildObjectConstructor(main_constructor, constructor);
277 BuildObjectConstructor(base_constructor, "");
278
279 if (parser_.opts.generate_object_based_api)
280 GenerateObjectAPIStructConstructor(struct_def);
281
282 for (auto it = struct_def.fields.vec.begin();
283 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700284 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700285 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700286 code_.SetValue("FIELDVAR", namer_.Variable(field));
287 code_.SetValue("VALUETYPE", GenType(field.value.type));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700288 GenComment(field.doc_comment);
289 if (!IsEnum(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700290 code_ += GenReaderMainBody() + "_{{FIELDVAR}} }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700291 } else if (IsEnum(field.value.type)) {
292 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700293 GenReaderMainBody() + "{{VALUETYPE}}(rawValue: _{{FIELDVAR}})! }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700294 }
295 }
296 code_ += "";
297 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700298 "{{ACCESS_TYPE}} static func verify<T>(_ verifier: inout Verifier, at "
299 "position: "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700300 "Int, of type: T.Type) throws where T: Verifiable {";
301 Indent();
302 code_ +=
303 "try verifier.inBuffer(position: position, of: {{STRUCTNAME}}.self)";
304 Outdent();
305 code_ += "}";
306 Outdent();
307 code_ += "}\n";
308 if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
309 }
310
311 void BuildStructConstructor(const StructDef &struct_def) {
312 code_ += "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) {";
313 Indent();
314 code_ += "let {{ACCESS}} = Struct(bb: bb, position: o)";
315 for (auto it = struct_def.fields.vec.begin();
316 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700317 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700318 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700319 const auto type = field.value.type;
320 code_.SetValue("FIELDVAR", namer_.Variable(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700321 code_.SetValue("VALUETYPE", GenType(type));
322 code_.SetValue("OFFSET", NumToString(field.value.offset));
323 if (IsScalar(type.base_type)) {
324 if (IsEnum(type))
325 code_.SetValue("VALUETYPE", GenTypeBasic(field.value.type, false));
326 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700327 "_{{FIELDVAR}} = {{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700328 "at: {{OFFSET}})";
329 } else {
330 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700331 "_{{FIELDVAR}} = {{VALUETYPE}}({{ACCESS}}.bb, o: "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700332 "{{ACCESS}}.postion + {{OFFSET}})";
333 }
334 }
335 Outdent();
336 code_ += "}\n";
337 }
338
339 void GenMutableStructReader(const StructDef &struct_def) {
340 GenObjectHeader(struct_def);
341
342 for (auto it = struct_def.fields.vec.begin();
343 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700344 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700345 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700346 const auto offset = NumToString(field.value.offset);
347 const auto type = GenType(field.value.type);
348 code_.SetValue("FIELDVAR", namer_.Variable(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700349 if (IsEnum(field.value.type)) {
350 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
351 }
352 code_.SetValue("VALUETYPE", type);
353 code_.SetValue("OFFSET", offset);
354 if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
355 code_ +=
356 GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
357 } else if (IsEnum(field.value.type)) {
358 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
359 code_ += GenReaderMainBody() + "return " +
360 GenEnumConstructor("{{OFFSET}}") + "?? " +
361 GenEnumDefaultValue(field) + " }";
362 } else if (IsStruct(field.value.type)) {
363 code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
364 code_ += GenReaderMainBody() + "return " +
365 GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
366 }
367 if (parser_.opts.mutable_buffer && !IsStruct(field.value.type))
368 code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type));
369 }
370
371 if (parser_.opts.generate_object_based_api) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700372 GenerateObjectAPIExtensionHeader(namer_.NamespacedType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700373 code_ += "return builder.create(struct: obj)";
374 Outdent();
375 code_ += "}";
376 }
377 Outdent();
378 code_ += "}\n";
379 }
380
Austin Schuh272c6132020-11-14 16:37:52 -0800381 // Generates the create function for swift
382 void GenStructWriter(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700383 const bool is_private_access =
384 parser_.opts.swift_implementation_only ||
385 struct_def.attributes.Lookup("private") != nullptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800386 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
Austin Schuh2dd86a92022-09-14 21:19:23 -0700387 code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
388 code_.SetValue("SHORT_STRUCTNAME", namer_.Method(struct_def));
Austin Schuh272c6132020-11-14 16:37:52 -0800389 code_ += "extension {{STRUCTNAME}} {";
390 Indent();
391 code_ += "@discardableResult";
392 code_ +=
393 "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout "
394 "FlatBufferBuilder, \\";
395 std::string func_header = "";
396 GenerateStructArgs(struct_def, &func_header, "", "");
397 code_ += func_header.substr(0, func_header.size() - 2) + "\\";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700398 code_ += ") -> Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -0800399 Indent();
400 code_ +=
401 "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
402 "{{STRUCTNAME}}.alignment)";
Austin Schuh272c6132020-11-14 16:37:52 -0800403 code_ += "return builder.endStruct()";
404 Outdent();
405 code_ += "}\n";
406 Outdent();
407 code_ += "}\n";
408 }
409
Austin Schuh272c6132020-11-14 16:37:52 -0800410 void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
411 const std::string &nameprefix,
412 const std::string &object_name,
413 const std::string &obj_api_named = "",
414 bool is_obj_api = false) {
415 auto &code = *code_ptr;
416 for (auto it = struct_def.fields.vec.begin();
417 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700418 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -0800419 if (field.deprecated) continue;
420 const auto &field_type = field.value.type;
421 if (IsStruct(field.value.type)) {
422 GenerateStructArgs(
423 *field_type.struct_def, code_ptr, (nameprefix + field.name),
424 (object_name + "." + field.name), obj_api_named, is_obj_api);
425 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700426 const auto field_var = namer_.Variable(field);
427 const auto field_field = namer_.Field(field);
428 const auto type = GenType(field.value.type);
Austin Schuh272c6132020-11-14 16:37:52 -0800429 if (!is_obj_api) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700430 code += nameprefix + field_var + ": " + type;
Austin Schuh272c6132020-11-14 16:37:52 -0800431 if (!IsEnum(field.value.type)) {
432 code += " = ";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700433 const auto is_bool = IsBool(field.value.type.base_type);
434 const auto constant =
Austin Schuh272c6132020-11-14 16:37:52 -0800435 is_bool ? ("0" == field.value.constant ? "false" : "true")
436 : field.value.constant;
437 code += constant;
438 }
439 code += ", ";
440 continue;
441 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700442 code += nameprefix + field_var + ": " + obj_api_named + object_name +
443 "." + field_field;
Austin Schuh272c6132020-11-14 16:37:52 -0800444 code += ", ";
445 }
446 }
447 }
448
James Kuszmaul8e62b022022-03-22 09:33:25 -0700449 // MARK: - Table Generator
Austin Schuh272c6132020-11-14 16:37:52 -0800450
451 // Generates the reader for swift
452 void GenTable(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700453 const bool is_private_access =
454 parser_.opts.swift_implementation_only ||
455 struct_def.attributes.Lookup("private") != nullptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800456 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
Austin Schuh272c6132020-11-14 16:37:52 -0800457 GenObjectHeader(struct_def);
458 GenTableAccessors(struct_def);
459 GenTableReader(struct_def);
460 GenTableWriter(struct_def);
461 if (parser_.opts.generate_object_based_api)
462 GenerateObjectAPITableExtension(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700463 code_ += "";
464 GenerateVerifier(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800465 Outdent();
466 code_ += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700467 if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800468 }
469
470 // Generates the reader for swift
471 void GenTableAccessors(const StructDef &struct_def) {
472 // Generate field id constants.
473 if (struct_def.fields.vec.size() > 0) {
474 code_ += "private enum {{TABLEOFFSET}}: VOffset {";
475 Indent();
476 for (auto it = struct_def.fields.vec.begin();
477 it != struct_def.fields.vec.end(); ++it) {
478 const auto &field = **it;
479 if (field.deprecated) { continue; }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700480 code_.SetValue("OFFSET_NAME", namer_.Variable(field));
Austin Schuh272c6132020-11-14 16:37:52 -0800481 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
482 code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
483 }
484 code_ += "var v: Int32 { Int32(self.rawValue) }";
485 code_ += "var p: VOffset { self.rawValue }";
486 Outdent();
487 code_ += "}";
488 code_ += "";
489 }
490 }
491
James Kuszmaul8e62b022022-03-22 09:33:25 -0700492 void GenObjectHeader(const StructDef &struct_def) {
493 GenComment(struct_def.doc_comment);
Austin Schuh272c6132020-11-14 16:37:52 -0800494
Austin Schuh2dd86a92022-09-14 21:19:23 -0700495 code_.SetValue("SHORT_STRUCTNAME", namer_.Type(struct_def));
496 code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700497 code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
498 code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : "");
499 code_ +=
500 "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\";
501 if (!struct_def.fixed) code_ += ", Verifiable\\";
502 if (!struct_def.fixed && parser_.opts.generate_object_based_api)
503 code_ += ", ObjectAPIPacker\\";
504 code_ += " {\n";
505 Indent();
506 code_ += ValidateFunc();
507 code_ +=
508 "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
509 code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
510 if (!struct_def.fixed) {
511 if (parser_.file_identifier_.length()) {
512 code_.SetValue("FILENAME", parser_.file_identifier_);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700513 code_ += "{{ACCESS_TYPE}} static var id: String { \"{{FILENAME}}\" } ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700514 code_ +=
515 "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
516 "FlatBufferBuilder, end: "
517 "Offset, prefix: Bool = false) { fbb.finish(offset: end, "
518 "fileId: "
Austin Schuh2dd86a92022-09-14 21:19:23 -0700519 "{{STRUCTNAME}}.id, addPrefix: prefix) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700520 }
521 code_ +=
522 "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
523 "ByteBuffer) -> "
524 "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
525 "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
526 "Int32(bb.reader))) }\n";
527 code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
Austin Schuh272c6132020-11-14 16:37:52 -0800528 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700529 code_ +=
530 "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
531 "{{OBJECTTYPE}}(bb: "
532 "bb, position: o) }";
533 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -0800534 }
535
536 void GenTableWriter(const StructDef &struct_def) {
537 flatbuffers::FieldDef *key_field = nullptr;
538 std::vector<std::string> require_fields;
539 std::vector<std::string> create_func_body;
540 std::vector<std::string> create_func_header;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700541 const auto should_generate_create = struct_def.fields.vec.size() != 0;
Austin Schuh272c6132020-11-14 16:37:52 -0800542
543 code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
544 code_ +=
545 "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout "
546 "FlatBufferBuilder) -> "
547 "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
548
549 for (auto it = struct_def.fields.vec.begin();
550 it != struct_def.fields.vec.end(); ++it) {
551 auto &field = **it;
552 if (field.deprecated) continue;
553 if (field.key) key_field = &field;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700554 if (field.IsRequired())
Austin Schuh272c6132020-11-14 16:37:52 -0800555 require_fields.push_back(NumToString(field.value.offset));
556
James Kuszmaul8e62b022022-03-22 09:33:25 -0700557 GenTableWriterFields(field, &create_func_body, &create_func_header);
Austin Schuh272c6132020-11-14 16:37:52 -0800558 }
559 code_ +=
560 "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
561 "FlatBufferBuilder, "
562 "start: "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700563 "UOffset) -> Offset { let end = Offset(offset: "
Austin Schuh272c6132020-11-14 16:37:52 -0800564 "fbb.endTable(at: start))\\";
565 if (require_fields.capacity() != 0) {
566 std::string fields = "";
567 for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
568 fields += *it + ", ";
569 code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
570 code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
571 }
572 code_ += "; return end }";
573
574 if (should_generate_create) {
575 code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
576 Indent();
577 code_ += "_ fbb: inout FlatBufferBuilder,";
578 for (auto it = create_func_header.begin(); it < create_func_header.end();
579 ++it) {
580 code_ += *it + "\\";
581 if (it < create_func_header.end() - 1) code_ += ",";
582 }
583 code_ += "";
584 Outdent();
James Kuszmaul8e62b022022-03-22 09:33:25 -0700585 code_ += ") -> Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -0800586 Indent();
587 code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
588 for (auto it = create_func_body.begin(); it < create_func_body.end();
589 ++it) {
590 code_ += *it;
591 }
592 code_ +=
593 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)";
594 Outdent();
595 code_ += "}";
596 }
597
598 std::string spacing = "";
599
600 if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
Austin Schuh272c6132020-11-14 16:37:52 -0800601 code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
602
Austin Schuh2dd86a92022-09-14 21:19:23 -0700603 code_ += "{{ACCESS_TYPE}} static func " +
604 namer_.Method("sort_vector_of", struct_def) +
605 "(offsets:[Offset], "
606 "_ fbb: inout FlatBufferBuilder) -> Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -0800607 Indent();
608 code_ += spacing + "var off = offsets";
609 code_ +=
610 spacing +
611 "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
612 "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
613 "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
614 code_ += spacing + "return fbb.createVector(ofOffsets: off)";
615 Outdent();
616 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700617 GenLookup(*key_field, namer_.NamespacedType(struct_def));
Austin Schuh272c6132020-11-14 16:37:52 -0800618 }
619 }
620
621 void GenTableWriterFields(const FieldDef &field,
622 std::vector<std::string> *create_body,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700623 std::vector<std::string> *create_header) {
Austin Schuh272c6132020-11-14 16:37:52 -0800624 std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { ";
625 auto &create_func_body = *create_body;
626 auto &create_func_header = *create_header;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700627 const auto field_field = namer_.Field(field);
628 const auto field_var = namer_.Variable(field);
629 const auto type = GenType(field.value.type);
630 const auto opt_scalar =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700631 field.IsOptional() && IsScalar(field.value.type.base_type);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700632 const auto nullable_type = opt_scalar ? type + "?" : type;
633 code_.SetValue("FIELDVAR", namer_.Variable(field));
Austin Schuh272c6132020-11-14 16:37:52 -0800634 code_.SetValue("VALUETYPE", nullable_type);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700635 code_.SetValue("OFFSET", namer_.Field(field));
Austin Schuh272c6132020-11-14 16:37:52 -0800636 code_.SetValue("CONSTANT", field.value.constant);
637 std::string check_if_vector =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700638 (IsVector(field.value.type) || IsArray(field.value.type)) ? "VectorOf("
639 : "(";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700640 const auto body = "add" + check_if_vector + field_field + ": ";
Austin Schuh272c6132020-11-14 16:37:52 -0800641 code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
642
Austin Schuh2dd86a92022-09-14 21:19:23 -0700643 create_func_body.push_back("{{STRUCTNAME}}." + body + field_field +
644 ", &fbb)");
Austin Schuh272c6132020-11-14 16:37:52 -0800645
646 if (IsScalar(field.value.type.base_type) &&
647 !IsBool(field.value.type.base_type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700648 const std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
649 const std::string optional_enum =
Austin Schuh272c6132020-11-14 16:37:52 -0800650 IsEnum(field.value.type) ? ("?" + is_enum) : "";
651 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700652 "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{FIELDVAR}}\\";
Austin Schuh272c6132020-11-14 16:37:52 -0800653
James Kuszmaul8e62b022022-03-22 09:33:25 -0700654 code_ += field.IsOptional() ? (optional_enum + "\\")
655 : (is_enum + ", def: {{CONSTANT}}\\");
Austin Schuh272c6132020-11-14 16:37:52 -0800656
657 code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
658
Austin Schuh2dd86a92022-09-14 21:19:23 -0700659 const auto default_value =
Austin Schuh272c6132020-11-14 16:37:52 -0800660 IsEnum(field.value.type)
James Kuszmaul8e62b022022-03-22 09:33:25 -0700661 ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field))
Austin Schuh272c6132020-11-14 16:37:52 -0800662 : field.value.constant;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700663 create_func_header.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -0700664 "" + field_field + ": " + nullable_type + " = " +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700665 (field.IsOptional() ? "nil" : default_value));
Austin Schuh272c6132020-11-14 16:37:52 -0800666 return;
667 }
668
669 if (IsBool(field.value.type.base_type)) {
670 std::string default_value =
671 "0" == field.value.constant ? "false" : "true";
672
673 code_.SetValue("CONSTANT", default_value);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700674 code_.SetValue("VALUETYPE", field.IsOptional() ? "Bool?" : "Bool");
Austin Schuh2dd86a92022-09-14 21:19:23 -0700675 code_ +=
676 "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{FIELDVAR}},\\";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700677 code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},";
Austin Schuh272c6132020-11-14 16:37:52 -0800678 code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700679 create_func_header.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -0700680 field_var + ": " + nullable_type + " = " +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700681 (field.IsOptional() ? "nil" : default_value));
Austin Schuh272c6132020-11-14 16:37:52 -0800682 return;
683 }
684
685 if (IsStruct(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700686 const auto create_struct =
687 "guard let {{FIELDVAR}} = {{FIELDVAR}} else { return };"
688 " fbb.create(struct: {{FIELDVAR}}, position: "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700689 "{{TABLEOFFSET}}.{{OFFSET}}.p) }";
690 code_ += type + "?" + builder_string + create_struct;
691 /// Optional hard coded since structs are always optional
Austin Schuh2dd86a92022-09-14 21:19:23 -0700692 create_func_header.push_back(field_var + ": " + type +
693 (field.IsOptional() ? "? = nil" : ""));
Austin Schuh272c6132020-11-14 16:37:52 -0800694 return;
695 }
696
Austin Schuh2dd86a92022-09-14 21:19:23 -0700697 const auto arg_label =
698 namer_.Variable(field) +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700699 (IsVector(field.value.type) || IsArray(field.value.type)
700 ? "VectorOffset"
701 : "Offset");
Austin Schuh2dd86a92022-09-14 21:19:23 -0700702 create_func_header.push_back(arg_label + " " + field_var + ": " + "Offset" +
703 (field.IsRequired() ? "" : " = Offset()"));
704 const auto reader_type =
Austin Schuh272c6132020-11-14 16:37:52 -0800705 IsStruct(field.value.type) && field.value.type.struct_def->fixed
706 ? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
Austin Schuh2dd86a92022-09-14 21:19:23 -0700707 : "offset: {{FIELDVAR}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700708 code_ += "Offset" + builder_string + "fbb.add(" + reader_type;
Austin Schuh272c6132020-11-14 16:37:52 -0800709
Austin Schuh2dd86a92022-09-14 21:19:23 -0700710 const auto vectortype = field.value.type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -0800711
712 if ((vectortype.base_type == BASE_TYPE_STRUCT &&
713 field.value.type.struct_def->fixed) &&
James Kuszmaul8e62b022022-03-22 09:33:25 -0700714 (IsVector(field.value.type) || IsArray(field.value.type))) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700715 const auto field_name = namer_.NamespacedType(*vectortype.struct_def);
716 code_ += "{{ACCESS_TYPE}} static func " +
717 namer_.Method("start_vector_of", field_var) +
Austin Schuh272c6132020-11-14 16:37:52 -0800718 "(_ size: Int, in builder: inout "
719 "FlatBufferBuilder) {";
720 Indent();
James Kuszmaul8e62b022022-03-22 09:33:25 -0700721 code_ += "builder.startVector(size * MemoryLayout<" + field_name +
722 ">.size, elementSize: MemoryLayout<" + field_name +
723 ">.alignment)";
Austin Schuh272c6132020-11-14 16:37:52 -0800724 Outdent();
725 code_ += "}";
726 }
727 }
728
James Kuszmaul8e62b022022-03-22 09:33:25 -0700729 void GenTableReader(const StructDef &struct_def) {
730 for (auto it = struct_def.fields.vec.begin();
731 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700732 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700733 if (field.deprecated) continue;
734 GenTableReaderFields(field);
735 }
736 }
737
Austin Schuh272c6132020-11-14 16:37:52 -0800738 void GenTableReaderFields(const FieldDef &field) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700739 const auto offset = NumToString(field.value.offset);
740 const auto field_field = namer_.Field(field);
741 const auto type = GenType(field.value.type);
742 code_.SetValue("FIELDVAR", namer_.Variable(field));
743 code_.SetValue("FIELDMETHOD", namer_.Method(field));
Austin Schuh272c6132020-11-14 16:37:52 -0800744 code_.SetValue("VALUETYPE", type);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700745 code_.SetValue("OFFSET", namer_.Constant(field.name));
Austin Schuh272c6132020-11-14 16:37:52 -0800746 code_.SetValue("CONSTANT", field.value.constant);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700747 bool opt_scalar =
748 field.IsOptional() && IsScalar(field.value.type.base_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800749 std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}";
750 std::string optional = opt_scalar ? "?" : "";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700751 const auto const_string = "return o == 0 ? " + def_Val + " : ";
Austin Schuh272c6132020-11-14 16:37:52 -0800752 GenComment(field.doc_comment);
753 if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
754 !IsBool(field.value.type.base_type)) {
755 code_ += GenReaderMainBody(optional) + GenOffset() + const_string +
756 GenReader("VALUETYPE", "o") + " }";
757 if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
758 return;
759 }
760
761 if (IsBool(field.value.type.base_type)) {
762 std::string default_value =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700763 field.IsOptional() ? "nil"
764 : ("0" == field.value.constant ? "false" : "true");
Austin Schuh272c6132020-11-14 16:37:52 -0800765 code_.SetValue("CONSTANT", default_value);
766 code_.SetValue("VALUETYPE", "Bool");
767 code_ += GenReaderMainBody(optional) + "\\";
768 code_.SetValue("VALUETYPE", "Byte");
769 code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " +
770 GenReader("VALUETYPE", "o") + " }";
771 if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
772 return;
773 }
774
775 if (IsEnum(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700776 const auto default_value =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700777 field.IsOptional() ? "nil" : GenEnumDefaultValue(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800778 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
779 code_ += GenReaderMainBody(optional) + "\\";
780 code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
781 GenEnumConstructor("o") + "?? " + default_value + " }";
782 if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
783 code_ += GenMutate("o", GenOffset(), true);
784 return;
785 }
786
Austin Schuh2dd86a92022-09-14 21:19:23 -0700787 const std::string is_required = field.IsRequired() ? "!" : "?";
788 const auto required_reader = field.IsRequired() ? "return " : const_string;
Austin Schuh272c6132020-11-14 16:37:52 -0800789
790 if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
791 code_.SetValue("VALUETYPE", GenType(field.value.type));
792 code_.SetValue("CONSTANT", "nil");
793 code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700794 "{{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, at: o) }";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700795 code_.SetValue("FIELDVAR", namer_.Variable("mutable", field_field));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700796 code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
797 code_.SetValue("CONSTANT", "nil");
798 code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
Austin Schuh272c6132020-11-14 16:37:52 -0800799 GenConstructor("o + {{ACCESS}}.postion");
800 return;
801 }
802 switch (field.value.type.base_type) {
803 case BASE_TYPE_STRUCT:
804 code_.SetValue("VALUETYPE", GenType(field.value.type));
805 code_.SetValue("CONSTANT", "nil");
806 code_ += GenReaderMainBody(is_required) + GenOffset() +
807 required_reader +
808 GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
809 break;
810
James Kuszmaul8e62b022022-03-22 09:33:25 -0700811 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700812 const auto default_string = "\"" + field.value.constant + "\"";
Austin Schuh272c6132020-11-14 16:37:52 -0800813 code_.SetValue("VALUETYPE", GenType(field.value.type));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700814 code_.SetValue("CONSTANT", field.IsDefault() ? default_string : "nil");
Austin Schuh272c6132020-11-14 16:37:52 -0800815 code_ += GenReaderMainBody(is_required) + GenOffset() +
816 required_reader + "{{ACCESS}}.string(at: o) }";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700817 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}SegmentArray: [UInt8]" +
Austin Schuh272c6132020-11-14 16:37:52 -0800818 is_required +
819 " { return "
820 "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
821 break;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700822 }
Austin Schuh272c6132020-11-14 16:37:52 -0800823 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
James Kuszmaul8e62b022022-03-22 09:33:25 -0700824 case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break;
Austin Schuh272c6132020-11-14 16:37:52 -0800825 case BASE_TYPE_UNION:
826 code_.SetValue("CONSTANT", "nil");
827 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700828 "{{ACCESS_TYPE}} func {{FIELDVAR}}<T: "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700829 "FlatbuffersInitializable>(type: "
Austin Schuh272c6132020-11-14 16:37:52 -0800830 "T.Type) -> T" +
831 is_required + " { " + GenOffset() + required_reader +
832 "{{ACCESS}}.union(o) }";
833 break;
834 default: FLATBUFFERS_ASSERT(0);
835 }
836 }
837
James Kuszmaul8e62b022022-03-22 09:33:25 -0700838 void GenTableReaderVectorFields(const FieldDef &field) {
839 std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700840 const auto vectortype = field.value.type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -0800841 code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
Austin Schuh2dd86a92022-09-14 21:19:23 -0700842 code_.SetValue("HAS_FIELDVAR", namer_.Variable("has", field));
843 code_ += "{{ACCESS_TYPE}} var {{HAS_FIELDVAR}}: Bool { " + GenOffset() +
844 "return o == 0 ? false : true }";
845 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}Count: Int32 { " + GenOffset() +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700846 "return o == 0 ? 0 : {{ACCESS}}.vector(count: o) }";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700847 code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) ? "0" : "nil");
848 const auto nullable =
849 IsScalar(vectortype.base_type) && !IsEnum(vectortype) ? "" : "?";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700850
Austin Schuh272c6132020-11-14 16:37:52 -0800851 if (vectortype.base_type != BASE_TYPE_UNION) {
852 code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
853 } else {
854 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700855 "{{ACCESS_TYPE}} func {{FIELDVAR}}<T: FlatbuffersInitializable>(at "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700856 "index: "
Austin Schuh272c6132020-11-14 16:37:52 -0800857 "Int32, type: T.Type) -> T? { " +
858 GenOffset() + "\\";
859 }
860
861 if (IsBool(vectortype.base_type)) {
862 code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700863 code_.SetValue("VALUETYPE", "Bool");
Austin Schuh272c6132020-11-14 16:37:52 -0800864 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700865
866 if (!IsEnum(vectortype)) code_ += const_string + "\\";
Austin Schuh272c6132020-11-14 16:37:52 -0800867
868 if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
869 !IsBool(field.value.type.base_type)) {
870 code_ +=
871 "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
872 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
873 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -0700874 "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}] { return "
Austin Schuh272c6132020-11-14 16:37:52 -0800875 "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }";
876 if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
877 return;
878 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700879
Austin Schuh272c6132020-11-14 16:37:52 -0800880 if (vectortype.base_type == BASE_TYPE_STRUCT &&
881 field.value.type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700882 code_ +=
883 "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
884 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700885 code_.SetValue("FIELDMETHOD", namer_.Method("mutable", field));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700886 code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
887 code_ += GenArrayMainBody(nullable) + GenOffset() + const_string +
888 GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
889
Austin Schuh272c6132020-11-14 16:37:52 -0800890 return;
891 }
892
893 if (IsString(vectortype)) {
894 code_ +=
895 "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
896 "index * {{SIZE}}) }";
897 return;
898 }
899
900 if (IsEnum(vectortype)) {
901 code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
902 code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
903 " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
904 "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
905 "index * {{SIZE}})) }";
906 return;
907 }
908 if (vectortype.base_type == BASE_TYPE_UNION) {
909 code_ +=
910 "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
911 "index * {{SIZE}}) }";
912 return;
913 }
914
915 if (vectortype.base_type == BASE_TYPE_STRUCT &&
916 !field.value.type.struct_def->fixed) {
917 code_ += GenConstructor(
918 "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
919 "{{SIZE}})");
Austin Schuh2dd86a92022-09-14 21:19:23 -0700920 const auto &sd = *field.value.type.struct_def;
921 const auto &fields = sd.fields.vec;
Austin Schuh272c6132020-11-14 16:37:52 -0800922 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700923 const auto &key_field = **kit;
Austin Schuh272c6132020-11-14 16:37:52 -0800924 if (key_field.key) {
925 GenByKeyFunctions(key_field);
926 break;
927 }
928 }
929 }
930 }
931
James Kuszmaul8e62b022022-03-22 09:33:25 -0700932 void GenerateCodingKeys(const StructDef &struct_def) {
933 code_ += "enum CodingKeys: String, CodingKey {";
934 Indent();
935 for (auto it = struct_def.fields.vec.begin();
936 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700937 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700938 if (field.deprecated) continue;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700939
940 code_.SetValue("RAWVALUENAME", field.name);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700941 code_.SetValue("FIELDVAR", namer_.Variable(field));
942 code_ += "case {{FIELDVAR}} = \"{{RAWVALUENAME}}\"";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700943 }
944 Outdent();
945 code_ += "}";
946 }
947
948 void GenerateEncoderUnionBody(const FieldDef &field) {
949 EnumDef &union_def = *field.value.type.enum_def;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700950 const auto is_vector = field.value.type.base_type == BASE_TYPE_VECTOR ||
951 field.value.type.base_type == BASE_TYPE_ARRAY;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700952 if (field.value.type.base_type == BASE_TYPE_UTYPE ||
953 (is_vector &&
954 field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
955 return;
956 if (is_vector) {
957 code_ +=
958 "var enumsEncoder = container.nestedUnkeyedContainer(forKey: "
Austin Schuh2dd86a92022-09-14 21:19:23 -0700959 ".{{FIELDVAR}}Type)";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700960 code_ +=
961 "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
Austin Schuh2dd86a92022-09-14 21:19:23 -0700962 ".{{FIELDVAR}})";
963 code_ += "for index in 0..<{{FIELDVAR}}Count {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700964 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -0700965 code_ += "guard let type = {{FIELDVAR}}Type(at: index) else { continue }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700966 code_ += "try enumsEncoder.encode(type)";
967 code_ += "switch type {";
968 for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
969 ++it) {
970 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700971 const auto type = GenType(ev.union_type);
972 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700973 code_.SetValue("VALUETYPE", type);
974 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
975 code_ += "case .{{KEY}}:";
976 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -0700977 code_ += "let _v = {{FIELDVAR}}(at: index, type: {{VALUETYPE}}.self)";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700978 code_ += "try contentEncoder.encode(_v)";
979 Outdent();
980 }
981 code_ += "default: break;";
982 code_ += "}";
983 Outdent();
984 code_ += "}";
985 return;
986 }
987
Austin Schuh2dd86a92022-09-14 21:19:23 -0700988 code_ += "switch {{FIELDVAR}}Type {";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700989 for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
990 ++it) {
991 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700992 const auto type = GenType(ev.union_type);
993 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700994 code_.SetValue("VALUETYPE", type);
995 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
996 code_ += "case .{{KEY}}:";
997 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -0700998 code_ += "let _v = {{FIELDVAR}}(type: {{VALUETYPE}}.self)";
999 code_ += "try container.encodeIfPresent(_v, forKey: .{{FIELDVAR}})";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001000 Outdent();
1001 }
1002 code_ += "default: break;";
1003 code_ += "}";
1004 }
1005
1006 void GenerateEncoderBody(const StructDef &struct_def) {
1007 code_ += "var container = encoder.container(keyedBy: CodingKeys.self)";
1008 for (auto it = struct_def.fields.vec.begin();
1009 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001010 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001011 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001012 const auto type = field.value.type;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001013
Austin Schuh2dd86a92022-09-14 21:19:23 -07001014 const auto is_non_union_vector =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001015 (field.value.type.base_type == BASE_TYPE_ARRAY ||
1016 field.value.type.base_type == BASE_TYPE_VECTOR) &&
1017 field.value.type.VectorType().base_type != BASE_TYPE_UTYPE;
1018
Austin Schuh2dd86a92022-09-14 21:19:23 -07001019 code_.SetValue("FIELDVAR", namer_.Variable(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001020 code_.SetValue("CONSTANT", field.value.constant);
1021 bool should_indent = true;
1022 if (is_non_union_vector) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001023 code_ += "if {{FIELDVAR}}Count > 0 {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001024 } else if (IsEnum(type) && !field.IsOptional()) {
1025 code_.SetValue("CONSTANT", GenEnumDefaultValue(field));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001026 code_ += "if {{FIELDVAR}} != {{CONSTANT}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001027 } else if (IsScalar(type.base_type) && !IsEnum(type) &&
1028 !IsBool(type.base_type) && !field.IsOptional()) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001029 code_ += "if {{FIELDVAR}} != {{CONSTANT}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001030 } else if (IsBool(type.base_type) && !field.IsOptional()) {
1031 std::string default_value =
1032 "0" == field.value.constant ? "false" : "true";
1033 code_.SetValue("CONSTANT", default_value);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001034 code_ += "if {{FIELDVAR}} != {{CONSTANT}} {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001035 } else {
1036 should_indent = false;
1037 }
1038 if (should_indent) Indent();
1039
1040 if (IsUnion(type) && !IsEnum(type)) {
1041 GenerateEncoderUnionBody(field);
1042 } else if (is_non_union_vector &&
1043 (!IsScalar(type.VectorType().base_type) ||
1044 IsEnum(type.VectorType()))) {
1045 code_ +=
1046 "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
Austin Schuh2dd86a92022-09-14 21:19:23 -07001047 ".{{FIELDVAR}})";
1048 code_ += "for index in 0..<{{FIELDVAR}}Count {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001049 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001050 code_ += "guard let type = {{FIELDVAR}}(at: index) else { continue }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001051 code_ += "try contentEncoder.encode(type)";
1052 Outdent();
1053 code_ += "}";
1054 } else {
1055 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001056 "try container.encodeIfPresent({{FIELDVAR}}, forKey: "
1057 ".{{FIELDVAR}})";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001058 }
1059 if (should_indent) Outdent();
1060
1061 if (is_non_union_vector ||
1062 (IsScalar(type.base_type) && !field.IsOptional())) {
1063 code_ += "}";
1064 }
1065 }
1066 }
1067
1068 void GenerateJSONEncodingAPIs(const StructDef &struct_def) {
1069 code_ += "extension {{STRUCTNAME}}: Encodable {";
1070 Indent();
1071 code_ += "";
1072 if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def);
1073
Austin Schuh2dd86a92022-09-14 21:19:23 -07001074 code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001075 Indent();
1076 if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def);
1077 Outdent();
1078 code_ += "}";
1079 Outdent();
1080 code_ += "}";
1081 code_ += "";
1082 }
1083
1084 void GenerateVerifier(const StructDef &struct_def) {
1085 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001086 "{{ACCESS_TYPE}} static func verify<T>(_ verifier: inout Verifier, at "
1087 "position: "
James Kuszmaul8e62b022022-03-22 09:33:25 -07001088 "Int, of type: T.Type) throws where T: Verifiable {";
1089 Indent();
1090 code_ += "var _v = try verifier.visitTable(at: position)";
1091 for (auto it = struct_def.fields.vec.begin();
1092 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001093 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001094 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001095 const auto offset = NumToString(field.value.offset);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001096
Austin Schuh2dd86a92022-09-14 21:19:23 -07001097 code_.SetValue("FIELDVAR", namer_.Variable(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001098 code_.SetValue("VALUETYPE", GenerateVerifierType(field));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001099 code_.SetValue("OFFSET", namer_.Field(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001100 code_.SetValue("ISREQUIRED", field.IsRequired() ? "true" : "false");
1101
1102 if (IsUnion(field.value.type)) {
1103 GenerateUnionTypeVerifier(field);
1104 continue;
1105 }
1106
1107 code_ +=
1108 "try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: "
Austin Schuh2dd86a92022-09-14 21:19:23 -07001109 "\"{{FIELDVAR}}\", required: {{ISREQUIRED}}, type: "
James Kuszmaul8e62b022022-03-22 09:33:25 -07001110 "{{VALUETYPE}}.self)";
1111 }
1112 code_ += "_v.finish()";
1113 Outdent();
1114 code_ += "}";
1115 }
1116
1117 void GenerateUnionTypeVerifier(const FieldDef &field) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001118 const auto is_vector =
1119 IsVector(field.value.type) || IsArray(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001120 if (field.value.type.base_type == BASE_TYPE_UTYPE ||
1121 (is_vector &&
1122 field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
1123 return;
1124 EnumDef &union_def = *field.value.type.enum_def;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001125 code_.SetValue("VALUETYPE", namer_.NamespacedType(union_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001126 code_.SetValue("FUNCTION_NAME", is_vector ? "visitUnionVector" : "visit");
1127 code_ +=
1128 "try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, "
1129 "unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: "
Austin Schuh2dd86a92022-09-14 21:19:23 -07001130 "\"{{FIELDVAR}}Type\", fieldName: \"{{FIELDVAR}}\", required: "
James Kuszmaul8e62b022022-03-22 09:33:25 -07001131 "{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in";
1132 Indent();
1133 code_ += "switch key {";
1134 for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
1135 ++it) {
1136 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001137 const auto type = GenType(ev.union_type);
1138 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001139 code_.SetValue("VALUETYPE", type);
1140 code_ += "case .{{KEY}}:";
1141 Indent();
1142 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1143 code_ += "break // NOTE - SWIFT doesnt support none";
1144 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1145 code_ +=
1146 "try ForwardOffset<String>.verify(&verifier, at: pos, of: "
1147 "String.self)";
1148 } else {
1149 code_.SetValue("MAINTYPE", ev.union_type.struct_def->fixed
1150 ? type
1151 : "ForwardOffset<" + type + ">");
1152 code_ +=
1153 "try {{MAINTYPE}}.verify(&verifier, at: pos, of: "
1154 "{{VALUETYPE}}.self)";
1155 }
1156 Outdent();
1157 }
1158 code_ += "}";
1159 Outdent();
1160 code_ += "})";
1161 }
1162
1163 std::string GenerateVerifierType(const FieldDef &field) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001164 const auto type = field.value.type;
1165 const auto is_vector = IsVector(type) || IsArray(type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001166
1167 if (is_vector) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001168 const auto vector_type = field.value.type.VectorType();
James Kuszmaul8e62b022022-03-22 09:33:25 -07001169 return "ForwardOffset<Vector<" +
1170 GenerateNestedVerifierTypes(vector_type) + ", " +
1171 GenType(vector_type) + ">>";
1172 }
1173
1174 return GenerateNestedVerifierTypes(field.value.type);
1175 }
1176
1177 std::string GenerateNestedVerifierTypes(const Type &type) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001178 const auto string_type = GenType(type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001179
1180 if (IsScalar(type.base_type)) { return string_type; }
1181
1182 if (IsString(type)) { return "ForwardOffset<" + string_type + ">"; }
1183
1184 if (type.struct_def && type.struct_def->fixed) { return string_type; }
1185
1186 return "ForwardOffset<" + string_type + ">";
1187 }
1188
Austin Schuh272c6132020-11-14 16:37:52 -08001189 void GenByKeyFunctions(const FieldDef &key_field) {
1190 code_.SetValue("TYPE", GenType(key_field.value.type));
1191 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001192 "{{ACCESS_TYPE}} func {{FIELDVAR}}By(key: {{TYPE}}) -> {{VALUETYPE}}? "
Austin Schuh272c6132020-11-14 16:37:52 -08001193 "{ \\";
1194 code_ += GenOffset() +
1195 "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
1196 "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
1197 }
1198
Austin Schuh272c6132020-11-14 16:37:52 -08001199 void GenEnum(const EnumDef &enum_def) {
1200 if (enum_def.generated) return;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001201 const auto is_private_access = enum_def.attributes.Lookup("private");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001202 code_.SetValue("ENUM_TYPE",
1203 enum_def.is_union ? "UnionEnum" : "Enum, Verifiable");
Austin Schuh272c6132020-11-14 16:37:52 -08001204 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
Austin Schuh2dd86a92022-09-14 21:19:23 -07001205 code_.SetValue("ENUM_NAME", namer_.NamespacedType(enum_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001206 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1207 GenComment(enum_def.doc_comment);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001208 code_ +=
1209 "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001210 Indent();
1211 code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001212 if (enum_def.is_union) {
1213 code_ += "";
1214 code_ += "{{ACCESS_TYPE}} init?(value: T) {";
1215 Indent();
1216 code_ += "self.init(rawValue: value)";
1217 Outdent();
1218 code_ += "}\n";
1219 }
Austin Schuh272c6132020-11-14 16:37:52 -08001220 code_ +=
1221 "{{ACCESS_TYPE}} static var byteSize: Int { return "
1222 "MemoryLayout<{{BASE_TYPE}}>.size "
1223 "}";
1224 code_ +=
1225 "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
1226 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1227 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001228 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
Austin Schuh272c6132020-11-14 16:37:52 -08001229 code_.SetValue("VALUE", enum_def.ToString(ev));
1230 GenComment(ev.doc_comment);
1231 code_ += "case {{KEY}} = {{VALUE}}";
1232 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001233 code_ += "";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001234 AddMinOrMaxEnumValue(namer_.LegacySwiftVariant(*enum_def.MaxValue()),
1235 "max");
1236 AddMinOrMaxEnumValue(namer_.LegacySwiftVariant(*enum_def.MinValue()),
1237 "min");
Austin Schuh272c6132020-11-14 16:37:52 -08001238 Outdent();
1239 code_ += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001240 if (parser_.opts.gen_json_coders) EnumEncoder(enum_def);
1241 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001242 if (parser_.opts.generate_object_based_api && enum_def.is_union) {
1243 code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
1244 Indent();
1245 code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001246 code_ += "{{ACCESS_TYPE}} var value: NativeObject?";
1247 code_ +=
1248 "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {";
Austin Schuh272c6132020-11-14 16:37:52 -08001249 Indent();
1250 code_ += "self.type = type";
1251 code_ += "self.value = v";
1252 Outdent();
1253 code_ += "}";
1254 code_ +=
1255 "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07001256 "Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -08001257 Indent();
1258 BuildUnionEnumSwitchCaseWritter(enum_def);
1259 Outdent();
1260 code_ += "}";
1261 Outdent();
1262 code_ += "}";
1263 }
1264 }
1265
James Kuszmaul8e62b022022-03-22 09:33:25 -07001266 void EnumEncoder(const EnumDef &enum_def) {
1267 code_ += "extension {{ENUM_NAME}}: Encodable {";
1268 Indent();
1269 code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
1270 Indent();
1271 code_ += "var container = encoder.singleValueContainer()";
1272 code_ += "switch self {";
1273 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1274 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001275 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001276 code_.SetValue("RAWKEY", ev.name);
1277 code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")";
1278 }
1279 code_ += "}";
1280 Outdent();
1281 code_ += "}";
1282 Outdent();
1283 code_ += "}";
1284 }
1285
1286 // MARK: - Object API
1287
Austin Schuh2dd86a92022-09-14 21:19:23 -07001288 void GenerateObjectAPIExtensionHeader(std::string type_name) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001289 code_ += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001290 code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + type_name + " {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001291 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001292 code_ += "return " + type_name + "(&self)";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001293 Outdent();
1294 code_ += "}";
1295 code_ +=
1296 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1297 "obj: "
1298 "inout " +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001299 type_name + "?) -> Offset {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001300 Indent();
1301 code_ += "guard var obj = obj else { return Offset() }";
1302 code_ += "return pack(&builder, obj: &obj)";
1303 Outdent();
1304 code_ += "}";
1305 code_ += "";
1306 code_ +=
1307 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1308 "obj: "
1309 "inout " +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001310 type_name + ") -> Offset {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001311 Indent();
1312 }
1313
1314 void GenerateObjectAPIStructConstructor(const StructDef &struct_def) {
1315 code_ +=
1316 "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {";
1317 Indent();
1318 for (auto it = struct_def.fields.vec.begin();
1319 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001320 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001321 if (field.deprecated) continue;
1322
Austin Schuh2dd86a92022-09-14 21:19:23 -07001323 const auto type = GenType(field.value.type);
1324 code_.SetValue("FIELDVAR", namer_.Variable(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001325 if (IsStruct(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001326 code_ += "var _v{{FIELDVAR}} = _t.{{FIELDVAR}}";
1327 code_ += "_{{FIELDVAR}} = _v{{FIELDVAR}}.unpack()";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001328 continue;
1329 }
1330 std::string is_enum = IsEnum(field.value.type) ? ".value" : "";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001331 code_ += "_{{FIELDVAR}} = _t.{{FIELDVAR}}" + is_enum;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001332 }
1333 Outdent();
1334 code_ += "}\n";
1335 }
1336
Austin Schuh272c6132020-11-14 16:37:52 -08001337 void GenObjectAPI(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001338 code_ += "{{ACCESS_TYPE}} class " +
1339 namer_.NamespacedObjectType(struct_def) + ": NativeObject {\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001340 std::vector<std::string> buffer_constructor;
1341 std::vector<std::string> base_constructor;
1342 Indent();
1343 for (auto it = struct_def.fields.vec.begin();
1344 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001345 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001346 if (field.deprecated) continue;
1347 BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
1348 base_constructor);
1349 }
1350 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001351 BuildObjectConstructor(buffer_constructor,
Austin Schuh2dd86a92022-09-14 21:19:23 -07001352 "_ _t: inout " + namer_.NamespacedType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001353 BuildObjectConstructor(base_constructor);
Austin Schuh272c6132020-11-14 16:37:52 -08001354 if (!struct_def.fixed)
1355 code_ +=
1356 "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
1357 "serialize(type: "
1358 "{{STRUCTNAME}}.self) }\n";
1359 Outdent();
1360 code_ += "}";
1361 }
1362
1363 void GenerateObjectAPITableExtension(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001364 GenerateObjectAPIExtensionHeader(namer_.NamespacedObjectType(struct_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001365 std::vector<std::string> unpack_body;
1366 std::string builder = ", &builder)";
1367 for (auto it = struct_def.fields.vec.begin();
1368 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001369 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001370 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001371 const auto field_var = namer_.Variable(field);
1372 const auto field_field = namer_.Field(field);
1373 const auto field_method = namer_.Method(field);
1374 const auto type = GenType(field.value.type);
Austin Schuh272c6132020-11-14 16:37:52 -08001375 std::string check_if_vector =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001376 (IsVector(field.value.type) || IsArray(field.value.type))
Austin Schuh272c6132020-11-14 16:37:52 -08001377 ? "VectorOf("
1378 : "(";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001379 std::string body = "add" + check_if_vector + field_method + ": ";
Austin Schuh272c6132020-11-14 16:37:52 -08001380 switch (field.value.type.base_type) {
1381 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1382 case BASE_TYPE_VECTOR: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001383 GenerateVectorObjectAPITableExtension(field);
1384 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001385 builder);
1386 break;
1387 }
1388 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001389 code_ += "let __" + field_var + " = obj." + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001390 "?.pack(builder: &builder) ?? Offset()";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001391 unpack_body.push_back("if let o = obj." + field_var + "?.type {");
1392 unpack_body.push_back(" {{STRUCTNAME}}.add(" + field_var +
1393 "Type: o" + builder);
1394 unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001395 builder);
1396 unpack_body.push_back("}\n");
1397 break;
1398 }
1399 case BASE_TYPE_STRUCT: {
1400 if (field.value.type.struct_def &&
1401 field.value.type.struct_def->fixed) {
1402 // This is a Struct (IsStruct), not a table. We create
James Kuszmaul8e62b022022-03-22 09:33:25 -07001403 // a native swift object in this case.
Austin Schuh272c6132020-11-14 16:37:52 -08001404 std::string code;
1405 GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
1406 "$0", true);
1407 code = code.substr(0, code.size() - 2);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001408 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." +
1409 field_field + builder);
Austin Schuh272c6132020-11-14 16:37:52 -08001410 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001411 code_ += "let __" + field_var + " = " + type +
1412 ".pack(&builder, obj: &obj." + field_field + ")";
1413 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001414 builder);
1415 }
1416 break;
1417 }
1418 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001419 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001420 builder);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001421 if (field.IsRequired()) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001422 code_ += "let __" + field_var + " = builder.create(string: obj." +
1423 field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001424 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001425 BuildingOptionalObjects(field_field, "builder.create(string: s)");
Austin Schuh272c6132020-11-14 16:37:52 -08001426 }
1427 break;
1428 }
1429 case BASE_TYPE_UTYPE: break;
1430 default:
Austin Schuh2dd86a92022-09-14 21:19:23 -07001431 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." +
1432 field_field + builder);
Austin Schuh272c6132020-11-14 16:37:52 -08001433 }
1434 }
1435 code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
1436 for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
1437 code_ += *it;
1438 code_ +=
1439 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
1440 "__root)";
1441 Outdent();
1442 code_ += "}";
1443 }
1444
Austin Schuh2dd86a92022-09-14 21:19:23 -07001445 void GenerateVectorObjectAPITableExtension(const FieldDef &field_def) {
1446 const Type &field_type = field_def.value.type;
1447 const auto type = GenType(field_type);
1448 const auto var = namer_.Variable(field_def);
1449 const auto field = namer_.Field(field_def);
1450
1451 const auto vectortype = field_type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -08001452 switch (vectortype.base_type) {
1453 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001454 code_ += "var __" + var + "__: [Offset] = []";
1455 code_ += "for i in obj." + var + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001456 Indent();
1457 code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001458 code_ += "__" + var + "__.append(off)";
Austin Schuh272c6132020-11-14 16:37:52 -08001459 Outdent();
1460 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001461 code_ += "let __" + var + " = builder.createVector(ofOffsets: __" +
1462 var + "__)";
1463 code_ += "let __" + var + "Type = builder.createVector(obj." + field +
Austin Schuh272c6132020-11-14 16:37:52 -08001464 ".compactMap { $0?.type })";
1465 break;
1466 }
1467 case BASE_TYPE_UTYPE: break;
1468 case BASE_TYPE_STRUCT: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001469 if (field_type.struct_def && !field_type.struct_def->fixed) {
1470 code_ += "var __" + var + "__: [Offset] = []";
1471 code_ += "for var i in obj." + var + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001472 Indent();
1473 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001474 "__" + var + "__.append(" + type + ".pack(&builder, obj: &i))";
Austin Schuh272c6132020-11-14 16:37:52 -08001475 Outdent();
1476 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001477 code_ += "let __" + var + " = builder.createVector(ofOffsets: __" +
1478 var + "__)";
Austin Schuh272c6132020-11-14 16:37:52 -08001479 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001480 code_ += "{{STRUCTNAME}}." + namer_.Method("start_vector_of", var) +
1481 "(obj." + field + ".count, in: &builder)";
Austin Schuh272c6132020-11-14 16:37:52 -08001482 std::string code;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001483 GenerateStructArgs(*field_type.struct_def, &code, "", "", "_o", true);
Austin Schuh272c6132020-11-14 16:37:52 -08001484 code = code.substr(0, code.size() - 2);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001485 code_ += "for i in obj." + field + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001486 Indent();
1487 code_ += "guard let _o = i else { continue }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001488 code_ += "builder.create(struct: _o)";
Austin Schuh272c6132020-11-14 16:37:52 -08001489 Outdent();
1490 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001491 code_ += "let __" + var + " = builder.endVector(len: obj." + field +
Austin Schuh272c6132020-11-14 16:37:52 -08001492 ".count)";
1493 }
1494 break;
1495 }
1496 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001497 code_ += "let __" + var + " = builder.createVector(ofStrings: obj." +
1498 var + ".compactMap({ $0 }) )";
Austin Schuh272c6132020-11-14 16:37:52 -08001499 break;
1500 }
1501 default: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001502 code_ += "let __" + var + " = builder.createVector(obj." + field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001503 break;
1504 }
1505 }
1506 }
1507
Austin Schuh2dd86a92022-09-14 21:19:23 -07001508 void BuildingOptionalObjects(const std::string &var,
Austin Schuh272c6132020-11-14 16:37:52 -08001509 const std::string &body_front) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001510 code_ += "let __" + var + ": Offset";
1511 code_ += "if let s = obj." + var + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001512 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001513 code_ += "__" + var + " = " + body_front;
Austin Schuh272c6132020-11-14 16:37:52 -08001514 Outdent();
1515 code_ += "} else {";
1516 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001517 code_ += "__" + var + " = Offset()";
Austin Schuh272c6132020-11-14 16:37:52 -08001518 Outdent();
1519 code_ += "}";
1520 code_ += "";
1521 }
1522
James Kuszmaul8e62b022022-03-22 09:33:25 -07001523 void BuildObjectConstructor(const std::vector<std::string> &body,
1524 const std::string &header = "") {
Austin Schuh272c6132020-11-14 16:37:52 -08001525 code_.SetValue("HEADER", header);
1526 code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
1527 Indent();
1528 for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
1529 Outdent();
1530 code_ += "}\n";
1531 }
1532
1533 void BuildObjectAPIConstructorBody(
1534 const FieldDef &field, bool is_fixed,
1535 std::vector<std::string> &buffer_constructor,
1536 std::vector<std::string> &base_constructor) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001537 const auto field_field = namer_.Field(field);
1538 const auto field_var = namer_.Variable(field);
1539 const auto type = GenType(field.value.type);
1540 code_.SetValue("FIELDVAR", field_field);
Austin Schuh272c6132020-11-14 16:37:52 -08001541 code_.SetValue("VALUETYPE", type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001542 std::string is_required = field.IsRequired() ? "" : "?";
Austin Schuh272c6132020-11-14 16:37:52 -08001543
1544 switch (field.value.type.base_type) {
1545 case BASE_TYPE_STRUCT: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001546 const auto objtype = GenType(field.value.type, true);
1547 code_.SetValue("VALUETYPE", objtype);
1548 const auto optional =
Austin Schuh272c6132020-11-14 16:37:52 -08001549 (field.value.type.struct_def && field.value.type.struct_def->fixed);
1550 std::string question_mark =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001551 (field.IsRequired() || (optional && is_fixed) ? "" : "?");
Austin Schuh272c6132020-11-14 16:37:52 -08001552
1553 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001554 "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + question_mark;
1555 base_constructor.push_back("" + field_var + " = " + objtype + "()");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001556
1557 if (field.value.type.struct_def->fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001558 buffer_constructor.push_back("" + field_var + " = _t." + field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001559 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001560 buffer_constructor.push_back("var __" + field_var + " = _t." +
1561 field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001562 buffer_constructor.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001563 "" + field_var + " = __" + field_var +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001564 (field.IsRequired() ? "!" : question_mark) + ".unpack()");
1565 }
Austin Schuh272c6132020-11-14 16:37:52 -08001566 break;
1567 }
1568 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1569 case BASE_TYPE_VECTOR: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001570 BuildObjectAPIConstructorBodyVectors(field, buffer_constructor,
Austin Schuh272c6132020-11-14 16:37:52 -08001571 base_constructor, " ");
1572 break;
1573 }
1574 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001575 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: String" + is_required;
1576 buffer_constructor.push_back(field_var + " = _t." + field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001577
1578 if (field.IsRequired()) {
1579 std::string default_value =
1580 field.IsDefault() ? field.value.constant : "";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001581 base_constructor.push_back(field_var + " = \"" + default_value +
1582 "\"");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001583 break;
1584 }
1585 if (field.IsDefault() && !field.IsRequired()) {
1586 std::string value = field.IsDefault() ? field.value.constant : "nil";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001587 base_constructor.push_back(field_var + " = \"" + value + "\"");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001588 }
Austin Schuh272c6132020-11-14 16:37:52 -08001589 break;
1590 }
1591 case BASE_TYPE_UTYPE: break;
1592 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001593 BuildUnionEnumSwitchCase(*field.value.type.enum_def, field_var,
Austin Schuh272c6132020-11-14 16:37:52 -08001594 buffer_constructor);
1595 break;
1596 }
1597 default: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001598 buffer_constructor.push_back(field_var + " = _t." + field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001599 std::string nullable = field.IsOptional() ? "?" : "";
Austin Schuh272c6132020-11-14 16:37:52 -08001600 if (IsScalar(field.value.type.base_type) &&
1601 !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001602 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + nullable;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001603 if (!field.IsOptional())
Austin Schuh2dd86a92022-09-14 21:19:23 -07001604 base_constructor.push_back(field_var + " = " +
1605 field.value.constant);
Austin Schuh272c6132020-11-14 16:37:52 -08001606 break;
1607 }
1608
1609 if (IsEnum(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001610 const auto default_value = IsEnum(field.value.type)
1611 ? GenEnumDefaultValue(field)
1612 : field.value.constant;
1613 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}";
1614 base_constructor.push_back(field_var + " = " + default_value);
Austin Schuh272c6132020-11-14 16:37:52 -08001615 break;
1616 }
1617
1618 if (IsBool(field.value.type.base_type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001619 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: Bool" + nullable;
Austin Schuh272c6132020-11-14 16:37:52 -08001620 std::string default_value =
1621 "0" == field.value.constant ? "false" : "true";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001622 if (!field.IsOptional())
Austin Schuh2dd86a92022-09-14 21:19:23 -07001623 base_constructor.push_back(field_var + " = " + default_value);
Austin Schuh272c6132020-11-14 16:37:52 -08001624 }
1625 }
1626 }
1627 }
1628
1629 void BuildObjectAPIConstructorBodyVectors(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001630 const FieldDef &field, std::vector<std::string> &buffer_constructor,
Austin Schuh272c6132020-11-14 16:37:52 -08001631 std::vector<std::string> &base_constructor,
1632 const std::string &indentation) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001633 const auto vectortype = field.value.type.VectorType();
1634 const auto field_var = namer_.Field(field);
1635 const auto field_field = namer_.Field(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001636
1637 if (vectortype.base_type != BASE_TYPE_UTYPE) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001638 buffer_constructor.push_back(field_var + " = []");
1639 buffer_constructor.push_back("for index in 0..<_t." + field_field +
1640 "Count {");
1641 base_constructor.push_back(field_var + " = []");
Austin Schuh272c6132020-11-14 16:37:52 -08001642 }
1643
1644 switch (vectortype.base_type) {
1645 case BASE_TYPE_STRUCT: {
1646 code_.SetValue("VALUETYPE", GenType(vectortype, true));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001647 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}?]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001648 if (!vectortype.struct_def->fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001649 buffer_constructor.push_back(indentation + "var __v_ = _t." +
1650 field_field + "(at: index)");
1651 buffer_constructor.push_back(indentation + field_var +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001652 ".append(__v_?.unpack())");
1653 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001654 buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1655 field_var + "(at: index))");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001656 }
Austin Schuh272c6132020-11-14 16:37:52 -08001657 break;
1658 }
1659 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1660 case BASE_TYPE_VECTOR: {
1661 break;
1662 }
1663 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001664 BuildUnionEnumSwitchCase(*field.value.type.enum_def, field_var,
Austin Schuh272c6132020-11-14 16:37:52 -08001665 buffer_constructor, indentation, true);
1666 break;
1667 }
1668 case BASE_TYPE_UTYPE: break;
1669 default: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001670 code_.SetValue(
1671 "VALUETYPE",
1672 (IsString(vectortype) ? "String?" : GenType(vectortype)));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001673 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}]";
Austin Schuh272c6132020-11-14 16:37:52 -08001674
1675 if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001676 const auto default_value = IsEnum(field.value.type)
1677 ? GenEnumDefaultValue(field)
1678 : field.value.constant;
1679 buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1680 field_field + "(at: index)!)");
Austin Schuh272c6132020-11-14 16:37:52 -08001681 break;
1682 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001683 buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1684 field_field + "(at: index))");
Austin Schuh272c6132020-11-14 16:37:52 -08001685 break;
1686 }
1687 }
1688 if (vectortype.base_type != BASE_TYPE_UTYPE)
1689 buffer_constructor.push_back("}");
1690 }
1691
Austin Schuh2dd86a92022-09-14 21:19:23 -07001692 void BuildUnionEnumSwitchCaseWritter(const EnumDef &ed) {
Austin Schuh272c6132020-11-14 16:37:52 -08001693 code_ += "switch type {";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001694 for (auto it = ed.Vals().begin(); it < ed.Vals().end(); ++it) {
1695 const auto ev = **it;
1696 const auto variant = namer_.LegacySwiftVariant(ev);
1697 const auto type = GenType(ev.union_type);
1698 const auto is_struct = IsStruct(ev.union_type) ? type + Mutable() : type;
1699 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1700 code_ += "case ." + variant + ":";
Austin Schuh272c6132020-11-14 16:37:52 -08001701 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001702 code_ += "var __obj = value as? " + GenType(ev.union_type, true);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001703 code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)";
Austin Schuh272c6132020-11-14 16:37:52 -08001704 Outdent();
1705 }
1706 code_ += "default: return Offset()";
1707 code_ += "}";
1708 }
1709
Austin Schuh2dd86a92022-09-14 21:19:23 -07001710 void BuildUnionEnumSwitchCase(const EnumDef &ed, const std::string &field,
Austin Schuh272c6132020-11-14 16:37:52 -08001711 std::vector<std::string> &buffer_constructor,
1712 const std::string &indentation = "",
1713 const bool is_vector = false) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001714 const auto ns_type = namer_.NamespacedType(ed);
1715 code_.SetValue("VALUETYPE", ns_type);
1716 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: \\";
Austin Schuh272c6132020-11-14 16:37:52 -08001717 code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
1718
Austin Schuh2dd86a92022-09-14 21:19:23 -07001719 const auto vector_reader = is_vector ? "(at: index" : "";
1720 buffer_constructor.push_back(indentation + "switch _t." + field + "Type" +
Austin Schuh272c6132020-11-14 16:37:52 -08001721 vector_reader + (is_vector ? ")" : "") + " {");
1722
Austin Schuh2dd86a92022-09-14 21:19:23 -07001723 for (auto it = ed.Vals().begin(); it < ed.Vals().end(); ++it) {
1724 const auto ev = **it;
1725 const auto variant = namer_.LegacySwiftVariant(ev);
1726 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1727 const auto type = IsStruct(ev.union_type)
1728 ? GenType(ev.union_type) + Mutable()
1729 : GenType(ev.union_type);
1730 buffer_constructor.push_back(indentation + "case ." + variant + ":");
Austin Schuh272c6132020-11-14 16:37:52 -08001731 buffer_constructor.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001732 indentation + " var _v = _t." + field + (is_vector ? "" : "(") +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001733 vector_reader + (is_vector ? ", " : "") + "type: " + type + ".self)");
Austin Schuh2dd86a92022-09-14 21:19:23 -07001734 const auto constructor =
1735 ns_type + "Union(_v?.unpack(), type: ." + variant + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001736 buffer_constructor.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001737 indentation + " " + field +
Austin Schuh272c6132020-11-14 16:37:52 -08001738 (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
1739 }
1740 buffer_constructor.push_back(indentation + "default: break");
1741 buffer_constructor.push_back(indentation + "}");
1742 }
1743
1744 void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001745 const auto current_value = str;
Austin Schuh272c6132020-11-14 16:37:52 -08001746 code_.SetValue(type, current_value);
1747 code_ += "{{ACCESS_TYPE}} static var " + type +
1748 ": {{ENUM_NAME}} { return .{{" + type + "}} }";
1749 }
1750
Austin Schuh2dd86a92022-09-14 21:19:23 -07001751 void GenLookup(const FieldDef &key_field, const std::string &struct_type) {
1752 code_.SetValue("STRUCTTYPE", struct_type);
Austin Schuh272c6132020-11-14 16:37:52 -08001753 code_.SetValue("OFFSET", NumToString(key_field.value.offset));
1754 std::string offset_reader =
1755 "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
1756 "fbb: fbb)";
1757
1758 code_.SetValue("TYPE", GenType(key_field.value.type));
1759 code_ +=
1760 "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
1761 "fbb: "
Austin Schuh2dd86a92022-09-14 21:19:23 -07001762 "ByteBuffer) -> {{STRUCTTYPE}}? {";
Austin Schuh272c6132020-11-14 16:37:52 -08001763 Indent();
1764 if (IsString(key_field.value.type))
1765 code_ += "let key = key.utf8.map { $0 }";
1766 code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
1767 code_ += "var start: Int32 = 0";
1768 code_ += "while span != 0 {";
1769 Indent();
1770 code_ += "var middle = span / 2";
1771 code_ +=
1772 "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
1773 if (IsString(key_field.value.type)) {
1774 code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
1775 } else {
1776 code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
1777 offset_reader + "))";
1778 }
1779
1780 code_ += "if comp > 0 {";
1781 Indent();
1782 code_ += "span = middle";
1783 Outdent();
1784 code_ += "} else if comp < 0 {";
1785 Indent();
1786 code_ += "middle += 1";
1787 code_ += "start += middle";
1788 code_ += "span -= middle";
1789 Outdent();
1790 code_ += "} else {";
1791 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001792 code_ += "return {{STRUCTTYPE}}(fbb, o: tableOffset)";
Austin Schuh272c6132020-11-14 16:37:52 -08001793 Outdent();
1794 code_ += "}";
1795 Outdent();
1796 code_ += "}";
1797 code_ += "return nil";
1798 Outdent();
1799 code_ += "}";
1800 }
1801
James Kuszmaul8e62b022022-03-22 09:33:25 -07001802 inline void GenPadding(const FieldDef &field, int *id) {
1803 if (field.padding) {
1804 for (int i = 0; i < 4; i++) {
1805 if (static_cast<int>(field.padding) & (1 << i)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001806 const auto bits = (1 << i) * 8;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001807 code_ += "private let padding" + NumToString((*id)++) + "__: UInt" +
1808 NumToString(bits) + " = 0";
1809 }
1810 }
1811 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
1812 }
1813 }
1814
Austin Schuh272c6132020-11-14 16:37:52 -08001815 void GenComment(const std::vector<std::string> &dc) {
1816 if (dc.begin() == dc.end()) {
1817 // Don't output empty comment blocks with 0 lines of comment content.
1818 return;
1819 }
1820 for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
1821 }
1822
1823 std::string GenOffset() {
1824 return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
1825 }
1826
1827 std::string GenReaderMainBody(const std::string &optional = "") {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001828 return "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + optional + " { ";
Austin Schuh272c6132020-11-14 16:37:52 -08001829 }
1830
1831 std::string GenReader(const std::string &type,
1832 const std::string &at = "{{OFFSET}}") {
1833 return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
1834 }
1835
1836 std::string GenConstructor(const std::string &offset) {
1837 return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
1838 }
1839
1840 std::string GenMutate(const std::string &offset,
1841 const std::string &get_offset, bool isRaw = false) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001842 return "@discardableResult {{ACCESS_TYPE}} func mutate({{FIELDVAR}}: "
Austin Schuh272c6132020-11-14 16:37:52 -08001843 "{{VALUETYPE}}) -> Bool {" +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001844 get_offset + " return {{ACCESS}}.mutate({{FIELDVAR}}" +
Austin Schuh272c6132020-11-14 16:37:52 -08001845 (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
1846 }
1847
1848 std::string GenMutateArray() {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001849 return "{{ACCESS_TYPE}} func mutate({{FIELDVAR}}: {{VALUETYPE}}, at "
1850 "index: Int32) -> Bool { " +
Austin Schuh272c6132020-11-14 16:37:52 -08001851 GenOffset() +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001852 "return {{ACCESS}}.directMutate({{FIELDVAR}}, index: "
Austin Schuh272c6132020-11-14 16:37:52 -08001853 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
1854 }
1855
1856 std::string GenEnumDefaultValue(const FieldDef &field) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001857 const auto &value = field.value;
Austin Schuh272c6132020-11-14 16:37:52 -08001858 FLATBUFFERS_ASSERT(value.type.enum_def);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001859 const auto &enum_def = *value.type.enum_def;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001860 // Vector of enum defaults are always "[]" which never works.
1861 const std::string constant = IsVector(value.type) ? "0" : value.constant;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001862 const auto enum_val = enum_def.FindByValue(constant);
Austin Schuh272c6132020-11-14 16:37:52 -08001863 if (enum_val) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001864 return "." + namer_.LegacySwiftVariant(*enum_val);
Austin Schuh272c6132020-11-14 16:37:52 -08001865 } else {
1866 const auto &ev = **enum_def.Vals().begin();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001867 return "." + namer_.LegacySwiftVariant(ev);
Austin Schuh272c6132020-11-14 16:37:52 -08001868 }
Austin Schuh272c6132020-11-14 16:37:52 -08001869 }
1870
1871 std::string GenEnumConstructor(const std::string &at) {
1872 return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
1873 }
1874
1875 std::string ValidateFunc() {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001876 return "static func validateVersion() { FlatBuffersVersion_2_0_8() }";
Austin Schuh272c6132020-11-14 16:37:52 -08001877 }
1878
1879 std::string GenType(const Type &type,
1880 const bool should_consider_suffix = false) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001881 return IsScalar(type.base_type) ? GenTypeBasic(type)
1882 : IsArray(type) ? GenType(type.VectorType())
1883 : GenTypePointer(type, should_consider_suffix);
Austin Schuh272c6132020-11-14 16:37:52 -08001884 }
1885
1886 std::string GenTypePointer(const Type &type,
1887 const bool should_consider_suffix) const {
1888 switch (type.base_type) {
1889 case BASE_TYPE_STRING: return "String";
1890 case BASE_TYPE_VECTOR: return GenType(type.VectorType());
1891 case BASE_TYPE_STRUCT: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001892 const auto &sd = *type.struct_def;
1893 if (should_consider_suffix && !sd.fixed) {
1894 return namer_.NamespacedObjectType(sd);
Austin Schuh272c6132020-11-14 16:37:52 -08001895 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001896 return namer_.NamespacedType(sd);
Austin Schuh272c6132020-11-14 16:37:52 -08001897 }
1898 case BASE_TYPE_UNION:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001899 default: return "FlatbuffersInitializable";
Austin Schuh272c6132020-11-14 16:37:52 -08001900 }
1901 }
1902
1903 std::string GenTypeBasic(const Type &type) const {
1904 return GenTypeBasic(type, true);
1905 }
1906
Austin Schuh272c6132020-11-14 16:37:52 -08001907 void Indent() { code_.IncrementIdentLevel(); }
1908
1909 void Outdent() { code_.DecrementIdentLevel(); }
1910
Austin Schuh272c6132020-11-14 16:37:52 -08001911 std::string GenTypeBasic(const Type &type, bool can_override) const {
1912 // clang-format off
1913 static const char * const swift_type[] = {
1914 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1915 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
1916 #STYPE,
1917 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1918 #undef FLATBUFFERS_TD
1919 };
1920 // clang-format on
1921 if (can_override) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001922 if (type.enum_def) return namer_.NamespacedType(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001923 if (type.base_type == BASE_TYPE_BOOL) return "Bool";
1924 }
1925 return swift_type[static_cast<int>(type.base_type)];
1926 }
1927
James Kuszmaul8e62b022022-03-22 09:33:25 -07001928 std::string Mutable() const { return "_Mutable"; }
1929
Austin Schuh2dd86a92022-09-14 21:19:23 -07001930 IdlNamer namer_;
Austin Schuh272c6132020-11-14 16:37:52 -08001931};
1932} // namespace swift
1933bool GenerateSwift(const Parser &parser, const std::string &path,
1934 const std::string &file_name) {
1935 swift::SwiftGenerator generator(parser, path, file_name);
1936 return generator.generate();
1937}
1938} // namespace flatbuffers