blob: c377e9f6ff61decc41a5ae2f0aa9bcfa2ae1510f [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;
50 code_.SetPadding(" ");
51 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",
130 nullptr,
131 };
132 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
133 }
134
135 bool generate() {
136 code_.Clear();
137 code_.SetValue("ACCESS", "_accessor");
138 code_.SetValue("TABLEOFFSET", "VTOFFSET");
139 code_ += "// " + std::string(FlatBuffersGeneratedWarning());
140 code_ += "// swiftlint:disable all\n";
141 code_ += "import FlatBuffers\n";
142 // Generate code for all the enum declarations.
143
144 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
145 ++it) {
146 const auto &enum_def = **it;
147 if (!enum_def.generated) { GenEnum(enum_def); }
148 }
149
150 for (auto it = parser_.structs_.vec.begin();
151 it != parser_.structs_.vec.end(); ++it) {
152 const auto &struct_def = **it;
153 if (struct_def.fixed && !struct_def.generated) {
154 GenStructReader(struct_def);
155 if (parser_.opts.generate_object_based_api) {
156 GenObjectAPI(struct_def);
157 }
158 }
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 GenStructWriter(struct_def);
166 }
167 }
168
169 for (auto it = parser_.structs_.vec.begin();
170 it != parser_.structs_.vec.end(); ++it) {
171 const auto &struct_def = **it;
172 if (!struct_def.fixed && !struct_def.generated) {
173 GenTable(struct_def);
174 if (parser_.opts.generate_object_based_api) {
175 GenObjectAPI(struct_def);
176 }
177 }
178 }
179
180 const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
181 const auto final_code = code_.ToString();
182 return SaveFile(filename.c_str(), final_code, false);
183 }
184
185 void mark(const std::string &str) {
186 code_.SetValue("MARKVALUE", str);
187 code_ += "\n// MARK: - {{MARKVALUE}}\n";
188 }
189
190 // Generates the create function for swift
191 void GenStructWriter(const StructDef &struct_def) {
192 auto is_private_access = struct_def.attributes.Lookup("private");
193 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
194 code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
195 code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
196 code_ += "extension {{STRUCTNAME}} {";
197 Indent();
198 code_ += "@discardableResult";
199 code_ +=
200 "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout "
201 "FlatBufferBuilder, \\";
202 std::string func_header = "";
203 GenerateStructArgs(struct_def, &func_header, "", "");
204 code_ += func_header.substr(0, func_header.size() - 2) + "\\";
205 code_ += ") -> Offset<UOffset> {";
206 Indent();
207 code_ +=
208 "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: "
209 "{{STRUCTNAME}}.alignment)";
210 GenerateStructBody(struct_def, "");
211 code_ += "return builder.endStruct()";
212 Outdent();
213 code_ += "}\n";
214 Outdent();
215 code_ += "}\n";
216 }
217
218 void GenerateStructBody(const StructDef &struct_def,
219 const std::string &nameprefix, int offset = 0) {
220 for (auto it = struct_def.fields.vec.begin();
221 it != struct_def.fields.vec.end(); ++it) {
222 auto &field = **it;
223 if (field.deprecated) continue;
224 auto name = nameprefix + Name(field);
225 const auto &field_type = field.value.type;
226 auto type = GenTypeBasic(field_type, false);
227 if (IsStruct(field.value.type)) {
228 GenerateStructBody(*field_type.struct_def, (nameprefix + field.name),
229 static_cast<int>(field.value.offset));
230 } else {
231 auto off = NumToString(offset + field.value.offset);
232 code_ += "builder.reverseAdd(v: " + name +
233 (field_type.enum_def ? ".rawValue" : "") +
234 ", postion: " + off + ")";
235 }
236 }
237 }
238
239 void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
240 const std::string &nameprefix,
241 const std::string &object_name,
242 const std::string &obj_api_named = "",
243 bool is_obj_api = false) {
244 auto &code = *code_ptr;
245 for (auto it = struct_def.fields.vec.begin();
246 it != struct_def.fields.vec.end(); ++it) {
247 auto &field = **it;
248 if (field.deprecated) continue;
249 const auto &field_type = field.value.type;
250 if (IsStruct(field.value.type)) {
251 GenerateStructArgs(
252 *field_type.struct_def, code_ptr, (nameprefix + field.name),
253 (object_name + "." + field.name), obj_api_named, is_obj_api);
254 } else {
255 auto name = Name(field);
256 auto type = GenType(field.value.type);
257 if (!is_obj_api) {
258 code += nameprefix + name + ": " + type;
259 if (!IsEnum(field.value.type)) {
260 code += " = ";
261 auto is_bool = IsBool(field.value.type.base_type);
262 auto constant =
263 is_bool ? ("0" == field.value.constant ? "false" : "true")
264 : field.value.constant;
265 code += constant;
266 }
267 code += ", ";
268 continue;
269 }
270 code +=
271 nameprefix + name + ": " + obj_api_named + object_name + "." + name;
272 code += ", ";
273 }
274 }
275 }
276
277 void GenObjectHeader(const StructDef &struct_def) {
278 GenComment(struct_def.doc_comment);
279 code_.SetValue("SHORT_STRUCTNAME", Name(struct_def));
280 code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def));
281 code_.SetValue("PROTOCOL",
282 struct_def.fixed ? "Readable" : "FlatBufferObject");
283 code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
284 code_ += "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: {{PROTOCOL}}\\";
285 if (!struct_def.fixed && parser_.opts.generate_object_based_api)
286 code_ += ", ObjectAPI\\";
287 code_ += " {\n";
288 Indent();
289 code_ += ValidateFunc();
290 code_ +=
291 "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
292 code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n";
293 if (struct_def.fixed) {
294 code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize));
295 code_.SetValue("MINALIGN", NumToString(struct_def.minalign));
296 code_ += "{{ACCESS_TYPE}} static var size = {{BYTESIZE}}";
297 code_ += "{{ACCESS_TYPE}} static var alignment = {{MINALIGN}}";
298 } else {
299 if (parser_.file_identifier_.length()) {
300 code_.SetValue("FILENAME", parser_.file_identifier_);
301 code_ +=
302 "{{ACCESS_TYPE}} static func finish(_ fbb: inout "
303 "FlatBufferBuilder, end: "
304 "Offset<UOffset>, prefix: Bool = false) { fbb.finish(offset: end, "
305 "fileId: "
306 "\"{{FILENAME}}\", addPrefix: prefix) }";
307 }
308 code_ +=
309 "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: "
310 "ByteBuffer) -> "
311 "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
312 "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
313 "Int32(bb.reader))) }\n";
314 code_ += "private init(_ t: Table) { {{ACCESS}} = t }";
315 }
316 code_ +=
317 "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
318 "{{OBJECTTYPE}}(bb: "
319 "bb, position: o) }";
320 code_ += "";
321 }
322
323 // Generates the reader for swift
324 void GenTable(const StructDef &struct_def) {
325 auto is_private_access = struct_def.attributes.Lookup("private");
326 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
327
328 GenObjectHeader(struct_def);
329 GenTableAccessors(struct_def);
330 GenTableReader(struct_def);
331 GenTableWriter(struct_def);
332 if (parser_.opts.generate_object_based_api)
333 GenerateObjectAPITableExtension(struct_def);
334 Outdent();
335 code_ += "}\n";
336 }
337
338 // Generates the reader for swift
339 void GenTableAccessors(const StructDef &struct_def) {
340 // Generate field id constants.
341 if (struct_def.fields.vec.size() > 0) {
342 code_ += "private enum {{TABLEOFFSET}}: VOffset {";
343 Indent();
344 for (auto it = struct_def.fields.vec.begin();
345 it != struct_def.fields.vec.end(); ++it) {
346 const auto &field = **it;
347 if (field.deprecated) { continue; }
348 code_.SetValue("OFFSET_NAME", Name(field));
349 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
350 code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
351 }
352 code_ += "var v: Int32 { Int32(self.rawValue) }";
353 code_ += "var p: VOffset { self.rawValue }";
354 Outdent();
355 code_ += "}";
356 code_ += "";
357 }
358 }
359
360 void GenerateObjectAPIExtensionHeader() {
361 code_ += "\n";
362 code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " +
363 ObjectAPIName("{{STRUCTNAME}}") + " {";
364 Indent();
365 code_ += "return " + ObjectAPIName("{{STRUCTNAME}}") + "(&self)";
366 Outdent();
367 code_ += "}";
368 code_ +=
369 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
370 "obj: "
371 "inout " +
372 ObjectAPIName("{{STRUCTNAME}}") + "?) -> Offset<UOffset> {";
373 Indent();
374 code_ += "guard var obj = obj else { return Offset<UOffset>() }";
375 code_ += "return pack(&builder, obj: &obj)";
376 Outdent();
377 code_ += "}";
378 code_ += "";
379 code_ +=
380 "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, "
381 "obj: "
382 "inout " +
383 ObjectAPIName("{{STRUCTNAME}}") + ") -> Offset<UOffset> {";
384 Indent();
385 }
386
387 void GenerateObjectAPIStructExtension(const StructDef &struct_def) {
388 GenerateObjectAPIExtensionHeader();
389 std::string code;
390 GenerateStructArgs(struct_def, &code, "", "", "obj", true);
391 code_ += "return create{{SHORT_STRUCTNAME}}(builder: &builder, \\";
392 code_ += code.substr(0, code.size() - 2) + "\\";
393 code_ += ")";
394 Outdent();
395 code_ += "}";
396 }
397
398 void GenTableReader(const StructDef &struct_def) {
399 for (auto it = struct_def.fields.vec.begin();
400 it != struct_def.fields.vec.end(); ++it) {
401 auto &field = **it;
402 if (field.deprecated) continue;
403 GenTableReaderFields(field);
404 }
405 }
406
407 void GenTableWriter(const StructDef &struct_def) {
408 flatbuffers::FieldDef *key_field = nullptr;
409 std::vector<std::string> require_fields;
410 std::vector<std::string> create_func_body;
411 std::vector<std::string> create_func_header;
412 auto should_generate_create = struct_def.fields.vec.size() != 0;
413
414 code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
415 code_ +=
416 "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout "
417 "FlatBufferBuilder) -> "
418 "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
419
420 for (auto it = struct_def.fields.vec.begin();
421 it != struct_def.fields.vec.end(); ++it) {
422 auto &field = **it;
423 if (field.deprecated) continue;
424 if (field.key) key_field = &field;
425 if (field.required)
426 require_fields.push_back(NumToString(field.value.offset));
427
428 GenTableWriterFields(field, &create_func_body, &create_func_header,
429 should_generate_create);
430 }
431 code_ +=
432 "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout "
433 "FlatBufferBuilder, "
434 "start: "
435 "UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(offset: "
436 "fbb.endTable(at: start))\\";
437 if (require_fields.capacity() != 0) {
438 std::string fields = "";
439 for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
440 fields += *it + ", ";
441 code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
442 code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
443 }
444 code_ += "; return end }";
445
446 if (should_generate_create) {
447 code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
448 Indent();
449 code_ += "_ fbb: inout FlatBufferBuilder,";
450 for (auto it = create_func_header.begin(); it < create_func_header.end();
451 ++it) {
452 code_ += *it + "\\";
453 if (it < create_func_header.end() - 1) code_ += ",";
454 }
455 code_ += "";
456 Outdent();
457 code_ += ") -> Offset<UOffset> {";
458 Indent();
459 code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)";
460 for (auto it = create_func_body.begin(); it < create_func_body.end();
461 ++it) {
462 code_ += *it;
463 }
464 code_ +=
465 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)";
466 Outdent();
467 code_ += "}";
468 }
469
470 std::string spacing = "";
471
472 if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
473 code_.SetValue("VALUENAME", NameWrappedInNameSpace(struct_def));
474 code_.SetValue("SHORT_VALUENAME", Name(struct_def));
475 code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
476
477 code_ +=
478 "{{ACCESS_TYPE}} static func "
479 "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset<UOffset>], "
480 "_ fbb: inout FlatBufferBuilder) -> Offset<UOffset> {";
481 Indent();
482 code_ += spacing + "var off = offsets";
483 code_ +=
484 spacing +
485 "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
486 "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
487 "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
488 code_ += spacing + "return fbb.createVector(ofOffsets: off)";
489 Outdent();
490 code_ += "}";
491 GenLookup(*key_field);
492 }
493 }
494
495 void GenTableWriterFields(const FieldDef &field,
496 std::vector<std::string> *create_body,
497 std::vector<std::string> *create_header,
498 bool &contains_structs) {
499 std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { ";
500 auto &create_func_body = *create_body;
501 auto &create_func_header = *create_header;
502 auto name = Name(field);
503 auto type = GenType(field.value.type);
504 bool opt_scalar = field.optional && IsScalar(field.value.type.base_type);
505 auto nullable_type = opt_scalar ? type + "?" : type;
506 code_.SetValue("VALUENAME", name);
507 code_.SetValue("VALUETYPE", nullable_type);
508 code_.SetValue("OFFSET", name);
509 code_.SetValue("CONSTANT", field.value.constant);
510 std::string check_if_vector =
511 (IsVector(field.value.type) ||
512 IsArray(field.value.type))
513 ? "VectorOf("
514 : "(";
515 auto body = "add" + check_if_vector + name + ": ";
516 code_ += "{{ACCESS_TYPE}} static func " + body + "\\";
517
518 create_func_body.push_back("{{STRUCTNAME}}." + body + name + ", &fbb)");
519
520 if (IsScalar(field.value.type.base_type) &&
521 !IsBool(field.value.type.base_type)) {
522 std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
523 std::string optional_enum =
524 IsEnum(field.value.type) ? ("?" + is_enum) : "";
525 code_ +=
526 "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{VALUENAME}}\\";
527
528 code_ += field.optional ? (optional_enum + "\\")
529 : (is_enum + ", def: {{CONSTANT}}\\");
530
531 code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
532
533 auto default_value =
534 IsEnum(field.value.type)
535 ? (field.optional ? "nil" : GenEnumDefaultValue(field))
536 : field.value.constant;
537 create_func_header.push_back("" + name + ": " + nullable_type + " = " +
538 (field.optional ? "nil" : default_value));
539 return;
540 }
541
542 if (IsBool(field.value.type.base_type)) {
543 std::string default_value =
544 "0" == field.value.constant ? "false" : "true";
545
546 code_.SetValue("CONSTANT", default_value);
547 code_.SetValue("VALUETYPE", field.optional ? "Bool?" : "Bool");
548 code_ += "{{VALUETYPE}}" + builder_string +
549 "fbb.add(element: {{VALUENAME}},\\";
550 code_ += field.optional ? "\\" : " def: {{CONSTANT}},";
551 code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
552 create_func_header.push_back(name + ": " + nullable_type + " = " +
553 (field.optional ? "nil" : default_value));
554 return;
555 }
556
557 if (IsStruct(field.value.type)) {
558 contains_structs = false;
559 auto struct_type = "Offset<UOffset>?";
560 auto camel_case_name = "structOf" + MakeCamel(name, true);
561 auto reader_type =
562 "fbb.add(structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
563 auto create_struct = "guard {{VALUENAME}} != nil else { return }; ";
564 code_ += struct_type + builder_string + create_struct + reader_type;
565 return;
566 }
567
568 auto offset_type = IsString(field.value.type)
569 ? "Offset<String>"
570 : "Offset<UOffset>";
571 auto camel_case_name =
572 (IsVector(field.value.type) ||
573 IsArray(field.value.type)
574 ? "vectorOf"
575 : "offsetOf") +
576 MakeCamel(name, true);
577 create_func_header.push_back(camel_case_name + " " + name + ": " +
578 offset_type + " = Offset()");
579 auto reader_type =
580 IsStruct(field.value.type) && field.value.type.struct_def->fixed
581 ? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
582 : "offset: {{VALUENAME}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
583 code_ += offset_type + builder_string + "fbb.add(" + reader_type;
584
585 auto vectortype = field.value.type.VectorType();
586
587 if ((vectortype.base_type == BASE_TYPE_STRUCT &&
588 field.value.type.struct_def->fixed) &&
589 (IsVector(field.value.type) ||
590 IsArray(field.value.type))) {
591 auto field_name = NameWrappedInNameSpace(*vectortype.struct_def);
592 code_ += "public static func startVectorOf" + MakeCamel(name, true) +
593 "(_ size: Int, in builder: inout "
594 "FlatBufferBuilder) {";
595 Indent();
596 code_ += "builder.startVectorOfStructs(count: size, size: " + field_name +
597 ".size, "
598 "alignment: " +
599 field_name + ".alignment)";
600 Outdent();
601 code_ += "}";
602 }
603 }
604
605 void GenTableReaderFields(const FieldDef &field) {
606 auto offset = NumToString(field.value.offset);
607 auto name = Name(field);
608 auto type = GenType(field.value.type);
609 code_.SetValue("VALUENAME", name);
610 code_.SetValue("VALUETYPE", type);
611 code_.SetValue("OFFSET", name);
612 code_.SetValue("CONSTANT", field.value.constant);
613 bool opt_scalar = field.optional && IsScalar(field.value.type.base_type);
614 std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}";
615 std::string optional = opt_scalar ? "?" : "";
616 auto const_string = "return o == 0 ? " + def_Val + " : ";
617 GenComment(field.doc_comment);
618 if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
619 !IsBool(field.value.type.base_type)) {
620 code_ += GenReaderMainBody(optional) + GenOffset() + const_string +
621 GenReader("VALUETYPE", "o") + " }";
622 if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
623 return;
624 }
625
626 if (IsBool(field.value.type.base_type)) {
627 std::string default_value =
628 "0" == field.value.constant ? "false" : "true";
629 code_.SetValue("CONSTANT", default_value);
630 code_.SetValue("VALUETYPE", "Bool");
631 code_ += GenReaderMainBody(optional) + "\\";
632 code_.SetValue("VALUETYPE", "Byte");
633 code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " +
634 GenReader("VALUETYPE", "o") + " }";
635 if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
636 return;
637 }
638
639 if (IsEnum(field.value.type)) {
640 auto default_value = field.optional ? "nil" : GenEnumDefaultValue(field);
641 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
642 code_ += GenReaderMainBody(optional) + "\\";
643 code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
644 GenEnumConstructor("o") + "?? " + default_value + " }";
645 if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
646 code_ += GenMutate("o", GenOffset(), true);
647 return;
648 }
649
650 std::string is_required = field.required ? "!" : "?";
651 auto required_reader = field.required ? "return " : const_string;
652
653 if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
654 code_.SetValue("VALUETYPE", GenType(field.value.type));
655 code_.SetValue("CONSTANT", "nil");
656 code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader +
657 GenConstructor("o + {{ACCESS}}.postion");
658 return;
659 }
660 switch (field.value.type.base_type) {
661 case BASE_TYPE_STRUCT:
662 code_.SetValue("VALUETYPE", GenType(field.value.type));
663 code_.SetValue("CONSTANT", "nil");
664 code_ += GenReaderMainBody(is_required) + GenOffset() +
665 required_reader +
666 GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
667 break;
668
669 case BASE_TYPE_STRING:
670 code_.SetValue("VALUETYPE", GenType(field.value.type));
671 code_.SetValue("CONSTANT", "nil");
672 code_ += GenReaderMainBody(is_required) + GenOffset() +
673 required_reader + "{{ACCESS}}.string(at: o) }";
674 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}SegmentArray: [UInt8]" +
675 is_required +
676 " { return "
677 "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
678 break;
679
680 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
681 case BASE_TYPE_VECTOR:
682 GenTableReaderVectorFields(field, const_string);
683 break;
684 case BASE_TYPE_UNION:
685 code_.SetValue("CONSTANT", "nil");
686 code_ +=
687 "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatBufferObject>(type: "
688 "T.Type) -> T" +
689 is_required + " { " + GenOffset() + required_reader +
690 "{{ACCESS}}.union(o) }";
691 break;
692 default: FLATBUFFERS_ASSERT(0);
693 }
694 }
695
696 void GenTableReaderVectorFields(const FieldDef &field,
697 const std::string &const_string) {
698 auto vectortype = field.value.type.VectorType();
699 code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
700 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}Count: Int32 { " + GenOffset() +
701 const_string + "{{ACCESS}}.vector(count: o) }";
702 code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) == true
703 ? field.value.constant
704 : "nil");
705 auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
706 nullable = IsEnum(vectortype) == true ? "?" : nullable;
707 if (vectortype.base_type != BASE_TYPE_UNION) {
708 code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
709 } else {
710 code_ +=
711 "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatBufferObject>(at index: "
712 "Int32, type: T.Type) -> T? { " +
713 GenOffset() + "\\";
714 }
715
716 if (IsBool(vectortype.base_type)) {
717 code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
718 code_.SetValue("VALUETYPE", "Byte");
719 }
720 if (!IsEnum(vectortype))
721 code_ +=
722 const_string + (IsBool(vectortype.base_type) ? "0 != " : "") + "\\";
723
724 if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
725 !IsBool(field.value.type.base_type)) {
726 code_ +=
727 "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
728 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
729 code_ +=
730 "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}] { return "
731 "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }";
732 if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
733 return;
734 }
735 if (vectortype.base_type == BASE_TYPE_STRUCT &&
736 field.value.type.struct_def->fixed) {
737 code_ += GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
738 return;
739 }
740
741 if (IsString(vectortype)) {
742 code_ +=
743 "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
744 "index * {{SIZE}}) }";
745 return;
746 }
747
748 if (IsEnum(vectortype)) {
749 code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
750 code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
751 " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
752 "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
753 "index * {{SIZE}})) }";
754 return;
755 }
756 if (vectortype.base_type == BASE_TYPE_UNION) {
757 code_ +=
758 "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
759 "index * {{SIZE}}) }";
760 return;
761 }
762
763 if (vectortype.base_type == BASE_TYPE_STRUCT &&
764 !field.value.type.struct_def->fixed) {
765 code_ += GenConstructor(
766 "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
767 "{{SIZE}})");
768 auto &sd = *field.value.type.struct_def;
769 auto &fields = sd.fields.vec;
770 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
771 auto &key_field = **kit;
772 if (key_field.key) {
773 GenByKeyFunctions(key_field);
774 break;
775 }
776 }
777 }
778 }
779
780 void GenByKeyFunctions(const FieldDef &key_field) {
781 code_.SetValue("TYPE", GenType(key_field.value.type));
782 code_ +=
783 "{{ACCESS_TYPE}} func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? "
784 "{ \\";
785 code_ += GenOffset() +
786 "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
787 "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
788 }
789
790 // Generates the reader for swift
791 void GenStructReader(const StructDef &struct_def) {
792 auto is_private_access = struct_def.attributes.Lookup("private");
793 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
794
795 GenObjectHeader(struct_def);
796 for (auto it = struct_def.fields.vec.begin();
797 it != struct_def.fields.vec.end(); ++it) {
798 auto &field = **it;
799 if (field.deprecated) continue;
800 auto offset = NumToString(field.value.offset);
801 auto name = Name(field);
802 auto type = GenType(field.value.type);
803 code_.SetValue("VALUENAME", name);
804 code_.SetValue("VALUETYPE", type);
805 code_.SetValue("OFFSET", offset);
806 GenComment(field.doc_comment);
807 if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
808 code_ +=
809 GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
810 if (parser_.opts.mutable_buffer) code_ += GenMutate("{{OFFSET}}", "");
811 } else if (IsEnum(field.value.type)) {
812 code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
813 code_ += GenReaderMainBody() + "return " +
814 GenEnumConstructor("{{OFFSET}}") + "?? " +
815 GenEnumDefaultValue(field) + " }";
816 } else if (IsStruct(field.value.type)) {
817 code_.SetValue("VALUETYPE", GenType(field.value.type));
818 code_ += GenReaderMainBody() + "return " +
819 GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
820 }
821 }
822 if (parser_.opts.generate_object_based_api)
823 GenerateObjectAPIStructExtension(struct_def);
824 Outdent();
825 code_ += "}\n";
826 }
827
828 void GenEnum(const EnumDef &enum_def) {
829 if (enum_def.generated) return;
830 auto is_private_access = enum_def.attributes.Lookup("private");
831 code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public");
832 code_.SetValue("ENUM_NAME", NameWrappedInNameSpace(enum_def));
833 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
834 GenComment(enum_def.doc_comment);
835 code_ += "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { ";
836 Indent();
837 code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}";
838 code_ +=
839 "{{ACCESS_TYPE}} static var byteSize: Int { return "
840 "MemoryLayout<{{BASE_TYPE}}>.size "
841 "}";
842 code_ +=
843 "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }";
844 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
845 const auto &ev = **it;
846 auto name = Name(ev);
847 code_.SetValue("KEY", name);
848 code_.SetValue("VALUE", enum_def.ToString(ev));
849 GenComment(ev.doc_comment);
850 code_ += "case {{KEY}} = {{VALUE}}";
851 }
852 code_ += "\n";
853 AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max");
854 AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min");
855 Outdent();
856 code_ += "}\n";
857 if (parser_.opts.generate_object_based_api && enum_def.is_union) {
858 code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {";
859 Indent();
860 code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}";
861 code_ += "{{ACCESS_TYPE}} var value: NativeTable?";
862 code_ += "{{ACCESS_TYPE}} init(_ v: NativeTable?, type: {{ENUM_NAME}}) {";
863 Indent();
864 code_ += "self.type = type";
865 code_ += "self.value = v";
866 Outdent();
867 code_ += "}";
868 code_ +=
869 "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> "
870 "Offset<UOffset> {";
871 Indent();
872 BuildUnionEnumSwitchCaseWritter(enum_def);
873 Outdent();
874 code_ += "}";
875 Outdent();
876 code_ += "}";
877 }
878 }
879
880 void GenObjectAPI(const StructDef &struct_def) {
881 code_ += "{{ACCESS_TYPE}} class " + ObjectAPIName("{{STRUCTNAME}}") +
882 ": NativeTable {\n";
883 std::vector<std::string> buffer_constructor;
884 std::vector<std::string> base_constructor;
885 Indent();
886 for (auto it = struct_def.fields.vec.begin();
887 it != struct_def.fields.vec.end(); ++it) {
888 auto &field = **it;
889 if (field.deprecated) continue;
890 BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor,
891 base_constructor);
892 }
893 code_ += "";
894 BuildObjectAPIConstructor(
895 buffer_constructor,
896 "_ _t: inout " + NameWrappedInNameSpace(struct_def));
897 BuildObjectAPIConstructor(base_constructor);
898 if (!struct_def.fixed)
899 code_ +=
900 "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return "
901 "serialize(type: "
902 "{{STRUCTNAME}}.self) }\n";
903 Outdent();
904 code_ += "}";
905 }
906
907 void GenerateObjectAPITableExtension(const StructDef &struct_def) {
908 GenerateObjectAPIExtensionHeader();
909 std::vector<std::string> unpack_body;
910 std::string builder = ", &builder)";
911 for (auto it = struct_def.fields.vec.begin();
912 it != struct_def.fields.vec.end(); ++it) {
913 auto &field = **it;
914 if (field.deprecated) continue;
915 auto name = Name(field);
916 auto type = GenType(field.value.type);
917 std::string check_if_vector =
918 (IsVector(field.value.type) ||
919 IsArray(field.value.type))
920 ? "VectorOf("
921 : "(";
922 std::string body = "add" + check_if_vector + name + ": ";
923 switch (field.value.type.base_type) {
924 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
925 case BASE_TYPE_VECTOR: {
926 GenerateVectorObjectAPITableExtension(field, name, type);
927 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
928 builder);
929 break;
930 }
931 case BASE_TYPE_UNION: {
932 code_ += "let __" + name + " = obj." + name +
933 "?.pack(builder: &builder) ?? Offset()";
934 unpack_body.push_back("if let o = obj." + name + "?.type {");
935 unpack_body.push_back(" {{STRUCTNAME}}.add(" + name + "Type: o" +
936 builder);
937 unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + name +
938 builder);
939 unpack_body.push_back("}\n");
940 break;
941 }
942 case BASE_TYPE_STRUCT: {
943 if (field.value.type.struct_def &&
944 field.value.type.struct_def->fixed) {
945 // This is a Struct (IsStruct), not a table. We create
946 // UnsafeMutableRawPointer in this case.
947 std::string code;
948 GenerateStructArgs(*field.value.type.struct_def, &code, "", "",
949 "$0", true);
950 code = code.substr(0, code.size() - 2);
951 unpack_body.push_back(
952 "{{STRUCTNAME}}." + body + "obj." + name + ".map { " +
953 NameWrappedInNameSpace(*field.value.type.struct_def) +
954 ".create" + Name(*field.value.type.struct_def) +
955 "(builder: &builder, " + code + ") }" + builder);
956 } else {
957 code_ += "let __" + name + " = " + type +
958 ".pack(&builder, obj: &obj." + name + ")";
959 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
960 builder);
961 }
962 break;
963 }
964 case BASE_TYPE_STRING: {
965 unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name +
966 builder);
967 if (field.required) {
968 code_ +=
969 "let __" + name + " = builder.create(string: obj." + name + ")";
970 } else {
971 BuildingOptionalObjects(name, "String",
972 "builder.create(string: s)");
973 }
974 break;
975 }
976 case BASE_TYPE_UTYPE: break;
977 default:
978 unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name +
979 builder);
980 }
981 }
982 code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)";
983 for (auto it = unpack_body.begin(); it < unpack_body.end(); it++)
984 code_ += *it;
985 code_ +=
986 "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: "
987 "__root)";
988 Outdent();
989 code_ += "}";
990 }
991
992 void GenerateVectorObjectAPITableExtension(const FieldDef &field,
993 const std::string &name,
994 const std::string &type) {
995 auto vectortype = field.value.type.VectorType();
996 switch (vectortype.base_type) {
997 case BASE_TYPE_UNION: {
998 code_ += "var __" + name + "__: [Offset<UOffset>] = []";
999 code_ += "for i in obj." + name + " {";
1000 Indent();
1001 code_ += "guard let off = i?.pack(builder: &builder) else { continue }";
1002 code_ += "__" + name + "__.append(off)";
1003 Outdent();
1004 code_ += "}";
1005 code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
1006 name + "__)";
1007 code_ += "let __" + name + "Type = builder.createVector(obj." + name +
1008 ".compactMap { $0?.type })";
1009 break;
1010 }
1011 case BASE_TYPE_UTYPE: break;
1012 case BASE_TYPE_STRUCT: {
1013 if (field.value.type.struct_def &&
1014 !field.value.type.struct_def->fixed) {
1015 code_ += "var __" + name + "__: [Offset<UOffset>] = []";
1016 code_ += "for var i in obj." + name + " {";
1017 Indent();
1018 code_ +=
1019 "__" + name + "__.append(" + type + ".pack(&builder, obj: &i))";
1020 Outdent();
1021 code_ += "}";
1022 code_ += "let __" + name + " = builder.createVector(ofOffsets: __" +
1023 name + "__)";
1024 } else {
1025 code_ += "{{STRUCTNAME}}.startVectorOf" + MakeCamel(name, true) +
1026 "(obj." + name + ".count, in: &builder)";
1027 std::string code;
1028 GenerateStructArgs(*field.value.type.struct_def, &code, "", "", "_o",
1029 true);
1030 code = code.substr(0, code.size() - 2);
1031 code_ += "for i in obj." + name + " {";
1032 Indent();
1033 code_ += "guard let _o = i else { continue }";
1034 code_ += NameWrappedInNameSpace(*field.value.type.struct_def) +
1035 ".create" + Name(*field.value.type.struct_def) +
1036 "(builder: &builder, " + code + ")";
1037 Outdent();
1038 code_ += "}";
1039 code_ += "let __" + name +
1040 " = builder.endVectorOfStructs(count: obj." + name +
1041 ".count)";
1042 }
1043 break;
1044 }
1045 case BASE_TYPE_STRING: {
1046 code_ += "let __" + name + " = builder.createVector(ofStrings: obj." +
1047 name + ".compactMap({ $0 }) )";
1048 break;
1049 }
1050 default: {
1051 code_ += "let __" + name + " = builder.createVector(obj." + name + ")";
1052 break;
1053 }
1054 }
1055 }
1056
1057 void BuildingOptionalObjects(const std::string &name,
1058 const std::string &object_type,
1059 const std::string &body_front) {
1060 code_ += "let __" + name + ": Offset<" + object_type + ">";
1061 code_ += "if let s = obj." + name + " {";
1062 Indent();
1063 code_ += "__" + name + " = " + body_front;
1064 Outdent();
1065 code_ += "} else {";
1066 Indent();
1067 code_ += "__" + name + " = Offset<" + object_type + ">()";
1068 Outdent();
1069 code_ += "}";
1070 code_ += "";
1071 }
1072
1073 void BuildObjectAPIConstructor(const std::vector<std::string> &body,
1074 const std::string &header = "") {
1075 code_.SetValue("HEADER", header);
1076 code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {";
1077 Indent();
1078 for (auto it = body.begin(); it < body.end(); ++it) code_ += *it;
1079 Outdent();
1080 code_ += "}\n";
1081 }
1082
1083 void BuildObjectAPIConstructorBody(
1084 const FieldDef &field, bool is_fixed,
1085 std::vector<std::string> &buffer_constructor,
1086 std::vector<std::string> &base_constructor) {
1087 auto name = Name(field);
1088 auto type = GenType(field.value.type);
1089 code_.SetValue("VALUENAME", name);
1090 code_.SetValue("VALUETYPE", type);
1091 std::string is_required = field.required ? "" : "?";
1092
1093 switch (field.value.type.base_type) {
1094 case BASE_TYPE_STRUCT: {
1095 type = GenType(field.value.type, true);
1096 code_.SetValue("VALUETYPE", type);
1097 buffer_constructor.push_back("var __" + name + " = _t." + name);
1098 auto optional =
1099 (field.value.type.struct_def && field.value.type.struct_def->fixed);
1100 std::string question_mark =
1101 (field.required || (optional && is_fixed) ? "" : "?");
1102
1103 code_ +=
1104 "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark;
1105 buffer_constructor.push_back("" + name + " = __" + name +
1106 (field.required ? "!" : question_mark) +
1107 ".unpack()");
1108 base_constructor.push_back("" + name + " = " + type + "()");
1109 break;
1110 }
1111 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1112 case BASE_TYPE_VECTOR: {
1113 BuildObjectAPIConstructorBodyVectors(field, name, buffer_constructor,
1114 base_constructor, " ");
1115 break;
1116 }
1117 case BASE_TYPE_STRING: {
1118 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required;
1119 buffer_constructor.push_back(name + " = _t." + name);
1120 if (field.required) base_constructor.push_back(name + " = \"\"");
1121 break;
1122 }
1123 case BASE_TYPE_UTYPE: break;
1124 case BASE_TYPE_UNION: {
1125 BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
1126 buffer_constructor);
1127 break;
1128 }
1129 default: {
1130 buffer_constructor.push_back(name + " = _t." + name);
1131 std::string nullable = field.optional ? "?" : "";
1132 if (IsScalar(field.value.type.base_type) &&
1133 !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) {
1134 code_ +=
1135 "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + nullable;
1136 if (!field.optional)
1137 base_constructor.push_back(name + " = " + field.value.constant);
1138 break;
1139 }
1140
1141 if (IsEnum(field.value.type)) {
1142 auto default_value = IsEnum(field.value.type)
1143 ? GenEnumDefaultValue(field)
1144 : field.value.constant;
1145 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}";
1146 base_constructor.push_back(name + " = " + default_value);
1147 break;
1148 }
1149
1150 if (IsBool(field.value.type.base_type)) {
1151 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable;
1152 std::string default_value =
1153 "0" == field.value.constant ? "false" : "true";
1154 if (!field.optional)
1155 base_constructor.push_back(name + " = " + default_value);
1156 }
1157 }
1158 }
1159 }
1160
1161 void BuildObjectAPIConstructorBodyVectors(
1162 const FieldDef &field, const std::string &name,
1163 std::vector<std::string> &buffer_constructor,
1164 std::vector<std::string> &base_constructor,
1165 const std::string &indentation) {
1166 auto vectortype = field.value.type.VectorType();
1167
1168 if (vectortype.base_type != BASE_TYPE_UTYPE) {
1169 buffer_constructor.push_back(name + " = []");
1170 buffer_constructor.push_back("for index in 0..<_t." + name + "Count {");
1171 base_constructor.push_back(name + " = []");
1172 }
1173
1174 switch (vectortype.base_type) {
1175 case BASE_TYPE_STRUCT: {
1176 code_.SetValue("VALUETYPE", GenType(vectortype, true));
1177 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]";
1178 buffer_constructor.push_back(indentation + "var __v_ = _t." + name +
1179 "(at: index)");
1180 buffer_constructor.push_back(indentation + name +
1181 ".append(__v_?.unpack())");
1182 break;
1183 }
1184 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();
1185 case BASE_TYPE_VECTOR: {
1186 break;
1187 }
1188 case BASE_TYPE_UNION: {
1189 BuildUnionEnumSwitchCase(*field.value.type.enum_def, name,
1190 buffer_constructor, indentation, true);
1191 break;
1192 }
1193 case BASE_TYPE_UTYPE: break;
1194 default: {
1195 code_.SetValue("VALUETYPE", (IsString(vectortype)
1196 ? "String?"
1197 : GenType(vectortype)));
1198 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]";
1199
1200 if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) {
1201 auto default_value = IsEnum(field.value.type)
1202 ? GenEnumDefaultValue(field)
1203 : field.value.constant;
1204 buffer_constructor.push_back(indentation + name + ".append(_t." +
1205 name + "(at: index)!)");
1206 break;
1207 }
1208 buffer_constructor.push_back(indentation + name + ".append(_t." + name +
1209 "(at: index))");
1210 break;
1211 }
1212 }
1213 if (vectortype.base_type != BASE_TYPE_UTYPE)
1214 buffer_constructor.push_back("}");
1215 }
1216
1217 void BuildUnionEnumSwitchCaseWritter(const EnumDef &ev) {
1218 auto field_name = Name(ev);
1219 code_.SetValue("VALUETYPE", field_name);
1220 code_ += "switch type {";
1221 for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
1222 auto field = **it;
1223 auto ev_name = Name(field);
1224 auto type = GenType(field.union_type);
1225
1226 if (field.union_type.base_type == BASE_TYPE_NONE ||
1227 IsString(field.union_type)) {
1228 continue;
1229 }
1230 code_ += "case ." + ev_name + ":";
1231 Indent();
1232 code_ += "var __obj = value as? " + GenType(field.union_type, true);
1233 code_ += "return " + type + ".pack(&builder, obj: &__obj)";
1234 Outdent();
1235 }
1236 code_ += "default: return Offset()";
1237 code_ += "}";
1238 }
1239
1240 void BuildUnionEnumSwitchCase(const EnumDef &ev, const std::string &name,
1241 std::vector<std::string> &buffer_constructor,
1242 const std::string &indentation = "",
1243 const bool is_vector = false) {
1244 auto field_name = NameWrappedInNameSpace(ev);
1245 code_.SetValue("VALUETYPE", field_name);
1246 code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: \\";
1247 code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?";
1248
1249 auto vector_reader = is_vector ? "(at: index" : "";
1250 buffer_constructor.push_back(indentation + "switch _t." + name + "Type" +
1251 vector_reader + (is_vector ? ")" : "") + " {");
1252
1253 for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) {
1254 auto field = **it;
1255 auto ev_name = Name(field);
1256 if (field.union_type.base_type == BASE_TYPE_NONE ||
1257 IsString(field.union_type)) {
1258 continue;
1259 }
1260 buffer_constructor.push_back(indentation + "case ." + ev_name + ":");
1261 buffer_constructor.push_back(
1262 indentation + " var _v = _t." + name + (is_vector ? "" : "(") +
1263 vector_reader + (is_vector ? ", " : "") +
1264 "type: " + GenType(field.union_type) + ".self)");
1265 auto constructor =
1266 field_name + "Union(_v?.unpack(), type: ." + ev_name + ")";
1267 buffer_constructor.push_back(
1268 indentation + " " + name +
1269 (is_vector ? ".append(" + constructor + ")" : " = " + constructor));
1270 }
1271 buffer_constructor.push_back(indentation + "default: break");
1272 buffer_constructor.push_back(indentation + "}");
1273 }
1274
1275 void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
1276 auto current_value = str;
1277 code_.SetValue(type, current_value);
1278 code_ += "{{ACCESS_TYPE}} static var " + type +
1279 ": {{ENUM_NAME}} { return .{{" + type + "}} }";
1280 }
1281
1282 void GenLookup(const FieldDef &key_field) {
1283 code_.SetValue("OFFSET", NumToString(key_field.value.offset));
1284 std::string offset_reader =
1285 "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
1286 "fbb: fbb)";
1287
1288 code_.SetValue("TYPE", GenType(key_field.value.type));
1289 code_ +=
1290 "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
1291 "fbb: "
1292 "ByteBuffer) -> {{VALUENAME}}? {";
1293 Indent();
1294 if (IsString(key_field.value.type))
1295 code_ += "let key = key.utf8.map { $0 }";
1296 code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
1297 code_ += "var start: Int32 = 0";
1298 code_ += "while span != 0 {";
1299 Indent();
1300 code_ += "var middle = span / 2";
1301 code_ +=
1302 "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
1303 if (IsString(key_field.value.type)) {
1304 code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)";
1305 } else {
1306 code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
1307 offset_reader + "))";
1308 }
1309
1310 code_ += "if comp > 0 {";
1311 Indent();
1312 code_ += "span = middle";
1313 Outdent();
1314 code_ += "} else if comp < 0 {";
1315 Indent();
1316 code_ += "middle += 1";
1317 code_ += "start += middle";
1318 code_ += "span -= middle";
1319 Outdent();
1320 code_ += "} else {";
1321 Indent();
1322 code_ += "return {{VALUENAME}}(fbb, o: tableOffset)";
1323 Outdent();
1324 code_ += "}";
1325 Outdent();
1326 code_ += "}";
1327 code_ += "return nil";
1328 Outdent();
1329 code_ += "}";
1330 }
1331
1332 void GenComment(const std::vector<std::string> &dc) {
1333 if (dc.begin() == dc.end()) {
1334 // Don't output empty comment blocks with 0 lines of comment content.
1335 return;
1336 }
1337 for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; }
1338 }
1339
1340 std::string GenOffset() {
1341 return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
1342 }
1343
1344 std::string GenReaderMainBody(const std::string &optional = "") {
1345 return "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + optional +
1346 " { ";
1347 }
1348
1349 std::string GenReader(const std::string &type,
1350 const std::string &at = "{{OFFSET}}") {
1351 return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
1352 }
1353
1354 std::string GenConstructor(const std::string &offset) {
1355 return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
1356 }
1357
1358 std::string GenMutate(const std::string &offset,
1359 const std::string &get_offset, bool isRaw = false) {
1360 return "@discardableResult {{ACCESS_TYPE}} func mutate({{VALUENAME}}: "
1361 "{{VALUETYPE}}) -> Bool {" +
1362 get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
1363 (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
1364 }
1365
1366 std::string GenMutateArray() {
1367 return "{{ACCESS_TYPE}} func mutate({{VALUENAME}}: {{VALUETYPE}}, at "
1368 "index: "
1369 "Int32) -> Bool { " +
1370 GenOffset() +
1371 "return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
1372 "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
1373 }
1374
1375 std::string GenEnumDefaultValue(const FieldDef &field) {
1376 auto &value = field.value;
1377 FLATBUFFERS_ASSERT(value.type.enum_def);
1378 auto &enum_def = *value.type.enum_def;
1379 auto enum_val = enum_def.FindByValue(value.constant);
1380 std::string name;
1381 if (enum_val) {
1382 name = Name(*enum_val);
1383 } else {
1384 const auto &ev = **enum_def.Vals().begin();
1385 name = Name(ev);
1386 }
1387 std::transform(name.begin(), name.end(), name.begin(), CharToLower);
1388 return "." + name;
1389 }
1390
1391 std::string GenEnumConstructor(const std::string &at) {
1392 return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
1393 }
1394
1395 std::string ValidateFunc() {
1396 return "static func validateVersion() { FlatBuffersVersion_1_12_0() }";
1397 }
1398
1399 std::string GenType(const Type &type,
1400 const bool should_consider_suffix = false) const {
1401 return IsScalar(type.base_type)
1402 ? GenTypeBasic(type)
1403 : (IsArray(type) ? GenType(type.VectorType())
1404 : GenTypePointer(type, should_consider_suffix));
1405 }
1406
1407 std::string GenTypePointer(const Type &type,
1408 const bool should_consider_suffix) const {
1409 switch (type.base_type) {
1410 case BASE_TYPE_STRING: return "String";
1411 case BASE_TYPE_VECTOR: return GenType(type.VectorType());
1412 case BASE_TYPE_STRUCT: {
1413 auto &struct_ = *type.struct_def;
1414 if (should_consider_suffix) {
1415 return WrapInNameSpace(struct_.defined_namespace,
1416 ObjectAPIName(Name(struct_)));
1417 }
1418 return WrapInNameSpace(struct_.defined_namespace, Name(struct_));
1419 }
1420 case BASE_TYPE_UNION:
1421 default: return "FlatBufferObject";
1422 }
1423 }
1424
1425 std::string GenTypeBasic(const Type &type) const {
1426 return GenTypeBasic(type, true);
1427 }
1428
1429 std::string ObjectAPIName(const std::string &name) const {
1430 return parser_.opts.object_prefix + name + parser_.opts.object_suffix;
1431 }
1432
1433 void Indent() { code_.IncrementIdentLevel(); }
1434
1435 void Outdent() { code_.DecrementIdentLevel(); }
1436
1437 std::string NameWrappedInNameSpace(const EnumDef &enum_def) const {
1438 return WrapInNameSpace(enum_def.defined_namespace, Name(enum_def));
1439 }
1440
1441 std::string NameWrappedInNameSpace(const StructDef &struct_def) const {
1442 return WrapInNameSpace(struct_def.defined_namespace, Name(struct_def));
1443 }
1444
1445 std::string GenTypeBasic(const Type &type, bool can_override) const {
1446 // clang-format off
1447 static const char * const swift_type[] = {
1448 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1449 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
1450 #STYPE,
1451 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1452 #undef FLATBUFFERS_TD
1453 };
1454 // clang-format on
1455 if (can_override) {
1456 if (type.enum_def) return NameWrappedInNameSpace(*type.enum_def);
1457 if (type.base_type == BASE_TYPE_BOOL) return "Bool";
1458 }
1459 return swift_type[static_cast<int>(type.base_type)];
1460 }
1461
1462 std::string EscapeKeyword(const std::string &name) const {
1463 return keywords_.find(name) == keywords_.end() ? name : name + "_";
1464 }
1465
1466 std::string Name(const EnumVal &ev) const {
1467 auto name = ev.name;
1468 if (isupper(name.front())) {
1469 std::transform(name.begin(), name.end(), name.begin(), CharToLower);
1470 }
1471 return EscapeKeyword(MakeCamel(name, false));
1472 }
1473
1474 std::string Name(const Definition &def) const {
1475 return EscapeKeyword(MakeCamel(def.name, false));
1476 }
1477};
1478} // namespace swift
1479bool GenerateSwift(const Parser &parser, const std::string &path,
1480 const std::string &file_name) {
1481 swift::SwiftGenerator generator(parser, path, file_name);
1482 return generator.generate();
1483}
1484} // namespace flatbuffers