blob: c3c322fca1af543ec8e45bed7b48cc18c1b1d1d8 [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"
24
25namespace flatbuffers {
26
27namespace swift {
28
29inline std::string GenIndirect(const std::string &reading) {
30 return "{{ACCESS}}.indirect(" + reading + ")";
31}
32
33inline std::string GenArrayMainBody(const std::string &optional) {
34 return "{{ACCESS_TYPE}} func {{VALUENAME}}(at index: Int32) -> "
35 "{{VALUETYPE}}" +
36 optional + " { ";
37}
38
39class SwiftGenerator : public BaseGenerator {
40 private:
41 CodeWriter code_;
42 std::unordered_set<std::string> keywords_;
43 int namespace_depth;
44
45 public:
46 SwiftGenerator(const Parser &parser, const std::string &path,
47 const std::string &file_name)
48 : BaseGenerator(parser, path, file_name, "", "_", "swift") {
49 namespace_depth = 0;
Austin Schuh58b9b472020-11-25 19:12:44 -080050 code_.SetPadding(" ");
Austin Schuh272c6132020-11-14 16:37:52 -080051 static const char *const keywords[] = {
52 "associatedtype",
53 "class",
54 "deinit",
55 "enum",
56 "extension",
57 "fileprivate",
58 "func",
59 "import",
60 "init",
61 "inout",
62 "internal",
63 "let",
64 "open",
65 "operator",
66 "private",
67 "protocol",
68 "public",
69 "rethrows",
70 "static",
71 "struct",
72 "subscript",
73 "typealias",
74 "var",
75 "break",
76 "case",
77 "continue",
78 "default",
79 "defer",
80 "do",
81 "else",
82 "fallthrough",
83 "for",
84 "guard",
85 "if",
86 "in",
87 "repeat",
88 "return",
89 "switch",
90 "where",
91 "while",
92 "Any",
93 "catch",
94 "false",
95 "is",
96 "nil",
97 "super",
98 "self",
99 "Self",
100 "throw",
101 "throws",
102 "true",
103 "try",
104 "associativity",
105 "convenience",
106 "dynamic",
107 "didSet",
108 "final",
109 "get",
110 "infix",
111 "indirect",
112 "lazy",
113 "left",
114 "mutating",
115 "none",
116 "nonmutating",
117 "optional",
118 "override",
119 "postfix",
120 "precedence",
121 "prefix",
122 "Protocol",
123 "required",
124 "right",
125 "set",
126 "Type",
127 "unowned",
128 "weak",
129 "willSet",
James Kuszmaul8e62b022022-03-22 09:33:25 -0700130 "Void",
Austin Schuh272c6132020-11-14 16:37:52 -0800131 nullptr,
132 };
133 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
134 }
135
136 bool generate() {
137 code_.Clear();
138 code_.SetValue("ACCESS", "_accessor");
139 code_.SetValue("TABLEOFFSET", "VTOFFSET");
140 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
Austin Schuh58b9b472020-11-25 19:12:44 -0800141 code_ += "// swiftlint:disable all";
142 code_ += "// swiftformat:disable all\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800143 code_ += "import FlatBuffers\n";
144 // Generate code for all the enum declarations.
145
146 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
147 ++it) {
148 const auto &enum_def = **it;
149 if (!enum_def.generated) { GenEnum(enum_def); }
150 }
151
152 for (auto it = parser_.structs_.vec.begin();
153 it != parser_.structs_.vec.end(); ++it) {
154 const auto &struct_def = **it;
155 if (struct_def.fixed && !struct_def.generated) {
156 GenStructReader(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700157 GenMutableStructReader(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800158 }
159 }
160
161 for (auto it = parser_.structs_.vec.begin();
162 it != parser_.structs_.vec.end(); ++it) {
163 const auto &struct_def = **it;
164 if (!struct_def.fixed && !struct_def.generated) {
165 GenTable(struct_def);
166 if (parser_.opts.generate_object_based_api) {
167 GenObjectAPI(struct_def);
168 }
169 }
170 }
171
172 const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
173 const auto final_code = code_.ToString();
174 return SaveFile(filename.c_str(), final_code, false);
175 }
176
177 void mark(const std::string &str) {
178 code_.SetValue("MARKVALUE", str);
179 code_ += "\n// MARK: - {{MARKVALUE}}\n";
180 }
181
James Kuszmaul8e62b022022-03-22 09:33:25 -0700182 // MARK: - Generating structs
183
184 // Generates the reader for swift
185 void GenStructReader(const StructDef &struct_def) {
186 auto is_private_access = struct_def.attributes.Lookup("private");
187 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
188 GenComment(struct_def.doc_comment);
189 code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
190 code_ +=
191 "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct, Verifiable, "
192 "FlatbuffersInitializable\\";
193 if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\";
194 code_ += " {";
195 code_ += "";
196 Indent();
197 code_ += ValidateFunc();
198 code_ += "";
199 int padding_id = 0;
200 std::string constructor = "";
201 std::vector<std::string> base_constructor;
202 std::vector<std::string> main_constructor;
203
204 for (auto it = struct_def.fields.vec.begin();
205 it != struct_def.fields.vec.end(); ++it) {
206 auto &field = **it;
207 if (field.deprecated) continue;
208
209 if (!constructor.empty()) constructor += ", ";
210
211 auto name = Name(field);
212 auto type = GenType(field.value.type);
213 code_.SetValue("VALUENAME", name);
214 if (IsEnum(field.value.type)) {
215 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
216 }
217 code_.SetValue("VALUETYPE", type);
218 GenComment(field.doc_comment);
219 std::string valueType =
220 IsEnum(field.value.type) ? "{{BASEVALUE}}" : "{{VALUETYPE}}";
221 code_ += "private var _{{VALUENAME}}: " + valueType;
222 auto accessing_value = IsEnum(field.value.type) ? ".value" : "";
223 auto is_bool = IsBool(field.value.type.base_type);
224 auto base_value = IsStruct(field.value.type) ? (type + "()")
225 : is_bool ? ("0" == field.value.constant ? "false" : "true")
226 : field.value.constant;
227
228 main_constructor.push_back("_" + name + " = " + name + accessing_value);
229 base_constructor.push_back("_" + name + " = " + base_value);
230
231 if (field.padding) { GenPadding(field, &padding_id); }
232 constructor += name + ": " + type;
233 }
234 code_ += "";
235 BuildStructConstructor(struct_def);
236 BuildObjectConstructor(main_constructor, constructor);
237 BuildObjectConstructor(base_constructor, "");
238
239 if (parser_.opts.generate_object_based_api)
240 GenerateObjectAPIStructConstructor(struct_def);
241
242 for (auto it = struct_def.fields.vec.begin();
243 it != struct_def.fields.vec.end(); ++it) {
244 auto &field = **it;
245 if (field.deprecated) continue;
246 auto name = Name(field);
247 auto type = GenType(field.value.type);
248 code_.SetValue("VALUENAME", name);
249 code_.SetValue("VALUETYPE", type);
250 GenComment(field.doc_comment);
251 if (!IsEnum(field.value.type)) {
252 code_ += GenReaderMainBody() + "_{{VALUENAME}} }";
253 } else if (IsEnum(field.value.type)) {
254 code_ +=
255 GenReaderMainBody() + "{{VALUETYPE}}(rawValue: _{{VALUENAME}})! }";
256 }
257 }
258 code_ += "";
259 code_ +=
260 "public static func verify<T>(_ verifier: inout Verifier, at position: "
261 "Int, of type: T.Type) throws where T: Verifiable {";
262 Indent();
263 code_ +=
264 "try verifier.inBuffer(position: position, of: {{STRUCTNAME}}.self)";
265 Outdent();
266 code_ += "}";
267 Outdent();
268 code_ += "}\n";
269 if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
270 }
271
272 void BuildStructConstructor(const StructDef &struct_def) {
273 code_ += "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) {";
274 Indent();
275 code_ += "let {{ACCESS}} = Struct(bb: bb, position: o)";
276 for (auto it = struct_def.fields.vec.begin();
277 it != struct_def.fields.vec.end(); ++it) {
278 auto &field = **it;
279 if (field.deprecated) continue;
280 auto name = Name(field);
281 auto type = field.value.type;
282 code_.SetValue("VALUENAME", name);
283 code_.SetValue("VALUETYPE", GenType(type));
284 code_.SetValue("OFFSET", NumToString(field.value.offset));
285 if (IsScalar(type.base_type)) {
286 if (IsEnum(type))
287 code_.SetValue("VALUETYPE", GenTypeBasic(field.value.type, false));
288 code_ +=
289 "_{{VALUENAME}} = {{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, "
290 "at: {{OFFSET}})";
291 } else {
292 code_ +=
293 "_{{VALUENAME}} = {{VALUETYPE}}({{ACCESS}}.bb, o: "
294 "{{ACCESS}}.postion + {{OFFSET}})";
295 }
296 }
297 Outdent();
298 code_ += "}\n";
299 }
300
301 void GenMutableStructReader(const StructDef &struct_def) {
302 GenObjectHeader(struct_def);
303
304 for (auto it = struct_def.fields.vec.begin();
305 it != struct_def.fields.vec.end(); ++it) {
306 auto &field = **it;
307 if (field.deprecated) continue;
308 auto offset = NumToString(field.value.offset);
309 auto name = Name(field);
310 auto type = GenType(field.value.type);
311 code_.SetValue("VALUENAME", name);
312 if (IsEnum(field.value.type)) {
313 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
314 }
315 code_.SetValue("VALUETYPE", type);
316 code_.SetValue("OFFSET", offset);
317 if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
318 code_ +=
319 GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
320 } else if (IsEnum(field.value.type)) {
321 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
322 code_ += GenReaderMainBody() + "return " +
323 GenEnumConstructor("{{OFFSET}}") + "?? " +
324 GenEnumDefaultValue(field) + " }";
325 } else if (IsStruct(field.value.type)) {
326 code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
327 code_ += GenReaderMainBody() + "return " +
328 GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
329 }
330 if (parser_.opts.mutable_buffer && !IsStruct(field.value.type))
331 code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type));
332 }
333
334 if (parser_.opts.generate_object_based_api) {
335 GenerateObjectAPIExtensionHeader(NameWrappedInNameSpace(struct_def));
336 code_ += "return builder.create(struct: obj)";
337 Outdent();
338 code_ += "}";
339 }
340 Outdent();
341 code_ += "}\n";
342 }
343
Austin Schuh272c6132020-11-14 16:37:52 -0800344 // Generates the create function for swift
345 void GenStructWriter(const StructDef &struct_def) {
346 auto is_private_access = struct_def.attributes.Lookup("private");
347 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
348 code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
349 code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
350 code_ += "extension {{STRUCTNAME}} {";
351 Indent();
352 code_ += "@discardableResult";
353 code_ +=
354 "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout "
355 "FlatBufferBuilder, \\";
356 std::string func_header = "";
357 GenerateStructArgs(struct_def, &func_header, "", "");
358 code_ += func_header.substr(0, func_header.size() - 2) + "\\";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700359 code_ += ") -> Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -0800360 Indent();
361 code_ +=
362 "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
363 "{{STRUCTNAME}}.alignment)";
Austin Schuh272c6132020-11-14 16:37:52 -0800364 code_ += "return builder.endStruct()";
365 Outdent();
366 code_ += "}\n";
367 Outdent();
368 code_ += "}\n";
369 }
370
Austin Schuh272c6132020-11-14 16:37:52 -0800371 void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
372 const std::string &nameprefix,
373 const std::string &object_name,
374 const std::string &obj_api_named = "",
375 bool is_obj_api = false) {
376 auto &code = *code_ptr;
377 for (auto it = struct_def.fields.vec.begin();
378 it != struct_def.fields.vec.end(); ++it) {
379 auto &field = **it;
380 if (field.deprecated) continue;
381 const auto &field_type = field.value.type;
382 if (IsStruct(field.value.type)) {
383 GenerateStructArgs(
384 *field_type.struct_def, code_ptr, (nameprefix + field.name),
385 (object_name + "." + field.name), obj_api_named, is_obj_api);
386 } else {
387 auto name = Name(field);
388 auto type = GenType(field.value.type);
389 if (!is_obj_api) {
390 code += nameprefix + name + ": " + type;
391 if (!IsEnum(field.value.type)) {
392 code += " = ";
393 auto is_bool = IsBool(field.value.type.base_type);
394 auto constant =
395 is_bool ? ("0" == field.value.constant ? "false" : "true")
396 : field.value.constant;
397 code += constant;
398 }
399 code += ", ";
400 continue;
401 }
402 code +=
403 nameprefix + name + ": " + obj_api_named + object_name + "." + name;
404 code += ", ";
405 }
406 }
407 }
408
James Kuszmaul8e62b022022-03-22 09:33:25 -0700409 // MARK: - Table Generator
Austin Schuh272c6132020-11-14 16:37:52 -0800410
411 // Generates the reader for swift
412 void GenTable(const StructDef &struct_def) {
413 auto is_private_access = struct_def.attributes.Lookup("private");
414 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
Austin Schuh272c6132020-11-14 16:37:52 -0800415 GenObjectHeader(struct_def);
416 GenTableAccessors(struct_def);
417 GenTableReader(struct_def);
418 GenTableWriter(struct_def);
419 if (parser_.opts.generate_object_based_api)
420 GenerateObjectAPITableExtension(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700421 code_ += "";
422 GenerateVerifier(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800423 Outdent();
424 code_ += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700425 if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800426 }
427
428 // Generates the reader for swift
429 void GenTableAccessors(const StructDef &struct_def) {
430 // Generate field id constants.
431 if (struct_def.fields.vec.size() > 0) {
432 code_ += "private enum {{TABLEOFFSET}}: VOffset {";
433 Indent();
434 for (auto it = struct_def.fields.vec.begin();
435 it != struct_def.fields.vec.end(); ++it) {
436 const auto &field = **it;
437 if (field.deprecated) { continue; }
438 code_.SetValue("OFFSET_NAME", Name(field));
439 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
440 code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
441 }
442 code_ += "var v: Int32 { Int32(self.rawValue) }";
443 code_ += "var p: VOffset { self.rawValue }";
444 Outdent();
445 code_ += "}";
446 code_ += "";
447 }
448 }
449
James Kuszmaul8e62b022022-03-22 09:33:25 -0700450 void GenObjectHeader(const StructDef &struct_def) {
451 GenComment(struct_def.doc_comment);
Austin Schuh272c6132020-11-14 16:37:52 -0800452
James Kuszmaul8e62b022022-03-22 09:33:25 -0700453 code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
454 code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
455 code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
456 code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : "");
457 code_ +=
458 "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\";
459 if (!struct_def.fixed) code_ += ", Verifiable\\";
460 if (!struct_def.fixed && parser_.opts.generate_object_based_api)
461 code_ += ", ObjectAPIPacker\\";
462 code_ += " {\n";
463 Indent();
464 code_ += ValidateFunc();
465 code_ +=
466 "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
467 code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
468 if (!struct_def.fixed) {
469 if (parser_.file_identifier_.length()) {
470 code_.SetValue("FILENAME", parser_.file_identifier_);
471 code_ +=
472 "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
473 "FlatBufferBuilder, end: "
474 "Offset, prefix: Bool = false) { fbb.finish(offset: end, "
475 "fileId: "
476 "\"{{FILENAME}}\", addPrefix: prefix) }";
477 }
478 code_ +=
479 "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
480 "ByteBuffer) -> "
481 "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
482 "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
483 "Int32(bb.reader))) }\n";
484 code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
Austin Schuh272c6132020-11-14 16:37:52 -0800485 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700486 code_ +=
487 "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
488 "{{OBJECTTYPE}}(bb: "
489 "bb, position: o) }";
490 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -0800491 }
492
493 void GenTableWriter(const StructDef &struct_def) {
494 flatbuffers::FieldDef *key_field = nullptr;
495 std::vector<std::string> require_fields;
496 std::vector<std::string> create_func_body;
497 std::vector<std::string> create_func_header;
498 auto should_generate_create = struct_def.fields.vec.size() != 0;
499
500 code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
501 code_ +=
502 "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout "
503 "FlatBufferBuilder) -> "
504 "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
505
506 for (auto it = struct_def.fields.vec.begin();
507 it != struct_def.fields.vec.end(); ++it) {
508 auto &field = **it;
509 if (field.deprecated) continue;
510 if (field.key) key_field = &field;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700511 if (field.IsRequired())
Austin Schuh272c6132020-11-14 16:37:52 -0800512 require_fields.push_back(NumToString(field.value.offset));
513
James Kuszmaul8e62b022022-03-22 09:33:25 -0700514 GenTableWriterFields(field, &create_func_body, &create_func_header);
Austin Schuh272c6132020-11-14 16:37:52 -0800515 }
516 code_ +=
517 "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
518 "FlatBufferBuilder, "
519 "start: "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700520 "UOffset) -> Offset { let end = Offset(offset: "
Austin Schuh272c6132020-11-14 16:37:52 -0800521 "fbb.endTable(at: start))\\";
522 if (require_fields.capacity() != 0) {
523 std::string fields = "";
524 for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
525 fields += *it + ", ";
526 code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
527 code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
528 }
529 code_ += "; return end }";
530
531 if (should_generate_create) {
532 code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
533 Indent();
534 code_ += "_ fbb: inout FlatBufferBuilder,";
535 for (auto it = create_func_header.begin(); it < create_func_header.end();
536 ++it) {
537 code_ += *it + "\\";
538 if (it < create_func_header.end() - 1) code_ += ",";
539 }
540 code_ += "";
541 Outdent();
James Kuszmaul8e62b022022-03-22 09:33:25 -0700542 code_ += ") -> Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -0800543 Indent();
544 code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
545 for (auto it = create_func_body.begin(); it < create_func_body.end();
546 ++it) {
547 code_ += *it;
548 }
549 code_ +=
550 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)";
551 Outdent();
552 code_ += "}";
553 }
554
555 std::string spacing = "";
556
557 if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
558 code_.SetValue("VALUENAME", NameWrappedInNameSpace(struct_def));
559 code_.SetValue("SHORT_VALUENAME", Name(struct_def));
560 code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
561
562 code_ +=
563 "{{ACCESS_TYPE}} static func "
James Kuszmaul8e62b022022-03-22 09:33:25 -0700564 "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset], "
565 "_ fbb: inout FlatBufferBuilder) -> Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -0800566 Indent();
567 code_ += spacing + "var off = offsets";
568 code_ +=
569 spacing +
570 "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
571 "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
572 "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
573 code_ += spacing + "return fbb.createVector(ofOffsets: off)";
574 Outdent();
575 code_ += "}";
576 GenLookup(*key_field);
577 }
578 }
579
580 void GenTableWriterFields(const FieldDef &field,
581 std::vector<std::string> *create_body,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700582 std::vector<std::string> *create_header) {
Austin Schuh272c6132020-11-14 16:37:52 -0800583 std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { ";
584 auto &create_func_body = *create_body;
585 auto &create_func_header = *create_header;
586 auto name = Name(field);
587 auto type = GenType(field.value.type);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700588 auto opt_scalar =
589 field.IsOptional() && IsScalar(field.value.type.base_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800590 auto nullable_type = opt_scalar ? type + "?" : type;
591 code_.SetValue("VALUENAME", name);
592 code_.SetValue("VALUETYPE", nullable_type);
593 code_.SetValue("OFFSET", name);
594 code_.SetValue("CONSTANT", field.value.constant);
595 std::string check_if_vector =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700596 (IsVector(field.value.type) || IsArray(field.value.type)) ? "VectorOf("
597 : "(";
Austin Schuh272c6132020-11-14 16:37:52 -0800598 auto body = "add" + check_if_vector + name + ": ";
599 code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
600
601 create_func_body.push_back("{{STRUCTNAME}}." + body + name + ", &fbb)");
602
603 if (IsScalar(field.value.type.base_type) &&
604 !IsBool(field.value.type.base_type)) {
605 std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
606 std::string optional_enum =
607 IsEnum(field.value.type) ? ("?" + is_enum) : "";
608 code_ +=
609 "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{VALUENAME}}\\";
610
James Kuszmaul8e62b022022-03-22 09:33:25 -0700611 code_ += field.IsOptional() ? (optional_enum + "\\")
612 : (is_enum + ", def: {{CONSTANT}}\\");
Austin Schuh272c6132020-11-14 16:37:52 -0800613
614 code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
615
616 auto default_value =
617 IsEnum(field.value.type)
James Kuszmaul8e62b022022-03-22 09:33:25 -0700618 ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field))
Austin Schuh272c6132020-11-14 16:37:52 -0800619 : field.value.constant;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700620 create_func_header.push_back(
621 "" + name + ": " + nullable_type + " = " +
622 (field.IsOptional() ? "nil" : default_value));
Austin Schuh272c6132020-11-14 16:37:52 -0800623 return;
624 }
625
626 if (IsBool(field.value.type.base_type)) {
627 std::string default_value =
628 "0" == field.value.constant ? "false" : "true";
629
630 code_.SetValue("CONSTANT", default_value);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700631 code_.SetValue("VALUETYPE", field.IsOptional() ? "Bool?" : "Bool");
Austin Schuh272c6132020-11-14 16:37:52 -0800632 code_ += "{{VALUETYPE}}" + builder_string +
633 "fbb.add(element: {{VALUENAME}},\\";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700634 code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},";
Austin Schuh272c6132020-11-14 16:37:52 -0800635 code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700636 create_func_header.push_back(
637 name + ": " + nullable_type + " = " +
638 (field.IsOptional() ? "nil" : default_value));
Austin Schuh272c6132020-11-14 16:37:52 -0800639 return;
640 }
641
642 if (IsStruct(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700643 auto create_struct =
644 "guard let {{VALUENAME}} = {{VALUENAME}} else { return };"
645 " fbb.create(struct: {{VALUENAME}}, position: "
646 "{{TABLEOFFSET}}.{{OFFSET}}.p) }";
647 code_ += type + "?" + builder_string + create_struct;
648 /// Optional hard coded since structs are always optional
649 create_func_header.push_back(name + ": " + type + "? = nil");
Austin Schuh272c6132020-11-14 16:37:52 -0800650 return;
651 }
652
Austin Schuh272c6132020-11-14 16:37:52 -0800653 auto camel_case_name =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700654 ConvertCase(name, Case::kLowerCamel) +
655 (IsVector(field.value.type) || IsArray(field.value.type)
656 ? "VectorOffset"
657 : "Offset");
Austin Schuh272c6132020-11-14 16:37:52 -0800658 create_func_header.push_back(camel_case_name + " " + name + ": " +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700659 "Offset = Offset()");
Austin Schuh272c6132020-11-14 16:37:52 -0800660 auto reader_type =
661 IsStruct(field.value.type) && field.value.type.struct_def->fixed
662 ? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
663 : "offset: {{VALUENAME}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700664 code_ += "Offset" + builder_string + "fbb.add(" + reader_type;
Austin Schuh272c6132020-11-14 16:37:52 -0800665
666 auto vectortype = field.value.type.VectorType();
667
668 if ((vectortype.base_type == BASE_TYPE_STRUCT &&
669 field.value.type.struct_def->fixed) &&
James Kuszmaul8e62b022022-03-22 09:33:25 -0700670 (IsVector(field.value.type) || IsArray(field.value.type))) {
Austin Schuh272c6132020-11-14 16:37:52 -0800671 auto field_name = NameWrappedInNameSpace(*vectortype.struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700672 code_ += "public static func startVectorOf" +
673 ConvertCase(name, Case::kUpperCamel) +
Austin Schuh272c6132020-11-14 16:37:52 -0800674 "(_ size: Int, in builder: inout "
675 "FlatBufferBuilder) {";
676 Indent();
James Kuszmaul8e62b022022-03-22 09:33:25 -0700677 code_ += "builder.startVector(size * MemoryLayout<" + field_name +
678 ">.size, elementSize: MemoryLayout<" + field_name +
679 ">.alignment)";
Austin Schuh272c6132020-11-14 16:37:52 -0800680 Outdent();
681 code_ += "}";
682 }
683 }
684
James Kuszmaul8e62b022022-03-22 09:33:25 -0700685 void GenTableReader(const StructDef &struct_def) {
686 for (auto it = struct_def.fields.vec.begin();
687 it != struct_def.fields.vec.end(); ++it) {
688 auto &field = **it;
689 if (field.deprecated) continue;
690 GenTableReaderFields(field);
691 }
692 }
693
Austin Schuh272c6132020-11-14 16:37:52 -0800694 void GenTableReaderFields(const FieldDef &field) {
695 auto offset = NumToString(field.value.offset);
696 auto name = Name(field);
697 auto type = GenType(field.value.type);
698 code_.SetValue("VALUENAME", name);
699 code_.SetValue("VALUETYPE", type);
700 code_.SetValue("OFFSET", name);
701 code_.SetValue("CONSTANT", field.value.constant);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700702 bool opt_scalar =
703 field.IsOptional() && IsScalar(field.value.type.base_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800704 std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}";
705 std::string optional = opt_scalar ? "?" : "";
706 auto const_string = "return o == 0 ? " + def_Val + " : ";
707 GenComment(field.doc_comment);
708 if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
709 !IsBool(field.value.type.base_type)) {
710 code_ += GenReaderMainBody(optional) + GenOffset() + const_string +
711 GenReader("VALUETYPE", "o") + " }";
712 if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
713 return;
714 }
715
716 if (IsBool(field.value.type.base_type)) {
717 std::string default_value =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700718 field.IsOptional() ? "nil"
719 : ("0" == field.value.constant ? "false" : "true");
Austin Schuh272c6132020-11-14 16:37:52 -0800720 code_.SetValue("CONSTANT", default_value);
721 code_.SetValue("VALUETYPE", "Bool");
722 code_ += GenReaderMainBody(optional) + "\\";
723 code_.SetValue("VALUETYPE", "Byte");
724 code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " +
725 GenReader("VALUETYPE", "o") + " }";
726 if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
727 return;
728 }
729
730 if (IsEnum(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700731 auto default_value =
732 field.IsOptional() ? "nil" : GenEnumDefaultValue(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800733 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
734 code_ += GenReaderMainBody(optional) + "\\";
735 code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
736 GenEnumConstructor("o") + "?? " + default_value + " }";
737 if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
738 code_ += GenMutate("o", GenOffset(), true);
739 return;
740 }
741
James Kuszmaul8e62b022022-03-22 09:33:25 -0700742 std::string is_required = field.IsRequired() ? "!" : "?";
743 auto required_reader = field.IsRequired() ? "return " : const_string;
Austin Schuh272c6132020-11-14 16:37:52 -0800744
745 if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
746 code_.SetValue("VALUETYPE", GenType(field.value.type));
747 code_.SetValue("CONSTANT", "nil");
748 code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700749 "{{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, at: o) }";
750 code_.SetValue("VALUENAME",
751 "mutable" + ConvertCase(name, Case::kUpperCamel));
752 code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
753 code_.SetValue("CONSTANT", "nil");
754 code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
Austin Schuh272c6132020-11-14 16:37:52 -0800755 GenConstructor("o + {{ACCESS}}.postion");
756 return;
757 }
758 switch (field.value.type.base_type) {
759 case BASE_TYPE_STRUCT:
760 code_.SetValue("VALUETYPE", GenType(field.value.type));
761 code_.SetValue("CONSTANT", "nil");
762 code_ += GenReaderMainBody(is_required) + GenOffset() +
763 required_reader +
764 GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
765 break;
766
James Kuszmaul8e62b022022-03-22 09:33:25 -0700767 case BASE_TYPE_STRING: {
768 auto default_string = "\"" + field.value.constant + "\"";
Austin Schuh272c6132020-11-14 16:37:52 -0800769 code_.SetValue("VALUETYPE", GenType(field.value.type));
James Kuszmaul8e62b022022-03-22 09:33:25 -0700770 code_.SetValue("CONSTANT", field.IsDefault() ? default_string : "nil");
Austin Schuh272c6132020-11-14 16:37:52 -0800771 code_ += GenReaderMainBody(is_required) + GenOffset() +
772 required_reader + "{{ACCESS}}.string(at: o) }";
773 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}SegmentArray: [UInt8]" +
774 is_required +
775 " { return "
776 "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
777 break;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700778 }
Austin Schuh272c6132020-11-14 16:37:52 -0800779 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
James Kuszmaul8e62b022022-03-22 09:33:25 -0700780 case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break;
Austin Schuh272c6132020-11-14 16:37:52 -0800781 case BASE_TYPE_UNION:
782 code_.SetValue("CONSTANT", "nil");
783 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -0700784 "{{ACCESS_TYPE}} func {{VALUENAME}}<T: "
785 "FlatbuffersInitializable>(type: "
Austin Schuh272c6132020-11-14 16:37:52 -0800786 "T.Type) -> T" +
787 is_required + " { " + GenOffset() + required_reader +
788 "{{ACCESS}}.union(o) }";
789 break;
790 default: FLATBUFFERS_ASSERT(0);
791 }
792 }
793
James Kuszmaul8e62b022022-03-22 09:33:25 -0700794 void GenTableReaderVectorFields(const FieldDef &field) {
795 std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
Austin Schuh272c6132020-11-14 16:37:52 -0800796 auto vectortype = field.value.type.VectorType();
797 code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
798 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}Count: Int32 { " + GenOffset() +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700799 "return o == 0 ? 0 : {{ACCESS}}.vector(count: o) }";
800 code_.SetValue("CONSTANT",
801 IsScalar(vectortype.base_type) == true ? "0" : "nil");
Austin Schuh272c6132020-11-14 16:37:52 -0800802 auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
803 nullable = IsEnum(vectortype) == true ? "?" : nullable;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700804
Austin Schuh272c6132020-11-14 16:37:52 -0800805 if (vectortype.base_type != BASE_TYPE_UNION) {
806 code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
807 } else {
808 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -0700809 "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatbuffersInitializable>(at "
810 "index: "
Austin Schuh272c6132020-11-14 16:37:52 -0800811 "Int32, type: T.Type) -> T? { " +
812 GenOffset() + "\\";
813 }
814
815 if (IsBool(vectortype.base_type)) {
816 code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700817 code_.SetValue("VALUETYPE", "Bool");
Austin Schuh272c6132020-11-14 16:37:52 -0800818 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700819
820 if (!IsEnum(vectortype)) code_ += const_string + "\\";
Austin Schuh272c6132020-11-14 16:37:52 -0800821
822 if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
823 !IsBool(field.value.type.base_type)) {
824 code_ +=
825 "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
826 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
827 code_ +=
828 "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}] { return "
829 "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }";
830 if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
831 return;
832 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700833
Austin Schuh272c6132020-11-14 16:37:52 -0800834 if (vectortype.base_type == BASE_TYPE_STRUCT &&
835 field.value.type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700836 code_ +=
837 "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
838 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
839 code_.SetValue("VALUENAME",
840 "mutable" + ConvertCase(Name(field), Case::kUpperCamel));
841 code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable());
842 code_ += GenArrayMainBody(nullable) + GenOffset() + const_string +
843 GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
844
Austin Schuh272c6132020-11-14 16:37:52 -0800845 return;
846 }
847
848 if (IsString(vectortype)) {
849 code_ +=
850 "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
851 "index * {{SIZE}}) }";
852 return;
853 }
854
855 if (IsEnum(vectortype)) {
856 code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
857 code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
858 " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
859 "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
860 "index * {{SIZE}})) }";
861 return;
862 }
863 if (vectortype.base_type == BASE_TYPE_UNION) {
864 code_ +=
865 "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
866 "index * {{SIZE}}) }";
867 return;
868 }
869
870 if (vectortype.base_type == BASE_TYPE_STRUCT &&
871 !field.value.type.struct_def->fixed) {
872 code_ += GenConstructor(
873 "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
874 "{{SIZE}})");
875 auto &sd = *field.value.type.struct_def;
876 auto &fields = sd.fields.vec;
877 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
878 auto &key_field = **kit;
879 if (key_field.key) {
880 GenByKeyFunctions(key_field);
881 break;
882 }
883 }
884 }
885 }
886
James Kuszmaul8e62b022022-03-22 09:33:25 -0700887 void GenerateCodingKeys(const StructDef &struct_def) {
888 code_ += "enum CodingKeys: String, CodingKey {";
889 Indent();
890 for (auto it = struct_def.fields.vec.begin();
891 it != struct_def.fields.vec.end(); ++it) {
892 auto &field = **it;
893 if (field.deprecated) continue;
894 auto name = Name(field);
895
896 code_.SetValue("RAWVALUENAME", field.name);
897 code_.SetValue("VALUENAME", name);
898 code_ += "case {{VALUENAME}} = \"{{RAWVALUENAME}}\"";
899 }
900 Outdent();
901 code_ += "}";
902 }
903
904 void GenerateEncoderUnionBody(const FieldDef &field) {
905 EnumDef &union_def = *field.value.type.enum_def;
906 auto is_vector = field.value.type.base_type == BASE_TYPE_VECTOR ||
907 field.value.type.base_type == BASE_TYPE_ARRAY;
908 if (field.value.type.base_type == BASE_TYPE_UTYPE ||
909 (is_vector &&
910 field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
911 return;
912 if (is_vector) {
913 code_ +=
914 "var enumsEncoder = container.nestedUnkeyedContainer(forKey: "
915 ".{{VALUENAME}}Type)";
916 code_ +=
917 "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
918 ".{{VALUENAME}})";
919 code_ += "for index in 0..<{{VALUENAME}}Count {";
920 Indent();
921 code_ +=
922 "guard let type = {{VALUENAME}}Type(at: index) else { continue }";
923 code_ += "try enumsEncoder.encode(type)";
924 code_ += "switch type {";
925 for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
926 ++it) {
927 const auto &ev = **it;
928
929 auto name = Name(ev);
930 auto type = GenType(ev.union_type);
931 code_.SetValue("KEY", name);
932 code_.SetValue("VALUETYPE", type);
933 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
934 code_ += "case .{{KEY}}:";
935 Indent();
936 code_ += "let _v = {{VALUENAME}}(at: index, type: {{VALUETYPE}}.self)";
937 code_ += "try contentEncoder.encode(_v)";
938 Outdent();
939 }
940 code_ += "default: break;";
941 code_ += "}";
942 Outdent();
943 code_ += "}";
944 return;
945 }
946
947 code_ += "switch {{VALUENAME}}Type {";
948 for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
949 ++it) {
950 const auto &ev = **it;
951
952 auto name = Name(ev);
953 auto type = GenType(ev.union_type);
954 code_.SetValue("KEY", name);
955 code_.SetValue("VALUETYPE", type);
956 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
957 code_ += "case .{{KEY}}:";
958 Indent();
959 code_ += "let _v = {{VALUENAME}}(type: {{VALUETYPE}}.self)";
960 code_ += "try container.encodeIfPresent(_v, forKey: .{{VALUENAME}})";
961 Outdent();
962 }
963 code_ += "default: break;";
964 code_ += "}";
965 }
966
967 void GenerateEncoderBody(const StructDef &struct_def) {
968 code_ += "var container = encoder.container(keyedBy: CodingKeys.self)";
969 for (auto it = struct_def.fields.vec.begin();
970 it != struct_def.fields.vec.end(); ++it) {
971 auto &field = **it;
972 if (field.deprecated) continue;
973 auto name = Name(field);
974 auto type = field.value.type;
975
976 auto is_non_union_vector =
977 (field.value.type.base_type == BASE_TYPE_ARRAY ||
978 field.value.type.base_type == BASE_TYPE_VECTOR) &&
979 field.value.type.VectorType().base_type != BASE_TYPE_UTYPE;
980
981 code_.SetValue("RAWVALUENAME", field.name);
982 code_.SetValue("VALUENAME", name);
983 code_.SetValue("CONSTANT", field.value.constant);
984 bool should_indent = true;
985 if (is_non_union_vector) {
986 code_ += "if {{VALUENAME}}Count > 0 {";
987 } else if (IsEnum(type) && !field.IsOptional()) {
988 code_.SetValue("CONSTANT", GenEnumDefaultValue(field));
989 code_ += "if {{VALUENAME}} != {{CONSTANT}} {";
990 } else if (IsScalar(type.base_type) && !IsEnum(type) &&
991 !IsBool(type.base_type) && !field.IsOptional()) {
992 code_ += "if {{VALUENAME}} != {{CONSTANT}} {";
993 } else if (IsBool(type.base_type) && !field.IsOptional()) {
994 std::string default_value =
995 "0" == field.value.constant ? "false" : "true";
996 code_.SetValue("CONSTANT", default_value);
997 code_ += "if {{VALUENAME}} != {{CONSTANT}} {";
998 } else {
999 should_indent = false;
1000 }
1001 if (should_indent) Indent();
1002
1003 if (IsUnion(type) && !IsEnum(type)) {
1004 GenerateEncoderUnionBody(field);
1005 } else if (is_non_union_vector &&
1006 (!IsScalar(type.VectorType().base_type) ||
1007 IsEnum(type.VectorType()))) {
1008 code_ +=
1009 "var contentEncoder = container.nestedUnkeyedContainer(forKey: "
1010 ".{{VALUENAME}})";
1011 code_ += "for index in 0..<{{VALUENAME}}Count {";
1012 Indent();
1013 code_ += "guard let type = {{VALUENAME}}(at: index) else { continue }";
1014 code_ += "try contentEncoder.encode(type)";
1015 Outdent();
1016 code_ += "}";
1017 } else {
1018 code_ +=
1019 "try container.encodeIfPresent({{VALUENAME}}, forKey: "
1020 ".{{VALUENAME}})";
1021 }
1022 if (should_indent) Outdent();
1023
1024 if (is_non_union_vector ||
1025 (IsScalar(type.base_type) && !field.IsOptional())) {
1026 code_ += "}";
1027 }
1028 }
1029 }
1030
1031 void GenerateJSONEncodingAPIs(const StructDef &struct_def) {
1032 code_ += "extension {{STRUCTNAME}}: Encodable {";
1033 Indent();
1034 code_ += "";
1035 if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def);
1036
1037 code_ += "public func encode(to encoder: Encoder) throws {";
1038 Indent();
1039 if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def);
1040 Outdent();
1041 code_ += "}";
1042 Outdent();
1043 code_ += "}";
1044 code_ += "";
1045 }
1046
1047 void GenerateVerifier(const StructDef &struct_def) {
1048 code_ +=
1049 "public static func verify<T>(_ verifier: inout Verifier, at position: "
1050 "Int, of type: T.Type) throws where T: Verifiable {";
1051 Indent();
1052 code_ += "var _v = try verifier.visitTable(at: position)";
1053 for (auto it = struct_def.fields.vec.begin();
1054 it != struct_def.fields.vec.end(); ++it) {
1055 auto &field = **it;
1056 if (field.deprecated) continue;
1057 auto offset = NumToString(field.value.offset);
1058 auto name = Name(field);
1059
1060 code_.SetValue("VALUENAME", name);
1061 code_.SetValue("VALUETYPE", GenerateVerifierType(field));
1062 code_.SetValue("OFFSET", name);
1063 code_.SetValue("ISREQUIRED", field.IsRequired() ? "true" : "false");
1064
1065 if (IsUnion(field.value.type)) {
1066 GenerateUnionTypeVerifier(field);
1067 continue;
1068 }
1069
1070 code_ +=
1071 "try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: "
1072 "\"{{VALUENAME}}\", required: {{ISREQUIRED}}, type: "
1073 "{{VALUETYPE}}.self)";
1074 }
1075 code_ += "_v.finish()";
1076 Outdent();
1077 code_ += "}";
1078 }
1079
1080 void GenerateUnionTypeVerifier(const FieldDef &field) {
1081 auto is_vector = IsVector(field.value.type) || IsArray(field.value.type);
1082 if (field.value.type.base_type == BASE_TYPE_UTYPE ||
1083 (is_vector &&
1084 field.value.type.VectorType().base_type == BASE_TYPE_UTYPE))
1085 return;
1086 EnumDef &union_def = *field.value.type.enum_def;
1087 code_.SetValue("VALUETYPE", NameWrappedInNameSpace(union_def));
1088 code_.SetValue("FUNCTION_NAME", is_vector ? "visitUnionVector" : "visit");
1089 code_ +=
1090 "try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, "
1091 "unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: "
1092 "\"{{VALUENAME}}Type\", fieldName: \"{{VALUENAME}}\", required: "
1093 "{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in";
1094 Indent();
1095 code_ += "switch key {";
1096 for (auto it = union_def.Vals().begin(); it != union_def.Vals().end();
1097 ++it) {
1098 const auto &ev = **it;
1099
1100 auto name = Name(ev);
1101 auto type = GenType(ev.union_type);
1102 code_.SetValue("KEY", name);
1103 code_.SetValue("VALUETYPE", type);
1104 code_ += "case .{{KEY}}:";
1105 Indent();
1106 if (ev.union_type.base_type == BASE_TYPE_NONE) {
1107 code_ += "break // NOTE - SWIFT doesnt support none";
1108 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1109 code_ +=
1110 "try ForwardOffset<String>.verify(&verifier, at: pos, of: "
1111 "String.self)";
1112 } else {
1113 code_.SetValue("MAINTYPE", ev.union_type.struct_def->fixed
1114 ? type
1115 : "ForwardOffset<" + type + ">");
1116 code_ +=
1117 "try {{MAINTYPE}}.verify(&verifier, at: pos, of: "
1118 "{{VALUETYPE}}.self)";
1119 }
1120 Outdent();
1121 }
1122 code_ += "}";
1123 Outdent();
1124 code_ += "})";
1125 }
1126
1127 std::string GenerateVerifierType(const FieldDef &field) {
1128 auto type = field.value.type;
1129 auto is_vector = IsVector(type) || IsArray(type);
1130
1131 if (is_vector) {
1132 auto vector_type = field.value.type.VectorType();
1133 return "ForwardOffset<Vector<" +
1134 GenerateNestedVerifierTypes(vector_type) + ", " +
1135 GenType(vector_type) + ">>";
1136 }
1137
1138 return GenerateNestedVerifierTypes(field.value.type);
1139 }
1140
1141 std::string GenerateNestedVerifierTypes(const Type &type) {
1142 auto string_type = GenType(type);
1143
1144 if (IsScalar(type.base_type)) { return string_type; }
1145
1146 if (IsString(type)) { return "ForwardOffset<" + string_type + ">"; }
1147
1148 if (type.struct_def && type.struct_def->fixed) { return string_type; }
1149
1150 return "ForwardOffset<" + string_type + ">";
1151 }
1152
Austin Schuh272c6132020-11-14 16:37:52 -08001153 void GenByKeyFunctions(const FieldDef &key_field) {
1154 code_.SetValue("TYPE", GenType(key_field.value.type));
1155 code_ +=
1156 "{{ACCESS_TYPE}} func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? "
1157 "{ \\";
1158 code_ += GenOffset() +
1159 "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
1160 "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
1161 }
1162
Austin Schuh272c6132020-11-14 16:37:52 -08001163 void GenEnum(const EnumDef &enum_def) {
1164 if (enum_def.generated) return;
1165 auto is_private_access = enum_def.attributes.Lookup("private");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001166 code_.SetValue("ENUM_TYPE",
1167 enum_def.is_union ? "UnionEnum" : "Enum, Verifiable");
Austin Schuh272c6132020-11-14 16:37:52 -08001168 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
1169 code_.SetValue("ENUM_NAME", NameWrappedInNameSpace(enum_def));
1170 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1171 GenComment(enum_def.doc_comment);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001172 code_ +=
1173 "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {";
Austin Schuh272c6132020-11-14 16:37:52 -08001174 Indent();
1175 code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001176 if (enum_def.is_union) {
1177 code_ += "";
1178 code_ += "{{ACCESS_TYPE}} init?(value: T) {";
1179 Indent();
1180 code_ += "self.init(rawValue: value)";
1181 Outdent();
1182 code_ += "}\n";
1183 }
Austin Schuh272c6132020-11-14 16:37:52 -08001184 code_ +=
1185 "{{ACCESS_TYPE}} static var byteSize: Int { return "
1186 "MemoryLayout<{{BASE_TYPE}}>.size "
1187 "}";
1188 code_ +=
1189 "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
1190 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1191 const auto &ev = **it;
1192 auto name = Name(ev);
1193 code_.SetValue("KEY", name);
1194 code_.SetValue("VALUE", enum_def.ToString(ev));
1195 GenComment(ev.doc_comment);
1196 code_ += "case {{KEY}} = {{VALUE}}";
1197 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001198 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001199 AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max");
1200 AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min");
1201 Outdent();
1202 code_ += "}\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001203 if (parser_.opts.gen_json_coders) EnumEncoder(enum_def);
1204 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08001205 if (parser_.opts.generate_object_based_api && enum_def.is_union) {
1206 code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
1207 Indent();
1208 code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001209 code_ += "{{ACCESS_TYPE}} var value: NativeObject?";
1210 code_ +=
1211 "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {";
Austin Schuh272c6132020-11-14 16:37:52 -08001212 Indent();
1213 code_ += "self.type = type";
1214 code_ += "self.value = v";
1215 Outdent();
1216 code_ += "}";
1217 code_ +=
1218 "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
James Kuszmaul8e62b022022-03-22 09:33:25 -07001219 "Offset {";
Austin Schuh272c6132020-11-14 16:37:52 -08001220 Indent();
1221 BuildUnionEnumSwitchCaseWritter(enum_def);
1222 Outdent();
1223 code_ += "}";
1224 Outdent();
1225 code_ += "}";
1226 }
1227 }
1228
James Kuszmaul8e62b022022-03-22 09:33:25 -07001229 void EnumEncoder(const EnumDef &enum_def) {
1230 code_ += "extension {{ENUM_NAME}}: Encodable {";
1231 Indent();
1232 code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
1233 Indent();
1234 code_ += "var container = encoder.singleValueContainer()";
1235 code_ += "switch self {";
1236 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1237 const auto &ev = **it;
1238 auto name = Name(ev);
1239 code_.SetValue("KEY", name);
1240 code_.SetValue("RAWKEY", ev.name);
1241 code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")";
1242 }
1243 code_ += "}";
1244 Outdent();
1245 code_ += "}";
1246 Outdent();
1247 code_ += "}";
1248 }
1249
1250 // MARK: - Object API
1251
1252 void GenerateObjectAPIExtensionHeader(std::string name) {
1253 code_ += "\n";
1254 code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + name + " {";
1255 Indent();
1256 code_ += "return " + name + "(&self)";
1257 Outdent();
1258 code_ += "}";
1259 code_ +=
1260 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1261 "obj: "
1262 "inout " +
1263 name + "?) -> Offset {";
1264 Indent();
1265 code_ += "guard var obj = obj else { return Offset() }";
1266 code_ += "return pack(&builder, obj: &obj)";
1267 Outdent();
1268 code_ += "}";
1269 code_ += "";
1270 code_ +=
1271 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
1272 "obj: "
1273 "inout " +
1274 name + ") -> Offset {";
1275 Indent();
1276 }
1277
1278 void GenerateObjectAPIStructConstructor(const StructDef &struct_def) {
1279 code_ +=
1280 "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {";
1281 Indent();
1282 for (auto it = struct_def.fields.vec.begin();
1283 it != struct_def.fields.vec.end(); ++it) {
1284 auto &field = **it;
1285 if (field.deprecated) continue;
1286
1287 auto name = Name(field);
1288 auto type = GenType(field.value.type);
1289 code_.SetValue("VALUENAME", name);
1290 if (IsStruct(field.value.type)) {
1291 code_ += "var _v{{VALUENAME}} = _t.{{VALUENAME}}";
1292 code_ += "_{{VALUENAME}} = _v{{VALUENAME}}.unpack()";
1293 continue;
1294 }
1295 std::string is_enum = IsEnum(field.value.type) ? ".value" : "";
1296 code_ += "_{{VALUENAME}} = _t.{{VALUENAME}}" + is_enum;
1297 }
1298 Outdent();
1299 code_ += "}\n";
1300 }
1301
Austin Schuh272c6132020-11-14 16:37:52 -08001302 void GenObjectAPI(const StructDef &struct_def) {
1303 code_ += "{{ACCESS_TYPE}} class " + ObjectAPIName("{{STRUCTNAME}}") +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001304 ": NativeObject {\n";
Austin Schuh272c6132020-11-14 16:37:52 -08001305 std::vector<std::string> buffer_constructor;
1306 std::vector<std::string> base_constructor;
1307 Indent();
1308 for (auto it = struct_def.fields.vec.begin();
1309 it != struct_def.fields.vec.end(); ++it) {
1310 auto &field = **it;
1311 if (field.deprecated) continue;
1312 BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
1313 base_constructor);
1314 }
1315 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001316 BuildObjectConstructor(buffer_constructor,
1317 "_ _t: inout " + NameWrappedInNameSpace(struct_def));
1318 BuildObjectConstructor(base_constructor);
Austin Schuh272c6132020-11-14 16:37:52 -08001319 if (!struct_def.fixed)
1320 code_ +=
1321 "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
1322 "serialize(type: "
1323 "{{STRUCTNAME}}.self) }\n";
1324 Outdent();
1325 code_ += "}";
1326 }
1327
1328 void GenerateObjectAPITableExtension(const StructDef &struct_def) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001329 GenerateObjectAPIExtensionHeader(ObjectAPIName("{{STRUCTNAME}}"));
Austin Schuh272c6132020-11-14 16:37:52 -08001330 std::vector<std::string> unpack_body;
1331 std::string builder = ", &builder)";
1332 for (auto it = struct_def.fields.vec.begin();
1333 it != struct_def.fields.vec.end(); ++it) {
1334 auto &field = **it;
1335 if (field.deprecated) continue;
1336 auto name = Name(field);
1337 auto type = GenType(field.value.type);
1338 std::string check_if_vector =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001339 (IsVector(field.value.type) || IsArray(field.value.type))
Austin Schuh272c6132020-11-14 16:37:52 -08001340 ? "VectorOf("
1341 : "(";
1342 std::string body = "add" + check_if_vector + name + ": ";
1343 switch (field.value.type.base_type) {
1344 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1345 case BASE_TYPE_VECTOR: {
1346 GenerateVectorObjectAPITableExtension(field, name, type);
1347 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
1348 builder);
1349 break;
1350 }
1351 case BASE_TYPE_UNION: {
1352 code_ += "let __" + name + " = obj." + name +
1353 "?.pack(builder: &builder) ?? Offset()";
1354 unpack_body.push_back("if let o = obj." + name + "?.type {");
1355 unpack_body.push_back(" {{STRUCTNAME}}.add(" + name + "Type: o" +
1356 builder);
1357 unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + name +
1358 builder);
1359 unpack_body.push_back("}\n");
1360 break;
1361 }
1362 case BASE_TYPE_STRUCT: {
1363 if (field.value.type.struct_def &&
1364 field.value.type.struct_def->fixed) {
1365 // This is a Struct (IsStruct), not a table. We create
James Kuszmaul8e62b022022-03-22 09:33:25 -07001366 // a native swift object in this case.
Austin Schuh272c6132020-11-14 16:37:52 -08001367 std::string code;
1368 GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
1369 "$0", true);
1370 code = code.substr(0, code.size() - 2);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001371 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name +
1372 builder);
Austin Schuh272c6132020-11-14 16:37:52 -08001373 } else {
1374 code_ += "let __" + name + " = " + type +
1375 ".pack(&builder, obj: &obj." + name + ")";
1376 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
1377 builder);
1378 }
1379 break;
1380 }
1381 case BASE_TYPE_STRING: {
1382 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
1383 builder);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001384 if (field.IsRequired()) {
Austin Schuh272c6132020-11-14 16:37:52 -08001385 code_ +=
1386 "let __" + name + " = builder.create(string: obj." + name + ")";
1387 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001388 BuildingOptionalObjects(name, "builder.create(string: s)");
Austin Schuh272c6132020-11-14 16:37:52 -08001389 }
1390 break;
1391 }
1392 case BASE_TYPE_UTYPE: break;
1393 default:
1394 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name +
1395 builder);
1396 }
1397 }
1398 code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
1399 for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
1400 code_ += *it;
1401 code_ +=
1402 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
1403 "__root)";
1404 Outdent();
1405 code_ += "}";
1406 }
1407
1408 void GenerateVectorObjectAPITableExtension(const FieldDef &field,
1409 const std::string &name,
1410 const std::string &type) {
1411 auto vectortype = field.value.type.VectorType();
1412 switch (vectortype.base_type) {
1413 case BASE_TYPE_UNION: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001414 code_ += "var __" + name + "__: [Offset] = []";
Austin Schuh272c6132020-11-14 16:37:52 -08001415 code_ += "for i in obj." + name + " {";
1416 Indent();
1417 code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
1418 code_ += "__" + name + "__.append(off)";
1419 Outdent();
1420 code_ += "}";
1421 code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
1422 name + "__)";
1423 code_ += "let __" + name + "Type = builder.createVector(obj." + name +
1424 ".compactMap { $0?.type })";
1425 break;
1426 }
1427 case BASE_TYPE_UTYPE: break;
1428 case BASE_TYPE_STRUCT: {
1429 if (field.value.type.struct_def &&
1430 !field.value.type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001431 code_ += "var __" + name + "__: [Offset] = []";
Austin Schuh272c6132020-11-14 16:37:52 -08001432 code_ += "for var i in obj." + name + " {";
1433 Indent();
1434 code_ +=
1435 "__" + name + "__.append(" + type + ".pack(&builder, obj: &i))";
1436 Outdent();
1437 code_ += "}";
1438 code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
1439 name + "__)";
1440 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001441 code_ += "{{STRUCTNAME}}.startVectorOf" +
1442 ConvertCase(name, Case::kUpperCamel) + "(obj." + name +
1443 ".count, in: &builder)";
Austin Schuh272c6132020-11-14 16:37:52 -08001444 std::string code;
1445 GenerateStructArgs(*field.value.type.struct_def, &code, "", "", "_o",
1446 true);
1447 code = code.substr(0, code.size() - 2);
1448 code_ += "for i in obj." + name + " {";
1449 Indent();
1450 code_ += "guard let _o = i else { continue }";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001451 code_ += "builder.create(struct: _o)";
Austin Schuh272c6132020-11-14 16:37:52 -08001452 Outdent();
1453 code_ += "}";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001454 code_ += "let __" + name + " = builder.endVector(len: obj." + name +
Austin Schuh272c6132020-11-14 16:37:52 -08001455 ".count)";
1456 }
1457 break;
1458 }
1459 case BASE_TYPE_STRING: {
1460 code_ += "let __" + name + " = builder.createVector(ofStrings: obj." +
1461 name + ".compactMap({ $0 }) )";
1462 break;
1463 }
1464 default: {
1465 code_ += "let __" + name + " = builder.createVector(obj." + name + ")";
1466 break;
1467 }
1468 }
1469 }
1470
1471 void BuildingOptionalObjects(const std::string &name,
Austin Schuh272c6132020-11-14 16:37:52 -08001472 const std::string &body_front) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001473 code_ += "let __" + name + ": Offset";
Austin Schuh272c6132020-11-14 16:37:52 -08001474 code_ += "if let s = obj." + name + " {";
1475 Indent();
1476 code_ += "__" + name + " = " + body_front;
1477 Outdent();
1478 code_ += "} else {";
1479 Indent();
James Kuszmaul8e62b022022-03-22 09:33:25 -07001480 code_ += "__" + name + " = Offset()";
Austin Schuh272c6132020-11-14 16:37:52 -08001481 Outdent();
1482 code_ += "}";
1483 code_ += "";
1484 }
1485
James Kuszmaul8e62b022022-03-22 09:33:25 -07001486 void BuildObjectConstructor(const std::vector<std::string> &body,
1487 const std::string &header = "") {
Austin Schuh272c6132020-11-14 16:37:52 -08001488 code_.SetValue("HEADER", header);
1489 code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
1490 Indent();
1491 for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
1492 Outdent();
1493 code_ += "}\n";
1494 }
1495
1496 void BuildObjectAPIConstructorBody(
1497 const FieldDef &field, bool is_fixed,
1498 std::vector<std::string> &buffer_constructor,
1499 std::vector<std::string> &base_constructor) {
1500 auto name = Name(field);
1501 auto type = GenType(field.value.type);
1502 code_.SetValue("VALUENAME", name);
1503 code_.SetValue("VALUETYPE", type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001504 std::string is_required = field.IsRequired() ? "" : "?";
Austin Schuh272c6132020-11-14 16:37:52 -08001505
1506 switch (field.value.type.base_type) {
1507 case BASE_TYPE_STRUCT: {
1508 type = GenType(field.value.type, true);
1509 code_.SetValue("VALUETYPE", type);
Austin Schuh272c6132020-11-14 16:37:52 -08001510 auto optional =
1511 (field.value.type.struct_def && field.value.type.struct_def->fixed);
1512 std::string question_mark =
James Kuszmaul8e62b022022-03-22 09:33:25 -07001513 (field.IsRequired() || (optional && is_fixed) ? "" : "?");
Austin Schuh272c6132020-11-14 16:37:52 -08001514
1515 code_ +=
1516 "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark;
Austin Schuh272c6132020-11-14 16:37:52 -08001517 base_constructor.push_back("" + name + " = " + type + "()");
James Kuszmaul8e62b022022-03-22 09:33:25 -07001518
1519 if (field.value.type.struct_def->fixed) {
1520 buffer_constructor.push_back("" + name + " = _t." + name);
1521 } else {
1522 buffer_constructor.push_back("var __" + name + " = _t." + name);
1523 buffer_constructor.push_back(
1524 "" + name + " = __" + name +
1525 (field.IsRequired() ? "!" : question_mark) + ".unpack()");
1526 }
Austin Schuh272c6132020-11-14 16:37:52 -08001527 break;
1528 }
1529 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1530 case BASE_TYPE_VECTOR: {
1531 BuildObjectAPIConstructorBodyVectors(field, name, buffer_constructor,
1532 base_constructor, " ");
1533 break;
1534 }
1535 case BASE_TYPE_STRING: {
1536 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required;
1537 buffer_constructor.push_back(name + " = _t." + name);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001538
1539 if (field.IsRequired()) {
1540 std::string default_value =
1541 field.IsDefault() ? field.value.constant : "";
1542 base_constructor.push_back(name + " = \"" + default_value + "\"");
1543 break;
1544 }
1545 if (field.IsDefault() && !field.IsRequired()) {
1546 std::string value = field.IsDefault() ? field.value.constant : "nil";
1547 base_constructor.push_back(name + " = \"" + value + "\"");
1548 }
Austin Schuh272c6132020-11-14 16:37:52 -08001549 break;
1550 }
1551 case BASE_TYPE_UTYPE: break;
1552 case BASE_TYPE_UNION: {
1553 BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
1554 buffer_constructor);
1555 break;
1556 }
1557 default: {
1558 buffer_constructor.push_back(name + " = _t." + name);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001559 std::string nullable = field.IsOptional() ? "?" : "";
Austin Schuh272c6132020-11-14 16:37:52 -08001560 if (IsScalar(field.value.type.base_type) &&
1561 !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
1562 code_ +=
1563 "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + nullable;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001564 if (!field.IsOptional())
Austin Schuh272c6132020-11-14 16:37:52 -08001565 base_constructor.push_back(name + " = " + field.value.constant);
1566 break;
1567 }
1568
1569 if (IsEnum(field.value.type)) {
1570 auto default_value = IsEnum(field.value.type)
1571 ? GenEnumDefaultValue(field)
1572 : field.value.constant;
1573 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}";
1574 base_constructor.push_back(name + " = " + default_value);
1575 break;
1576 }
1577
1578 if (IsBool(field.value.type.base_type)) {
1579 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable;
1580 std::string default_value =
1581 "0" == field.value.constant ? "false" : "true";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001582 if (!field.IsOptional())
Austin Schuh272c6132020-11-14 16:37:52 -08001583 base_constructor.push_back(name + " = " + default_value);
1584 }
1585 }
1586 }
1587 }
1588
1589 void BuildObjectAPIConstructorBodyVectors(
1590 const FieldDef &field, const std::string &name,
1591 std::vector<std::string> &buffer_constructor,
1592 std::vector<std::string> &base_constructor,
1593 const std::string &indentation) {
1594 auto vectortype = field.value.type.VectorType();
1595
1596 if (vectortype.base_type != BASE_TYPE_UTYPE) {
1597 buffer_constructor.push_back(name + " = []");
1598 buffer_constructor.push_back("for index in 0..<_t." + name + "Count {");
1599 base_constructor.push_back(name + " = []");
1600 }
1601
1602 switch (vectortype.base_type) {
1603 case BASE_TYPE_STRUCT: {
1604 code_.SetValue("VALUETYPE", GenType(vectortype, true));
1605 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001606 if (!vectortype.struct_def->fixed) {
1607 buffer_constructor.push_back(indentation + "var __v_ = _t." + name +
1608 "(at: index)");
1609 buffer_constructor.push_back(indentation + name +
1610 ".append(__v_?.unpack())");
1611 } else {
1612 buffer_constructor.push_back(indentation + name + ".append(_t." +
1613 name + "(at: index))");
1614 }
Austin Schuh272c6132020-11-14 16:37:52 -08001615 break;
1616 }
1617 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1618 case BASE_TYPE_VECTOR: {
1619 break;
1620 }
1621 case BASE_TYPE_UNION: {
1622 BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
1623 buffer_constructor, indentation, true);
1624 break;
1625 }
1626 case BASE_TYPE_UTYPE: break;
1627 default: {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001628 code_.SetValue(
1629 "VALUETYPE",
1630 (IsString(vectortype) ? "String?" : GenType(vectortype)));
Austin Schuh272c6132020-11-14 16:37:52 -08001631 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]";
1632
1633 if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
1634 auto default_value = IsEnum(field.value.type)
1635 ? GenEnumDefaultValue(field)
1636 : field.value.constant;
1637 buffer_constructor.push_back(indentation + name + ".append(_t." +
1638 name + "(at: index)!)");
1639 break;
1640 }
1641 buffer_constructor.push_back(indentation + name + ".append(_t." + name +
1642 "(at: index))");
1643 break;
1644 }
1645 }
1646 if (vectortype.base_type != BASE_TYPE_UTYPE)
1647 buffer_constructor.push_back("}");
1648 }
1649
1650 void BuildUnionEnumSwitchCaseWritter(const EnumDef &ev) {
1651 auto field_name = Name(ev);
1652 code_.SetValue("VALUETYPE", field_name);
1653 code_ += "switch type {";
1654 for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
1655 auto field = **it;
1656 auto ev_name = Name(field);
1657 auto type = GenType(field.union_type);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001658 auto is_struct = IsStruct(field.union_type) ? type + Mutable() : type;
1659 if (field.union_type.base_type == BASE_TYPE_NONE) { continue; }
Austin Schuh272c6132020-11-14 16:37:52 -08001660 code_ += "case ." + ev_name + ":";
1661 Indent();
1662 code_ += "var __obj = value as? " + GenType(field.union_type, true);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001663 code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)";
Austin Schuh272c6132020-11-14 16:37:52 -08001664 Outdent();
1665 }
1666 code_ += "default: return Offset()";
1667 code_ += "}";
1668 }
1669
1670 void BuildUnionEnumSwitchCase(const EnumDef &ev, const std::string &name,
1671 std::vector<std::string> &buffer_constructor,
1672 const std::string &indentation = "",
1673 const bool is_vector = false) {
1674 auto field_name = NameWrappedInNameSpace(ev);
1675 code_.SetValue("VALUETYPE", field_name);
1676 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: \\";
1677 code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
1678
1679 auto vector_reader = is_vector ? "(at: index" : "";
1680 buffer_constructor.push_back(indentation + "switch _t." + name + "Type" +
1681 vector_reader + (is_vector ? ")" : "") + " {");
1682
1683 for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
1684 auto field = **it;
1685 auto ev_name = Name(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001686 if (field.union_type.base_type == BASE_TYPE_NONE) { continue; }
1687 auto type = IsStruct(field.union_type)
1688 ? GenType(field.union_type) + Mutable()
1689 : GenType(field.union_type);
Austin Schuh272c6132020-11-14 16:37:52 -08001690 buffer_constructor.push_back(indentation + "case ." + ev_name + ":");
1691 buffer_constructor.push_back(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001692 indentation + " var _v = _t." + name + (is_vector ? "" : "(") +
1693 vector_reader + (is_vector ? ", " : "") + "type: " + type + ".self)");
Austin Schuh272c6132020-11-14 16:37:52 -08001694 auto constructor =
1695 field_name + "Union(_v?.unpack(), type: ." + ev_name + ")";
1696 buffer_constructor.push_back(
James Kuszmaul8e62b022022-03-22 09:33:25 -07001697 indentation + " " + name +
Austin Schuh272c6132020-11-14 16:37:52 -08001698 (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
1699 }
1700 buffer_constructor.push_back(indentation + "default: break");
1701 buffer_constructor.push_back(indentation + "}");
1702 }
1703
1704 void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
1705 auto current_value = str;
1706 code_.SetValue(type, current_value);
1707 code_ += "{{ACCESS_TYPE}} static var " + type +
1708 ": {{ENUM_NAME}} { return .{{" + type + "}} }";
1709 }
1710
1711 void GenLookup(const FieldDef &key_field) {
1712 code_.SetValue("OFFSET", NumToString(key_field.value.offset));
1713 std::string offset_reader =
1714 "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
1715 "fbb: fbb)";
1716
1717 code_.SetValue("TYPE", GenType(key_field.value.type));
1718 code_ +=
1719 "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
1720 "fbb: "
1721 "ByteBuffer) -> {{VALUENAME}}? {";
1722 Indent();
1723 if (IsString(key_field.value.type))
1724 code_ += "let key = key.utf8.map { $0 }";
1725 code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
1726 code_ += "var start: Int32 = 0";
1727 code_ += "while span != 0 {";
1728 Indent();
1729 code_ += "var middle = span / 2";
1730 code_ +=
1731 "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
1732 if (IsString(key_field.value.type)) {
1733 code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
1734 } else {
1735 code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
1736 offset_reader + "))";
1737 }
1738
1739 code_ += "if comp > 0 {";
1740 Indent();
1741 code_ += "span = middle";
1742 Outdent();
1743 code_ += "} else if comp < 0 {";
1744 Indent();
1745 code_ += "middle += 1";
1746 code_ += "start += middle";
1747 code_ += "span -= middle";
1748 Outdent();
1749 code_ += "} else {";
1750 Indent();
1751 code_ += "return {{VALUENAME}}(fbb, o: tableOffset)";
1752 Outdent();
1753 code_ += "}";
1754 Outdent();
1755 code_ += "}";
1756 code_ += "return nil";
1757 Outdent();
1758 code_ += "}";
1759 }
1760
James Kuszmaul8e62b022022-03-22 09:33:25 -07001761 inline void GenPadding(const FieldDef &field, int *id) {
1762 if (field.padding) {
1763 for (int i = 0; i < 4; i++) {
1764 if (static_cast<int>(field.padding) & (1 << i)) {
1765 auto bits = (1 << i) * 8;
1766 code_ += "private let padding" + NumToString((*id)++) + "__: UInt" +
1767 NumToString(bits) + " = 0";
1768 }
1769 }
1770 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
1771 }
1772 }
1773
Austin Schuh272c6132020-11-14 16:37:52 -08001774 void GenComment(const std::vector<std::string> &dc) {
1775 if (dc.begin() == dc.end()) {
1776 // Don't output empty comment blocks with 0 lines of comment content.
1777 return;
1778 }
1779 for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
1780 }
1781
1782 std::string GenOffset() {
1783 return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
1784 }
1785
1786 std::string GenReaderMainBody(const std::string &optional = "") {
1787 return "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + optional +
1788 " { ";
1789 }
1790
1791 std::string GenReader(const std::string &type,
1792 const std::string &at = "{{OFFSET}}") {
1793 return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
1794 }
1795
1796 std::string GenConstructor(const std::string &offset) {
1797 return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
1798 }
1799
1800 std::string GenMutate(const std::string &offset,
1801 const std::string &get_offset, bool isRaw = false) {
1802 return "@discardableResult {{ACCESS_TYPE}} func mutate({{VALUENAME}}: "
1803 "{{VALUETYPE}}) -> Bool {" +
1804 get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
1805 (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
1806 }
1807
1808 std::string GenMutateArray() {
1809 return "{{ACCESS_TYPE}} func mutate({{VALUENAME}}: {{VALUETYPE}}, at "
1810 "index: "
1811 "Int32) -> Bool { " +
1812 GenOffset() +
1813 "return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
1814 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
1815 }
1816
1817 std::string GenEnumDefaultValue(const FieldDef &field) {
1818 auto &value = field.value;
1819 FLATBUFFERS_ASSERT(value.type.enum_def);
1820 auto &enum_def = *value.type.enum_def;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001821 // Vector of enum defaults are always "[]" which never works.
1822 const std::string constant = IsVector(value.type) ? "0" : value.constant;
1823 auto enum_val = enum_def.FindByValue(constant);
Austin Schuh272c6132020-11-14 16:37:52 -08001824 std::string name;
1825 if (enum_val) {
1826 name = Name(*enum_val);
1827 } else {
1828 const auto &ev = **enum_def.Vals().begin();
1829 name = Name(ev);
1830 }
Austin Schuh272c6132020-11-14 16:37:52 -08001831 return "." + name;
1832 }
1833
1834 std::string GenEnumConstructor(const std::string &at) {
1835 return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
1836 }
1837
1838 std::string ValidateFunc() {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001839 return "static func validateVersion() { FlatBuffersVersion_2_0_0() }";
Austin Schuh272c6132020-11-14 16:37:52 -08001840 }
1841
1842 std::string GenType(const Type &type,
1843 const bool should_consider_suffix = false) const {
1844 return IsScalar(type.base_type)
1845 ? GenTypeBasic(type)
1846 : (IsArray(type) ? GenType(type.VectorType())
1847 : GenTypePointer(type, should_consider_suffix));
1848 }
1849
1850 std::string GenTypePointer(const Type &type,
1851 const bool should_consider_suffix) const {
1852 switch (type.base_type) {
1853 case BASE_TYPE_STRING: return "String";
1854 case BASE_TYPE_VECTOR: return GenType(type.VectorType());
1855 case BASE_TYPE_STRUCT: {
1856 auto &struct_ = *type.struct_def;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001857 if (should_consider_suffix && !struct_.fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -08001858 return WrapInNameSpace(struct_.defined_namespace,
1859 ObjectAPIName(Name(struct_)));
1860 }
1861 return WrapInNameSpace(struct_.defined_namespace, Name(struct_));
1862 }
1863 case BASE_TYPE_UNION:
James Kuszmaul8e62b022022-03-22 09:33:25 -07001864 default: return "FlatbuffersInitializable";
Austin Schuh272c6132020-11-14 16:37:52 -08001865 }
1866 }
1867
1868 std::string GenTypeBasic(const Type &type) const {
1869 return GenTypeBasic(type, true);
1870 }
1871
1872 std::string ObjectAPIName(const std::string &name) const {
1873 return parser_.opts.object_prefix + name + parser_.opts.object_suffix;
1874 }
1875
1876 void Indent() { code_.IncrementIdentLevel(); }
1877
1878 void Outdent() { code_.DecrementIdentLevel(); }
1879
1880 std::string NameWrappedInNameSpace(const EnumDef &enum_def) const {
1881 return WrapInNameSpace(enum_def.defined_namespace, Name(enum_def));
1882 }
1883
1884 std::string NameWrappedInNameSpace(const StructDef &struct_def) const {
1885 return WrapInNameSpace(struct_def.defined_namespace, Name(struct_def));
1886 }
1887
1888 std::string GenTypeBasic(const Type &type, bool can_override) const {
1889 // clang-format off
1890 static const char * const swift_type[] = {
1891 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1892 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
1893 #STYPE,
1894 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1895 #undef FLATBUFFERS_TD
1896 };
1897 // clang-format on
1898 if (can_override) {
1899 if (type.enum_def) return NameWrappedInNameSpace(*type.enum_def);
1900 if (type.base_type == BASE_TYPE_BOOL) return "Bool";
1901 }
1902 return swift_type[static_cast<int>(type.base_type)];
1903 }
1904
1905 std::string EscapeKeyword(const std::string &name) const {
1906 return keywords_.find(name) == keywords_.end() ? name : name + "_";
1907 }
1908
James Kuszmaul8e62b022022-03-22 09:33:25 -07001909 std::string Mutable() const { return "_Mutable"; }
1910
Austin Schuh272c6132020-11-14 16:37:52 -08001911 std::string Name(const EnumVal &ev) const {
1912 auto name = ev.name;
1913 if (isupper(name.front())) {
1914 std::transform(name.begin(), name.end(), name.begin(), CharToLower);
1915 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001916 return EscapeKeyword(ConvertCase(name, Case::kLowerCamel));
Austin Schuh272c6132020-11-14 16:37:52 -08001917 }
1918
1919 std::string Name(const Definition &def) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001920 return EscapeKeyword(ConvertCase(def.name, Case::kLowerCamel));
Austin Schuh272c6132020-11-14 16:37:52 -08001921 }
1922};
1923} // namespace swift
1924bool GenerateSwift(const Parser &parser, const std::string &path,
1925 const std::string &file_name) {
1926 swift::SwiftGenerator generator(parser, path, file_name);
1927 return generator.generate();
1928}
1929} // namespace flatbuffers