blob: c7cf2b5c8830b7a8a03797a62ab4179f1f591103 [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;
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001201 const bool is_private_access = parser_.opts.swift_implementation_only ||
1202 enum_def.attributes.Lookup("private") != nullptr;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001203 code_.SetValue("ENUM_TYPE",
1204 enum_def.is_union ? "UnionEnum" : "Enum, Verifiable");
Austin Schuh272c6132020-11-14 16:37:52 -08001205 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
Austin Schuh2dd86a92022-09-14 21:19:23 -07001206 code_.SetValue("ENUM_NAME", namer_.NamespacedType(enum_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001207 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1208 GenComment(enum_def.doc_comment);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001209 code_ +=
1210 "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001211 Indent();
1212 code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001213 if (enum_def.is_union) {
1214 code_ += "";
1215 code_ += "{{ACCESS_TYPE}} init?(value: T) {";
1216 Indent();
1217 code_ += "self.init(rawValue: value)";
1218 Outdent();
1219 code_ += "}\n";
1220 }
Austin Schuh272c6132020-11-14 16:37:52 -08001221 code_ +=
1222 "{{ACCESS_TYPE}} static var byteSize: Int { return "
1223 "MemoryLayout<{{BASE_TYPE}}>.size "
1224 "}";
1225 code_ +=
1226 "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
1227 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1228 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001229 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
Austin Schuh272c6132020-11-14 16:37:52 -08001230 code_.SetValue("VALUE", enum_def.ToString(ev));
1231 GenComment(ev.doc_comment);
1232 code_ += "case {{KEY}} = {{VALUE}}";
1233 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001234 code_ += "";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001235 AddMinOrMaxEnumValue(namer_.LegacySwiftVariant(*enum_def.MaxValue()),
1236 "max");
1237 AddMinOrMaxEnumValue(namer_.LegacySwiftVariant(*enum_def.MinValue()),
1238 "min");
Austin Schuh272c6132020-11-14 16:37:52 -08001239 Outdent();
1240 code_ += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001241 if (parser_.opts.gen_json_coders) EnumEncoder(enum_def);
1242 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001243 if (parser_.opts.generate_object_based_api && enum_def.is_union) {
1244 code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
1245 Indent();
1246 code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001247 code_ += "{{ACCESS_TYPE}} var value: NativeObject?";
1248 code_ +=
1249 "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {";
Austin Schuh272c6132020-11-14 16:37:52 -08001250 Indent();
1251 code_ += "self.type = type";
1252 code_ += "self.value = v";
1253 Outdent();
1254 code_ += "}";
1255 code_ +=
1256 "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07001257 "Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -08001258 Indent();
1259 BuildUnionEnumSwitchCaseWritter(enum_def);
1260 Outdent();
1261 code_ += "}";
1262 Outdent();
1263 code_ += "}";
1264 }
1265 }
1266
James Kuszmaul8e62b022022-03-22 09:33:25 -07001267 void EnumEncoder(const EnumDef &enum_def) {
1268 code_ += "extension {{ENUM_NAME}}: Encodable {";
1269 Indent();
1270 code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
1271 Indent();
1272 code_ += "var container = encoder.singleValueContainer()";
1273 code_ += "switch self {";
1274 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1275 const auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001276 code_.SetValue("KEY", namer_.LegacySwiftVariant(ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001277 code_.SetValue("RAWKEY", ev.name);
1278 code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")";
1279 }
1280 code_ += "}";
1281 Outdent();
1282 code_ += "}";
1283 Outdent();
1284 code_ += "}";
1285 }
1286
1287 // MARK: - Object API
1288
Austin Schuh2dd86a92022-09-14 21:19:23 -07001289 void GenerateObjectAPIExtensionHeader(std::string type_name) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001290 code_ += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001291 code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + type_name + " {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001292 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001293 code_ += "return " + type_name + "(&self)";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001294 Outdent();
1295 code_ += "}";
1296 code_ +=
1297 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1298 "obj: "
1299 "inout " +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001300 type_name + "?) -> Offset {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001301 Indent();
1302 code_ += "guard var obj = obj else { return Offset() }";
1303 code_ += "return pack(&builder, obj: &obj)";
1304 Outdent();
1305 code_ += "}";
1306 code_ += "";
1307 code_ +=
1308 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1309 "obj: "
1310 "inout " +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001311 type_name + ") -> Offset {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001312 Indent();
1313 }
1314
1315 void GenerateObjectAPIStructConstructor(const StructDef &struct_def) {
1316 code_ +=
1317 "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {";
1318 Indent();
1319 for (auto it = struct_def.fields.vec.begin();
1320 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001321 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001322 if (field.deprecated) continue;
1323
Austin Schuh2dd86a92022-09-14 21:19:23 -07001324 const auto type = GenType(field.value.type);
1325 code_.SetValue("FIELDVAR", namer_.Variable(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001326 if (IsStruct(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001327 code_ += "var _v{{FIELDVAR}} = _t.{{FIELDVAR}}";
1328 code_ += "_{{FIELDVAR}} = _v{{FIELDVAR}}.unpack()";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001329 continue;
1330 }
1331 std::string is_enum = IsEnum(field.value.type) ? ".value" : "";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001332 code_ += "_{{FIELDVAR}} = _t.{{FIELDVAR}}" + is_enum;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001333 }
1334 Outdent();
1335 code_ += "}\n";
1336 }
1337
Austin Schuh272c6132020-11-14 16:37:52 -08001338 void GenObjectAPI(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001339 code_ += "{{ACCESS_TYPE}} class " +
1340 namer_.NamespacedObjectType(struct_def) + ": NativeObject {\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001341 std::vector<std::string> buffer_constructor;
1342 std::vector<std::string> base_constructor;
1343 Indent();
1344 for (auto it = struct_def.fields.vec.begin();
1345 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001346 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001347 if (field.deprecated) continue;
1348 BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
1349 base_constructor);
1350 }
1351 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001352 BuildObjectConstructor(buffer_constructor,
Austin Schuh2dd86a92022-09-14 21:19:23 -07001353 "_ _t: inout " + namer_.NamespacedType(struct_def));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001354 BuildObjectConstructor(base_constructor);
Austin Schuh272c6132020-11-14 16:37:52 -08001355 if (!struct_def.fixed)
1356 code_ +=
1357 "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
1358 "serialize(type: "
1359 "{{STRUCTNAME}}.self) }\n";
1360 Outdent();
1361 code_ += "}";
1362 }
1363
1364 void GenerateObjectAPITableExtension(const StructDef &struct_def) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001365 GenerateObjectAPIExtensionHeader(namer_.NamespacedObjectType(struct_def));
Austin Schuh272c6132020-11-14 16:37:52 -08001366 std::vector<std::string> unpack_body;
1367 std::string builder = ", &builder)";
1368 for (auto it = struct_def.fields.vec.begin();
1369 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001370 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08001371 if (field.deprecated) continue;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001372 const auto field_var = namer_.Variable(field);
1373 const auto field_field = namer_.Field(field);
1374 const auto field_method = namer_.Method(field);
1375 const auto type = GenType(field.value.type);
Austin Schuh272c6132020-11-14 16:37:52 -08001376 std::string check_if_vector =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001377 (IsVector(field.value.type) || IsArray(field.value.type))
Austin Schuh272c6132020-11-14 16:37:52 -08001378 ? "VectorOf("
1379 : "(";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001380 std::string body = "add" + check_if_vector + field_method + ": ";
Austin Schuh272c6132020-11-14 16:37:52 -08001381 switch (field.value.type.base_type) {
1382 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1383 case BASE_TYPE_VECTOR: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001384 GenerateVectorObjectAPITableExtension(field);
1385 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001386 builder);
1387 break;
1388 }
1389 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001390 code_ += "let __" + field_var + " = obj." + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001391 "?.pack(builder: &builder) ?? Offset()";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001392 unpack_body.push_back("if let o = obj." + field_var + "?.type {");
1393 unpack_body.push_back(" {{STRUCTNAME}}.add(" + field_var +
1394 "Type: o" + builder);
1395 unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001396 builder);
1397 unpack_body.push_back("}\n");
1398 break;
1399 }
1400 case BASE_TYPE_STRUCT: {
1401 if (field.value.type.struct_def &&
1402 field.value.type.struct_def->fixed) {
1403 // This is a Struct (IsStruct), not a table. We create
James Kuszmaul8e62b022022-03-22 09:33:25 -07001404 // a native swift object in this case.
Austin Schuh272c6132020-11-14 16:37:52 -08001405 std::string code;
1406 GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
1407 "$0", true);
1408 code = code.substr(0, code.size() - 2);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001409 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." +
1410 field_field + builder);
Austin Schuh272c6132020-11-14 16:37:52 -08001411 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001412 code_ += "let __" + field_var + " = " + type +
1413 ".pack(&builder, obj: &obj." + field_field + ")";
1414 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001415 builder);
1416 }
1417 break;
1418 }
1419 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001420 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + field_var +
Austin Schuh272c6132020-11-14 16:37:52 -08001421 builder);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001422 if (field.IsRequired()) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001423 code_ += "let __" + field_var + " = builder.create(string: obj." +
1424 field_field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001425 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001426 BuildingOptionalObjects(field_field, "builder.create(string: s)");
Austin Schuh272c6132020-11-14 16:37:52 -08001427 }
1428 break;
1429 }
1430 case BASE_TYPE_UTYPE: break;
1431 default:
Austin Schuh2dd86a92022-09-14 21:19:23 -07001432 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." +
1433 field_field + builder);
Austin Schuh272c6132020-11-14 16:37:52 -08001434 }
1435 }
1436 code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
1437 for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
1438 code_ += *it;
1439 code_ +=
1440 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
1441 "__root)";
1442 Outdent();
1443 code_ += "}";
1444 }
1445
Austin Schuh2dd86a92022-09-14 21:19:23 -07001446 void GenerateVectorObjectAPITableExtension(const FieldDef &field_def) {
1447 const Type &field_type = field_def.value.type;
1448 const auto type = GenType(field_type);
1449 const auto var = namer_.Variable(field_def);
1450 const auto field = namer_.Field(field_def);
1451
1452 const auto vectortype = field_type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -08001453 switch (vectortype.base_type) {
1454 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001455 code_ += "var __" + var + "__: [Offset] = []";
1456 code_ += "for i in obj." + var + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001457 Indent();
1458 code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001459 code_ += "__" + var + "__.append(off)";
Austin Schuh272c6132020-11-14 16:37:52 -08001460 Outdent();
1461 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001462 code_ += "let __" + var + " = builder.createVector(ofOffsets: __" +
1463 var + "__)";
1464 code_ += "let __" + var + "Type = builder.createVector(obj." + field +
Austin Schuh272c6132020-11-14 16:37:52 -08001465 ".compactMap { $0?.type })";
1466 break;
1467 }
1468 case BASE_TYPE_UTYPE: break;
1469 case BASE_TYPE_STRUCT: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001470 if (field_type.struct_def && !field_type.struct_def->fixed) {
1471 code_ += "var __" + var + "__: [Offset] = []";
1472 code_ += "for var i in obj." + var + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001473 Indent();
1474 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001475 "__" + var + "__.append(" + type + ".pack(&builder, obj: &i))";
Austin Schuh272c6132020-11-14 16:37:52 -08001476 Outdent();
1477 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001478 code_ += "let __" + var + " = builder.createVector(ofOffsets: __" +
1479 var + "__)";
Austin Schuh272c6132020-11-14 16:37:52 -08001480 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001481 code_ += "{{STRUCTNAME}}." + namer_.Method("start_vector_of", var) +
1482 "(obj." + field + ".count, in: &builder)";
Austin Schuh272c6132020-11-14 16:37:52 -08001483 std::string code;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001484 GenerateStructArgs(*field_type.struct_def, &code, "", "", "_o", true);
Austin Schuh272c6132020-11-14 16:37:52 -08001485 code = code.substr(0, code.size() - 2);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001486 code_ += "for i in obj." + field + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001487 Indent();
1488 code_ += "guard let _o = i else { continue }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001489 code_ += "builder.create(struct: _o)";
Austin Schuh272c6132020-11-14 16:37:52 -08001490 Outdent();
1491 code_ += "}";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001492 code_ += "let __" + var + " = builder.endVector(len: obj." + field +
Austin Schuh272c6132020-11-14 16:37:52 -08001493 ".count)";
1494 }
1495 break;
1496 }
1497 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001498 code_ += "let __" + var + " = builder.createVector(ofStrings: obj." +
1499 var + ".compactMap({ $0 }) )";
Austin Schuh272c6132020-11-14 16:37:52 -08001500 break;
1501 }
1502 default: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001503 code_ += "let __" + var + " = builder.createVector(obj." + field + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001504 break;
1505 }
1506 }
1507 }
1508
Austin Schuh2dd86a92022-09-14 21:19:23 -07001509 void BuildingOptionalObjects(const std::string &var,
Austin Schuh272c6132020-11-14 16:37:52 -08001510 const std::string &body_front) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001511 code_ += "let __" + var + ": Offset";
1512 code_ += "if let s = obj." + var + " {";
Austin Schuh272c6132020-11-14 16:37:52 -08001513 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001514 code_ += "__" + var + " = " + body_front;
Austin Schuh272c6132020-11-14 16:37:52 -08001515 Outdent();
1516 code_ += "} else {";
1517 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001518 code_ += "__" + var + " = Offset()";
Austin Schuh272c6132020-11-14 16:37:52 -08001519 Outdent();
1520 code_ += "}";
1521 code_ += "";
1522 }
1523
James Kuszmaul8e62b022022-03-22 09:33:25 -07001524 void BuildObjectConstructor(const std::vector<std::string> &body,
1525 const std::string &header = "") {
Austin Schuh272c6132020-11-14 16:37:52 -08001526 code_.SetValue("HEADER", header);
1527 code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
1528 Indent();
1529 for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
1530 Outdent();
1531 code_ += "}\n";
1532 }
1533
1534 void BuildObjectAPIConstructorBody(
1535 const FieldDef &field, bool is_fixed,
1536 std::vector<std::string> &buffer_constructor,
1537 std::vector<std::string> &base_constructor) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001538 const auto field_field = namer_.Field(field);
1539 const auto field_var = namer_.Variable(field);
1540 const auto type = GenType(field.value.type);
1541 code_.SetValue("FIELDVAR", field_field);
Austin Schuh272c6132020-11-14 16:37:52 -08001542 code_.SetValue("VALUETYPE", type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001543 std::string is_required = field.IsRequired() ? "" : "?";
Austin Schuh272c6132020-11-14 16:37:52 -08001544
1545 switch (field.value.type.base_type) {
1546 case BASE_TYPE_STRUCT: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001547 const auto objtype = GenType(field.value.type, true);
1548 code_.SetValue("VALUETYPE", objtype);
1549 const auto optional =
Austin Schuh272c6132020-11-14 16:37:52 -08001550 (field.value.type.struct_def && field.value.type.struct_def->fixed);
1551 std::string question_mark =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001552 (field.IsRequired() || (optional && is_fixed) ? "" : "?");
Austin Schuh272c6132020-11-14 16:37:52 -08001553
1554 code_ +=
Austin Schuh2dd86a92022-09-14 21:19:23 -07001555 "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + question_mark;
1556 base_constructor.push_back("" + field_var + " = " + objtype + "()");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001557
1558 if (field.value.type.struct_def->fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001559 buffer_constructor.push_back("" + field_var + " = _t." + field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001560 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001561 buffer_constructor.push_back("var __" + field_var + " = _t." +
1562 field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001563 buffer_constructor.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001564 "" + field_var + " = __" + field_var +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001565 (field.IsRequired() ? "!" : question_mark) + ".unpack()");
1566 }
Austin Schuh272c6132020-11-14 16:37:52 -08001567 break;
1568 }
1569 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1570 case BASE_TYPE_VECTOR: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001571 BuildObjectAPIConstructorBodyVectors(field, buffer_constructor,
Austin Schuh272c6132020-11-14 16:37:52 -08001572 base_constructor, " ");
1573 break;
1574 }
1575 case BASE_TYPE_STRING: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001576 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: String" + is_required;
1577 buffer_constructor.push_back(field_var + " = _t." + field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001578
1579 if (field.IsRequired()) {
1580 std::string default_value =
1581 field.IsDefault() ? field.value.constant : "";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001582 base_constructor.push_back(field_var + " = \"" + default_value +
1583 "\"");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001584 break;
1585 }
1586 if (field.IsDefault() && !field.IsRequired()) {
1587 std::string value = field.IsDefault() ? field.value.constant : "nil";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001588 base_constructor.push_back(field_var + " = \"" + value + "\"");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001589 }
Austin Schuh272c6132020-11-14 16:37:52 -08001590 break;
1591 }
1592 case BASE_TYPE_UTYPE: break;
1593 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001594 BuildUnionEnumSwitchCase(*field.value.type.enum_def, field_var,
Austin Schuh272c6132020-11-14 16:37:52 -08001595 buffer_constructor);
1596 break;
1597 }
1598 default: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001599 buffer_constructor.push_back(field_var + " = _t." + field_field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001600 std::string nullable = field.IsOptional() ? "?" : "";
Austin Schuh272c6132020-11-14 16:37:52 -08001601 if (IsScalar(field.value.type.base_type) &&
1602 !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001603 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + nullable;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001604 if (!field.IsOptional())
Austin Schuh2dd86a92022-09-14 21:19:23 -07001605 base_constructor.push_back(field_var + " = " +
1606 field.value.constant);
Austin Schuh272c6132020-11-14 16:37:52 -08001607 break;
1608 }
1609
1610 if (IsEnum(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001611 const auto default_value = IsEnum(field.value.type)
1612 ? GenEnumDefaultValue(field)
1613 : field.value.constant;
1614 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}";
1615 base_constructor.push_back(field_var + " = " + default_value);
Austin Schuh272c6132020-11-14 16:37:52 -08001616 break;
1617 }
1618
1619 if (IsBool(field.value.type.base_type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001620 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: Bool" + nullable;
Austin Schuh272c6132020-11-14 16:37:52 -08001621 std::string default_value =
1622 "0" == field.value.constant ? "false" : "true";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001623 if (!field.IsOptional())
Austin Schuh2dd86a92022-09-14 21:19:23 -07001624 base_constructor.push_back(field_var + " = " + default_value);
Austin Schuh272c6132020-11-14 16:37:52 -08001625 }
1626 }
1627 }
1628 }
1629
1630 void BuildObjectAPIConstructorBodyVectors(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001631 const FieldDef &field, std::vector<std::string> &buffer_constructor,
Austin Schuh272c6132020-11-14 16:37:52 -08001632 std::vector<std::string> &base_constructor,
1633 const std::string &indentation) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001634 const auto vectortype = field.value.type.VectorType();
1635 const auto field_var = namer_.Field(field);
1636 const auto field_field = namer_.Field(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001637
1638 if (vectortype.base_type != BASE_TYPE_UTYPE) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001639 buffer_constructor.push_back(field_var + " = []");
1640 buffer_constructor.push_back("for index in 0..<_t." + field_field +
1641 "Count {");
1642 base_constructor.push_back(field_var + " = []");
Austin Schuh272c6132020-11-14 16:37:52 -08001643 }
1644
1645 switch (vectortype.base_type) {
1646 case BASE_TYPE_STRUCT: {
1647 code_.SetValue("VALUETYPE", GenType(vectortype, true));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001648 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}?]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001649 if (!vectortype.struct_def->fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001650 buffer_constructor.push_back(indentation + "var __v_ = _t." +
1651 field_field + "(at: index)");
1652 buffer_constructor.push_back(indentation + field_var +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001653 ".append(__v_?.unpack())");
1654 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001655 buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1656 field_var + "(at: index))");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001657 }
Austin Schuh272c6132020-11-14 16:37:52 -08001658 break;
1659 }
1660 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1661 case BASE_TYPE_VECTOR: {
1662 break;
1663 }
1664 case BASE_TYPE_UNION: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001665 BuildUnionEnumSwitchCase(*field.value.type.enum_def, field_var,
Austin Schuh272c6132020-11-14 16:37:52 -08001666 buffer_constructor, indentation, true);
1667 break;
1668 }
1669 case BASE_TYPE_UTYPE: break;
1670 default: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001671 code_.SetValue(
1672 "VALUETYPE",
1673 (IsString(vectortype) ? "String?" : GenType(vectortype)));
Austin Schuh2dd86a92022-09-14 21:19:23 -07001674 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: [{{VALUETYPE}}]";
Austin Schuh272c6132020-11-14 16:37:52 -08001675
1676 if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001677 const auto default_value = IsEnum(field.value.type)
1678 ? GenEnumDefaultValue(field)
1679 : field.value.constant;
1680 buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1681 field_field + "(at: index)!)");
Austin Schuh272c6132020-11-14 16:37:52 -08001682 break;
1683 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001684 buffer_constructor.push_back(indentation + field_var + ".append(_t." +
1685 field_field + "(at: index))");
Austin Schuh272c6132020-11-14 16:37:52 -08001686 break;
1687 }
1688 }
1689 if (vectortype.base_type != BASE_TYPE_UTYPE)
1690 buffer_constructor.push_back("}");
1691 }
1692
Austin Schuh2dd86a92022-09-14 21:19:23 -07001693 void BuildUnionEnumSwitchCaseWritter(const EnumDef &ed) {
Austin Schuh272c6132020-11-14 16:37:52 -08001694 code_ += "switch type {";
Austin Schuh2dd86a92022-09-14 21:19:23 -07001695 for (auto it = ed.Vals().begin(); it < ed.Vals().end(); ++it) {
1696 const auto ev = **it;
1697 const auto variant = namer_.LegacySwiftVariant(ev);
1698 const auto type = GenType(ev.union_type);
1699 const auto is_struct = IsStruct(ev.union_type) ? type + Mutable() : type;
1700 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1701 code_ += "case ." + variant + ":";
Austin Schuh272c6132020-11-14 16:37:52 -08001702 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001703 code_ += "var __obj = value as? " + GenType(ev.union_type, true);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001704 code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)";
Austin Schuh272c6132020-11-14 16:37:52 -08001705 Outdent();
1706 }
1707 code_ += "default: return Offset()";
1708 code_ += "}";
1709 }
1710
Austin Schuh2dd86a92022-09-14 21:19:23 -07001711 void BuildUnionEnumSwitchCase(const EnumDef &ed, const std::string &field,
Austin Schuh272c6132020-11-14 16:37:52 -08001712 std::vector<std::string> &buffer_constructor,
1713 const std::string &indentation = "",
1714 const bool is_vector = false) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001715 const auto ns_type = namer_.NamespacedType(ed);
1716 code_.SetValue("VALUETYPE", ns_type);
1717 code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}: \\";
Austin Schuh272c6132020-11-14 16:37:52 -08001718 code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
1719
Austin Schuh2dd86a92022-09-14 21:19:23 -07001720 const auto vector_reader = is_vector ? "(at: index" : "";
1721 buffer_constructor.push_back(indentation + "switch _t." + field + "Type" +
Austin Schuh272c6132020-11-14 16:37:52 -08001722 vector_reader + (is_vector ? ")" : "") + " {");
1723
Austin Schuh2dd86a92022-09-14 21:19:23 -07001724 for (auto it = ed.Vals().begin(); it < ed.Vals().end(); ++it) {
1725 const auto ev = **it;
1726 const auto variant = namer_.LegacySwiftVariant(ev);
1727 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1728 const auto type = IsStruct(ev.union_type)
1729 ? GenType(ev.union_type) + Mutable()
1730 : GenType(ev.union_type);
1731 buffer_constructor.push_back(indentation + "case ." + variant + ":");
Austin Schuh272c6132020-11-14 16:37:52 -08001732 buffer_constructor.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001733 indentation + " var _v = _t." + field + (is_vector ? "" : "(") +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001734 vector_reader + (is_vector ? ", " : "") + "type: " + type + ".self)");
Austin Schuh2dd86a92022-09-14 21:19:23 -07001735 const auto constructor =
1736 ns_type + "Union(_v?.unpack(), type: ." + variant + ")";
Austin Schuh272c6132020-11-14 16:37:52 -08001737 buffer_constructor.push_back(
Austin Schuh2dd86a92022-09-14 21:19:23 -07001738 indentation + " " + field +
Austin Schuh272c6132020-11-14 16:37:52 -08001739 (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
1740 }
1741 buffer_constructor.push_back(indentation + "default: break");
1742 buffer_constructor.push_back(indentation + "}");
1743 }
1744
1745 void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001746 const auto current_value = str;
Austin Schuh272c6132020-11-14 16:37:52 -08001747 code_.SetValue(type, current_value);
1748 code_ += "{{ACCESS_TYPE}} static var " + type +
1749 ": {{ENUM_NAME}} { return .{{" + type + "}} }";
1750 }
1751
Austin Schuh2dd86a92022-09-14 21:19:23 -07001752 void GenLookup(const FieldDef &key_field, const std::string &struct_type) {
1753 code_.SetValue("STRUCTTYPE", struct_type);
Austin Schuh272c6132020-11-14 16:37:52 -08001754 code_.SetValue("OFFSET", NumToString(key_field.value.offset));
1755 std::string offset_reader =
1756 "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
1757 "fbb: fbb)";
1758
1759 code_.SetValue("TYPE", GenType(key_field.value.type));
1760 code_ +=
1761 "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
1762 "fbb: "
Austin Schuh2dd86a92022-09-14 21:19:23 -07001763 "ByteBuffer) -> {{STRUCTTYPE}}? {";
Austin Schuh272c6132020-11-14 16:37:52 -08001764 Indent();
1765 if (IsString(key_field.value.type))
1766 code_ += "let key = key.utf8.map { $0 }";
1767 code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
1768 code_ += "var start: Int32 = 0";
1769 code_ += "while span != 0 {";
1770 Indent();
1771 code_ += "var middle = span / 2";
1772 code_ +=
1773 "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
1774 if (IsString(key_field.value.type)) {
1775 code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
1776 } else {
1777 code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
1778 offset_reader + "))";
1779 }
1780
1781 code_ += "if comp > 0 {";
1782 Indent();
1783 code_ += "span = middle";
1784 Outdent();
1785 code_ += "} else if comp < 0 {";
1786 Indent();
1787 code_ += "middle += 1";
1788 code_ += "start += middle";
1789 code_ += "span -= middle";
1790 Outdent();
1791 code_ += "} else {";
1792 Indent();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001793 code_ += "return {{STRUCTTYPE}}(fbb, o: tableOffset)";
Austin Schuh272c6132020-11-14 16:37:52 -08001794 Outdent();
1795 code_ += "}";
1796 Outdent();
1797 code_ += "}";
1798 code_ += "return nil";
1799 Outdent();
1800 code_ += "}";
1801 }
1802
James Kuszmaul8e62b022022-03-22 09:33:25 -07001803 inline void GenPadding(const FieldDef &field, int *id) {
1804 if (field.padding) {
1805 for (int i = 0; i < 4; i++) {
1806 if (static_cast<int>(field.padding) & (1 << i)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001807 const auto bits = (1 << i) * 8;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001808 code_ += "private let padding" + NumToString((*id)++) + "__: UInt" +
1809 NumToString(bits) + " = 0";
1810 }
1811 }
1812 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
1813 }
1814 }
1815
Austin Schuh272c6132020-11-14 16:37:52 -08001816 void GenComment(const std::vector<std::string> &dc) {
1817 if (dc.begin() == dc.end()) {
1818 // Don't output empty comment blocks with 0 lines of comment content.
1819 return;
1820 }
1821 for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
1822 }
1823
1824 std::string GenOffset() {
1825 return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
1826 }
1827
1828 std::string GenReaderMainBody(const std::string &optional = "") {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001829 return "{{ACCESS_TYPE}} var {{FIELDVAR}}: {{VALUETYPE}}" + optional + " { ";
Austin Schuh272c6132020-11-14 16:37:52 -08001830 }
1831
1832 std::string GenReader(const std::string &type,
1833 const std::string &at = "{{OFFSET}}") {
1834 return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
1835 }
1836
1837 std::string GenConstructor(const std::string &offset) {
1838 return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
1839 }
1840
1841 std::string GenMutate(const std::string &offset,
1842 const std::string &get_offset, bool isRaw = false) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001843 return "@discardableResult {{ACCESS_TYPE}} func mutate({{FIELDVAR}}: "
Austin Schuh272c6132020-11-14 16:37:52 -08001844 "{{VALUETYPE}}) -> Bool {" +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001845 get_offset + " return {{ACCESS}}.mutate({{FIELDVAR}}" +
Austin Schuh272c6132020-11-14 16:37:52 -08001846 (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
1847 }
1848
1849 std::string GenMutateArray() {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001850 return "{{ACCESS_TYPE}} func mutate({{FIELDVAR}}: {{VALUETYPE}}, at "
1851 "index: Int32) -> Bool { " +
Austin Schuh272c6132020-11-14 16:37:52 -08001852 GenOffset() +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001853 "return {{ACCESS}}.directMutate({{FIELDVAR}}, index: "
Austin Schuh272c6132020-11-14 16:37:52 -08001854 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
1855 }
1856
1857 std::string GenEnumDefaultValue(const FieldDef &field) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001858 const auto &value = field.value;
Austin Schuh272c6132020-11-14 16:37:52 -08001859 FLATBUFFERS_ASSERT(value.type.enum_def);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001860 const auto &enum_def = *value.type.enum_def;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001861 // Vector of enum defaults are always "[]" which never works.
1862 const std::string constant = IsVector(value.type) ? "0" : value.constant;
Austin Schuh2dd86a92022-09-14 21:19:23 -07001863 const auto enum_val = enum_def.FindByValue(constant);
Austin Schuh272c6132020-11-14 16:37:52 -08001864 if (enum_val) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001865 return "." + namer_.LegacySwiftVariant(*enum_val);
Austin Schuh272c6132020-11-14 16:37:52 -08001866 } else {
1867 const auto &ev = **enum_def.Vals().begin();
Austin Schuh2dd86a92022-09-14 21:19:23 -07001868 return "." + namer_.LegacySwiftVariant(ev);
Austin Schuh272c6132020-11-14 16:37:52 -08001869 }
Austin Schuh272c6132020-11-14 16:37:52 -08001870 }
1871
1872 std::string GenEnumConstructor(const std::string &at) {
1873 return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
1874 }
1875
1876 std::string ValidateFunc() {
James Kuszmaul3b15b0c2022-11-08 14:03:16 -08001877 return "static func validateVersion() { FlatBuffersVersion_22_10_26() }";
Austin Schuh272c6132020-11-14 16:37:52 -08001878 }
1879
1880 std::string GenType(const Type &type,
1881 const bool should_consider_suffix = false) const {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001882 return IsScalar(type.base_type) ? GenTypeBasic(type)
1883 : IsArray(type) ? GenType(type.VectorType())
1884 : GenTypePointer(type, should_consider_suffix);
Austin Schuh272c6132020-11-14 16:37:52 -08001885 }
1886
1887 std::string GenTypePointer(const Type &type,
1888 const bool should_consider_suffix) const {
1889 switch (type.base_type) {
1890 case BASE_TYPE_STRING: return "String";
1891 case BASE_TYPE_VECTOR: return GenType(type.VectorType());
1892 case BASE_TYPE_STRUCT: {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001893 const auto &sd = *type.struct_def;
1894 if (should_consider_suffix && !sd.fixed) {
1895 return namer_.NamespacedObjectType(sd);
Austin Schuh272c6132020-11-14 16:37:52 -08001896 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001897 return namer_.NamespacedType(sd);
Austin Schuh272c6132020-11-14 16:37:52 -08001898 }
1899 case BASE_TYPE_UNION:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001900 default: return "FlatbuffersInitializable";
Austin Schuh272c6132020-11-14 16:37:52 -08001901 }
1902 }
1903
1904 std::string GenTypeBasic(const Type &type) const {
1905 return GenTypeBasic(type, true);
1906 }
1907
Austin Schuh272c6132020-11-14 16:37:52 -08001908 void Indent() { code_.IncrementIdentLevel(); }
1909
1910 void Outdent() { code_.DecrementIdentLevel(); }
1911
Austin Schuh272c6132020-11-14 16:37:52 -08001912 std::string GenTypeBasic(const Type &type, bool can_override) const {
1913 // clang-format off
1914 static const char * const swift_type[] = {
1915 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1916 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
1917 #STYPE,
1918 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1919 #undef FLATBUFFERS_TD
1920 };
1921 // clang-format on
1922 if (can_override) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001923 if (type.enum_def) return namer_.NamespacedType(*type.enum_def);
Austin Schuh272c6132020-11-14 16:37:52 -08001924 if (type.base_type == BASE_TYPE_BOOL) return "Bool";
1925 }
1926 return swift_type[static_cast<int>(type.base_type)];
1927 }
1928
James Kuszmaul8e62b022022-03-22 09:33:25 -07001929 std::string Mutable() const { return "_Mutable"; }
1930
Austin Schuh2dd86a92022-09-14 21:19:23 -07001931 IdlNamer namer_;
Austin Schuh272c6132020-11-14 16:37:52 -08001932};
1933} // namespace swift
1934bool GenerateSwift(const Parser &parser, const std::string &path,
1935 const std::string &file_name) {
1936 swift::SwiftGenerator generator(parser, path, file_name);
1937 return generator.generate();
1938}
1939} // namespace flatbuffers