1 | /* |
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 | |
25 | namespace flatbuffers { |
26 | |
27 | namespace swift { |
28 | |
29 | inline std::string GenIndirect(const std::string &reading) { |
30 | return "{{ACCESS}}.indirect(" + reading + ")" ; |
31 | } |
32 | |
33 | inline std::string GenArrayMainBody(const std::string &optional) { |
34 | return "{{ACCESS_TYPE}} func {{VALUENAME}}(at index: Int32) -> " |
35 | "{{VALUETYPE}}" + |
36 | optional + " { " ; |
37 | } |
38 | |
39 | class 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 | "Void" , |
131 | 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()); |
141 | code_ += "// swiftlint:disable all" ; |
142 | code_ += "// swiftformat:disable all\n" ; |
143 | 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); |
157 | GenMutableStructReader(struct_def); |
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 | 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 | |
182 | // 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 | |
344 | // 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 = "" ; |
357 | GenerateStructArgs(struct_def, &func_header, "" , "" ); |
358 | code_ += func_header.substr(0, func_header.size() - 2) + "\\" ; |
359 | code_ += ") -> Offset {" ; |
360 | Indent(); |
361 | code_ += |
362 | "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: " |
363 | "{{STRUCTNAME}}.alignment)" ; |
364 | code_ += "return builder.endStruct()" ; |
365 | Outdent(); |
366 | code_ += "}\n" ; |
367 | Outdent(); |
368 | code_ += "}\n" ; |
369 | } |
370 | |
371 | 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 | |
409 | // MARK: - Table Generator |
410 | |
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" ); |
415 | 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); |
421 | code_ += "" ; |
422 | GenerateVerifier(struct_def); |
423 | Outdent(); |
424 | code_ += "}\n" ; |
425 | if (parser_.opts.gen_json_coders) GenerateJSONEncodingAPIs(struct_def); |
426 | } |
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 | |
450 | void (const StructDef &struct_def) { |
451 | GenComment(struct_def.doc_comment); |
452 | |
453 | 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 }" ; |
485 | } |
486 | code_ += |
487 | "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = " |
488 | "{{OBJECTTYPE}}(bb: " |
489 | "bb, position: o) }" ; |
490 | code_ += "" ; |
491 | } |
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> ; |
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; |
511 | if (field.IsRequired()) |
512 | require_fields.push_back(NumToString(field.value.offset)); |
513 | |
514 | GenTableWriterFields(field, &create_func_body, &create_func_header); |
515 | } |
516 | code_ += |
517 | "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout " |
518 | "FlatBufferBuilder, " |
519 | "start: " |
520 | "UOffset) -> Offset { let end = Offset(offset: " |
521 | "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(); |
542 | code_ += ") -> Offset {" ; |
543 | 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 " |
564 | "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset], " |
565 | "_ fbb: inout FlatBufferBuilder) -> Offset {" ; |
566 | 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, |
582 | std::vector<std::string> *) { |
583 | std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { " ; |
584 | auto &create_func_body = *create_body; |
585 | auto & = *create_header; |
586 | auto name = Name(field); |
587 | auto type = GenType(field.value.type); |
588 | auto opt_scalar = |
589 | field.IsOptional() && IsScalar(field.value.type.base_type); |
590 | 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 = |
596 | (IsVector(field.value.type) || IsArray(field.value.type)) ? "VectorOf(" |
597 | : "(" ; |
598 | 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 | |
611 | code_ += field.IsOptional() ? (optional_enum + "\\" ) |
612 | : (is_enum + ", def: {{CONSTANT}}\\" ); |
613 | |
614 | code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }" ; |
615 | |
616 | auto default_value = |
617 | IsEnum(field.value.type) |
618 | ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field)) |
619 | : field.value.constant; |
620 | create_func_header.push_back( |
621 | "" + name + ": " + nullable_type + " = " + |
622 | (field.IsOptional() ? "nil" : default_value)); |
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 | |
630 | code_.SetValue("CONSTANT" , default_value); |
631 | code_.SetValue("VALUETYPE" , field.IsOptional() ? "Bool?" : "Bool" ); |
632 | code_ += "{{VALUETYPE}}" + builder_string + |
633 | "fbb.add(element: {{VALUENAME}},\\" ; |
634 | code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}}," ; |
635 | code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }" ; |
636 | create_func_header.push_back( |
637 | name + ": " + nullable_type + " = " + |
638 | (field.IsOptional() ? "nil" : default_value)); |
639 | return; |
640 | } |
641 | |
642 | if (IsStruct(field.value.type)) { |
643 | 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" ); |
650 | return; |
651 | } |
652 | |
653 | auto camel_case_name = |
654 | MakeCamel(name, false) + |
655 | (IsVector(field.value.type) || IsArray(field.value.type) |
656 | ? "VectorOffset" |
657 | : "Offset" ); |
658 | create_func_header.push_back(camel_case_name + " " + name + ": " + |
659 | "Offset = Offset()" ); |
660 | 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) }" ; |
664 | code_ += "Offset" + builder_string + "fbb.add(" + reader_type; |
665 | |
666 | auto vectortype = field.value.type.VectorType(); |
667 | |
668 | if ((vectortype.base_type == BASE_TYPE_STRUCT && |
669 | field.value.type.struct_def->fixed) && |
670 | (IsVector(field.value.type) || IsArray(field.value.type))) { |
671 | auto field_name = NameWrappedInNameSpace(*vectortype.struct_def); |
672 | code_ += "public static func startVectorOf" + MakeCamel(name, true) + |
673 | "(_ size: Int, in builder: inout " |
674 | "FlatBufferBuilder) {" ; |
675 | Indent(); |
676 | code_ += "builder.startVector(size * MemoryLayout<" + field_name + |
677 | ">.size, elementSize: MemoryLayout<" + field_name + |
678 | ">.alignment)" ; |
679 | Outdent(); |
680 | code_ += "}" ; |
681 | } |
682 | } |
683 | |
684 | void GenTableReader(const StructDef &struct_def) { |
685 | for (auto it = struct_def.fields.vec.begin(); |
686 | it != struct_def.fields.vec.end(); ++it) { |
687 | auto &field = **it; |
688 | if (field.deprecated) continue; |
689 | GenTableReaderFields(field); |
690 | } |
691 | } |
692 | |
693 | void GenTableReaderFields(const FieldDef &field) { |
694 | auto offset = NumToString(field.value.offset); |
695 | auto name = Name(field); |
696 | auto type = GenType(field.value.type); |
697 | code_.SetValue("VALUENAME" , name); |
698 | code_.SetValue("VALUETYPE" , type); |
699 | code_.SetValue("OFFSET" , name); |
700 | code_.SetValue("CONSTANT" , field.value.constant); |
701 | bool opt_scalar = |
702 | field.IsOptional() && IsScalar(field.value.type.base_type); |
703 | std::string def_Val = opt_scalar ? "nil" : "{{CONSTANT}}" ; |
704 | std::string optional = opt_scalar ? "?" : "" ; |
705 | auto const_string = "return o == 0 ? " + def_Val + " : " ; |
706 | GenComment(field.doc_comment); |
707 | if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) && |
708 | !IsBool(field.value.type.base_type)) { |
709 | code_ += GenReaderMainBody(optional) + GenOffset() + const_string + |
710 | GenReader("VALUETYPE" , "o" ) + " }" ; |
711 | if (parser_.opts.mutable_buffer) code_ += GenMutate("o" , GenOffset()); |
712 | return; |
713 | } |
714 | |
715 | if (IsBool(field.value.type.base_type)) { |
716 | std::string default_value = |
717 | field.IsOptional() ? "nil" |
718 | : ("0" == field.value.constant ? "false" : "true" ); |
719 | code_.SetValue("CONSTANT" , default_value); |
720 | code_.SetValue("VALUETYPE" , "Bool" ); |
721 | code_ += GenReaderMainBody(optional) + "\\" ; |
722 | code_.SetValue("VALUETYPE" , "Byte" ); |
723 | code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " + |
724 | GenReader("VALUETYPE" , "o" ) + " }" ; |
725 | if (parser_.opts.mutable_buffer) code_ += GenMutate("o" , GenOffset()); |
726 | return; |
727 | } |
728 | |
729 | if (IsEnum(field.value.type)) { |
730 | auto default_value = |
731 | field.IsOptional() ? "nil" : GenEnumDefaultValue(field); |
732 | code_.SetValue("BASEVALUE" , GenTypeBasic(field.value.type, false)); |
733 | code_ += GenReaderMainBody(optional) + "\\" ; |
734 | code_ += GenOffset() + "return o == 0 ? " + default_value + " : " + |
735 | GenEnumConstructor("o" ) + "?? " + default_value + " }" ; |
736 | if (parser_.opts.mutable_buffer && !IsUnion(field.value.type)) |
737 | code_ += GenMutate("o" , GenOffset(), true); |
738 | return; |
739 | } |
740 | |
741 | std::string is_required = field.IsRequired() ? "!" : "?" ; |
742 | auto required_reader = field.IsRequired() ? "return " : const_string; |
743 | |
744 | if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) { |
745 | code_.SetValue("VALUETYPE" , GenType(field.value.type)); |
746 | code_.SetValue("CONSTANT" , "nil" ); |
747 | code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader + |
748 | "{{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, at: o) }" ; |
749 | code_.SetValue("VALUENAME" , "mutable" + MakeCamel(name)); |
750 | code_.SetValue("VALUETYPE" , GenType(field.value.type) + Mutable()); |
751 | code_.SetValue("CONSTANT" , "nil" ); |
752 | code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader + |
753 | GenConstructor("o + {{ACCESS}}.postion" ); |
754 | return; |
755 | } |
756 | switch (field.value.type.base_type) { |
757 | case BASE_TYPE_STRUCT: |
758 | code_.SetValue("VALUETYPE" , GenType(field.value.type)); |
759 | code_.SetValue("CONSTANT" , "nil" ); |
760 | code_ += GenReaderMainBody(is_required) + GenOffset() + |
761 | required_reader + |
762 | GenConstructor(GenIndirect("o + {{ACCESS}}.postion" )); |
763 | break; |
764 | |
765 | case BASE_TYPE_STRING: { |
766 | auto default_string = "\"" + field.value.constant + "\"" ; |
767 | code_.SetValue("VALUETYPE" , GenType(field.value.type)); |
768 | code_.SetValue("CONSTANT" , field.IsDefault() ? default_string : "nil" ); |
769 | code_ += GenReaderMainBody(is_required) + GenOffset() + |
770 | required_reader + "{{ACCESS}}.string(at: o) }" ; |
771 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}SegmentArray: [UInt8]" + |
772 | is_required + |
773 | " { return " |
774 | "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }" ; |
775 | break; |
776 | } |
777 | case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru |
778 | case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break; |
779 | case BASE_TYPE_UNION: |
780 | code_.SetValue("CONSTANT" , "nil" ); |
781 | code_ += |
782 | "{{ACCESS_TYPE}} func {{VALUENAME}}<T: " |
783 | "FlatbuffersInitializable>(type: " |
784 | "T.Type) -> T" + |
785 | is_required + " { " + GenOffset() + required_reader + |
786 | "{{ACCESS}}.union(o) }" ; |
787 | break; |
788 | default: FLATBUFFERS_ASSERT(0); |
789 | } |
790 | } |
791 | |
792 | void GenTableReaderVectorFields(const FieldDef &field) { |
793 | std::string const_string = "return o == 0 ? {{CONSTANT}} : " ; |
794 | auto vectortype = field.value.type.VectorType(); |
795 | code_.SetValue("SIZE" , NumToString(InlineSize(vectortype))); |
796 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}Count: Int32 { " + GenOffset() + |
797 | "return o == 0 ? 0 : {{ACCESS}}.vector(count: o) }" ; |
798 | code_.SetValue("CONSTANT" , |
799 | IsScalar(vectortype.base_type) == true ? "0" : "nil" ); |
800 | auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?" ; |
801 | nullable = IsEnum(vectortype) == true ? "?" : nullable; |
802 | |
803 | if (vectortype.base_type != BASE_TYPE_UNION) { |
804 | code_ += GenArrayMainBody(nullable) + GenOffset() + "\\" ; |
805 | } else { |
806 | code_ += |
807 | "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatbuffersInitializable>(at " |
808 | "index: " |
809 | "Int32, type: T.Type) -> T? { " + |
810 | GenOffset() + "\\" ; |
811 | } |
812 | |
813 | if (IsBool(vectortype.base_type)) { |
814 | code_.SetValue("CONSTANT" , field.value.offset == 0 ? "false" : "true" ); |
815 | code_.SetValue("VALUETYPE" , "Bool" ); |
816 | } |
817 | |
818 | if (!IsEnum(vectortype)) code_ += const_string + "\\" ; |
819 | |
820 | if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) && |
821 | !IsBool(field.value.type.base_type)) { |
822 | code_ += |
823 | "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: " |
824 | "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }" ; |
825 | code_ += |
826 | "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}] { return " |
827 | "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }" ; |
828 | if (parser_.opts.mutable_buffer) code_ += GenMutateArray(); |
829 | return; |
830 | } |
831 | |
832 | if (vectortype.base_type == BASE_TYPE_STRUCT && |
833 | field.value.type.struct_def->fixed) { |
834 | code_ += |
835 | "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: " |
836 | "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }" ; |
837 | code_.SetValue("VALUENAME" , "mutable" + MakeCamel(Name(field))); |
838 | code_.SetValue("VALUETYPE" , GenType(field.value.type) + Mutable()); |
839 | code_ += GenArrayMainBody(nullable) + GenOffset() + const_string + |
840 | GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}" ); |
841 | |
842 | return; |
843 | } |
844 | |
845 | if (IsString(vectortype)) { |
846 | code_ += |
847 | "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + " |
848 | "index * {{SIZE}}) }" ; |
849 | return; |
850 | } |
851 | |
852 | if (IsEnum(vectortype)) { |
853 | code_.SetValue("BASEVALUE" , GenTypeBasic(vectortype, false)); |
854 | code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) + |
855 | " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: " |
856 | "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + " |
857 | "index * {{SIZE}})) }" ; |
858 | return; |
859 | } |
860 | if (vectortype.base_type == BASE_TYPE_UNION) { |
861 | code_ += |
862 | "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + " |
863 | "index * {{SIZE}}) }" ; |
864 | return; |
865 | } |
866 | |
867 | if (vectortype.base_type == BASE_TYPE_STRUCT && |
868 | !field.value.type.struct_def->fixed) { |
869 | code_ += GenConstructor( |
870 | "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * " |
871 | "{{SIZE}})" ); |
872 | auto &sd = *field.value.type.struct_def; |
873 | auto &fields = sd.fields.vec; |
874 | for (auto kit = fields.begin(); kit != fields.end(); ++kit) { |
875 | auto &key_field = **kit; |
876 | if (key_field.key) { |
877 | GenByKeyFunctions(key_field); |
878 | break; |
879 | } |
880 | } |
881 | } |
882 | } |
883 | |
884 | void GenerateCodingKeys(const StructDef &struct_def) { |
885 | code_ += "enum CodingKeys: String, CodingKey {" ; |
886 | Indent(); |
887 | for (auto it = struct_def.fields.vec.begin(); |
888 | it != struct_def.fields.vec.end(); ++it) { |
889 | auto &field = **it; |
890 | if (field.deprecated) continue; |
891 | auto name = Name(field); |
892 | |
893 | code_.SetValue("RAWVALUENAME" , field.name); |
894 | code_.SetValue("VALUENAME" , name); |
895 | code_ += "case {{VALUENAME}} = \"{{RAWVALUENAME}}\"" ; |
896 | } |
897 | Outdent(); |
898 | code_ += "}" ; |
899 | } |
900 | |
901 | void GenerateEncoderUnionBody(const FieldDef &field) { |
902 | EnumDef &union_def = *field.value.type.enum_def; |
903 | auto is_vector = field.value.type.base_type == BASE_TYPE_VECTOR || |
904 | field.value.type.base_type == BASE_TYPE_ARRAY; |
905 | if (field.value.type.base_type == BASE_TYPE_UTYPE || |
906 | (is_vector && |
907 | field.value.type.VectorType().base_type == BASE_TYPE_UTYPE)) |
908 | return; |
909 | if (is_vector) { |
910 | code_ += |
911 | "var enumsEncoder = container.nestedUnkeyedContainer(forKey: " |
912 | ".{{VALUENAME}}Type)" ; |
913 | code_ += |
914 | "var contentEncoder = container.nestedUnkeyedContainer(forKey: " |
915 | ".{{VALUENAME}})" ; |
916 | code_ += "for index in 0..<{{VALUENAME}}Count {" ; |
917 | Indent(); |
918 | code_ += |
919 | "guard let type = {{VALUENAME}}Type(at: index) else { continue }" ; |
920 | code_ += "try enumsEncoder.encode(type)" ; |
921 | code_ += "switch type {" ; |
922 | for (auto it = union_def.Vals().begin(); it != union_def.Vals().end(); |
923 | ++it) { |
924 | const auto &ev = **it; |
925 | |
926 | auto name = Name(ev); |
927 | auto type = GenType(ev.union_type); |
928 | code_.SetValue("KEY" , name); |
929 | code_.SetValue("VALUETYPE" , type); |
930 | if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } |
931 | code_ += "case .{{KEY}}:" ; |
932 | Indent(); |
933 | code_ += "let _v = {{VALUENAME}}(at: index, type: {{VALUETYPE}}.self)" ; |
934 | code_ += "try contentEncoder.encode(_v)" ; |
935 | Outdent(); |
936 | } |
937 | code_ += "default: break;" ; |
938 | code_ += "}" ; |
939 | Outdent(); |
940 | code_ += "}" ; |
941 | return; |
942 | } |
943 | |
944 | code_ += "switch {{VALUENAME}}Type {" ; |
945 | for (auto it = union_def.Vals().begin(); it != union_def.Vals().end(); |
946 | ++it) { |
947 | const auto &ev = **it; |
948 | |
949 | auto name = Name(ev); |
950 | auto type = GenType(ev.union_type); |
951 | code_.SetValue("KEY" , name); |
952 | code_.SetValue("VALUETYPE" , type); |
953 | if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } |
954 | code_ += "case .{{KEY}}:" ; |
955 | Indent(); |
956 | code_ += "let _v = {{VALUENAME}}(type: {{VALUETYPE}}.self)" ; |
957 | code_ += "try container.encodeIfPresent(_v, forKey: .{{VALUENAME}})" ; |
958 | Outdent(); |
959 | } |
960 | code_ += "default: break;" ; |
961 | code_ += "}" ; |
962 | } |
963 | |
964 | void GenerateEncoderBody(const StructDef &struct_def) { |
965 | code_ += "var container = encoder.container(keyedBy: CodingKeys.self)" ; |
966 | for (auto it = struct_def.fields.vec.begin(); |
967 | it != struct_def.fields.vec.end(); ++it) { |
968 | auto &field = **it; |
969 | if (field.deprecated) continue; |
970 | auto name = Name(field); |
971 | auto type = field.value.type; |
972 | |
973 | auto is_non_union_vector = |
974 | (field.value.type.base_type == BASE_TYPE_ARRAY || |
975 | field.value.type.base_type == BASE_TYPE_VECTOR) && |
976 | field.value.type.VectorType().base_type != BASE_TYPE_UTYPE; |
977 | |
978 | code_.SetValue("RAWVALUENAME" , field.name); |
979 | code_.SetValue("VALUENAME" , name); |
980 | code_.SetValue("CONSTANT" , field.value.constant); |
981 | bool should_indent = true; |
982 | if (is_non_union_vector) { |
983 | code_ += "if {{VALUENAME}}Count > 0 {" ; |
984 | } else if (IsEnum(type) && !field.IsOptional()) { |
985 | code_.SetValue("CONSTANT" , GenEnumDefaultValue(field)); |
986 | code_ += "if {{VALUENAME}} != {{CONSTANT}} {" ; |
987 | } else if (IsScalar(type.base_type) && !IsEnum(type) && |
988 | !IsBool(type.base_type) && !field.IsOptional()) { |
989 | code_ += "if {{VALUENAME}} != {{CONSTANT}} {" ; |
990 | } else if (IsBool(type.base_type) && !field.IsOptional()) { |
991 | std::string default_value = |
992 | "0" == field.value.constant ? "false" : "true" ; |
993 | code_.SetValue("CONSTANT" , default_value); |
994 | code_ += "if {{VALUENAME}} != {{CONSTANT}} {" ; |
995 | } else { |
996 | should_indent = false; |
997 | } |
998 | if (should_indent) Indent(); |
999 | |
1000 | if (IsUnion(type) && !IsEnum(type)) { |
1001 | GenerateEncoderUnionBody(field); |
1002 | } else if (is_non_union_vector && |
1003 | (!IsScalar(type.VectorType().base_type) || |
1004 | IsEnum(type.VectorType()))) { |
1005 | code_ += |
1006 | "var contentEncoder = container.nestedUnkeyedContainer(forKey: " |
1007 | ".{{VALUENAME}})" ; |
1008 | code_ += "for index in 0..<{{VALUENAME}}Count {" ; |
1009 | Indent(); |
1010 | code_ += "guard let type = {{VALUENAME}}(at: index) else { continue }" ; |
1011 | code_ += "try contentEncoder.encode(type)" ; |
1012 | Outdent(); |
1013 | code_ += "}" ; |
1014 | } else { |
1015 | code_ += |
1016 | "try container.encodeIfPresent({{VALUENAME}}, forKey: " |
1017 | ".{{VALUENAME}})" ; |
1018 | } |
1019 | if (should_indent) Outdent(); |
1020 | |
1021 | if (is_non_union_vector || |
1022 | (IsScalar(type.base_type) && !field.IsOptional())) { |
1023 | code_ += "}" ; |
1024 | } |
1025 | } |
1026 | } |
1027 | |
1028 | void GenerateJSONEncodingAPIs(const StructDef &struct_def) { |
1029 | code_ += "extension {{STRUCTNAME}}: Encodable {" ; |
1030 | Indent(); |
1031 | code_ += "" ; |
1032 | if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def); |
1033 | |
1034 | code_ += "public func encode(to encoder: Encoder) throws {" ; |
1035 | Indent(); |
1036 | if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def); |
1037 | Outdent(); |
1038 | code_ += "}" ; |
1039 | Outdent(); |
1040 | code_ += "}" ; |
1041 | code_ += "" ; |
1042 | } |
1043 | |
1044 | void GenerateVerifier(const StructDef &struct_def) { |
1045 | code_ += |
1046 | "public static func verify<T>(_ verifier: inout Verifier, at position: " |
1047 | "Int, of type: T.Type) throws where T: Verifiable {" ; |
1048 | Indent(); |
1049 | code_ += "var _v = try verifier.visitTable(at: position)" ; |
1050 | for (auto it = struct_def.fields.vec.begin(); |
1051 | it != struct_def.fields.vec.end(); ++it) { |
1052 | auto &field = **it; |
1053 | if (field.deprecated) continue; |
1054 | auto offset = NumToString(field.value.offset); |
1055 | auto name = Name(field); |
1056 | |
1057 | code_.SetValue("VALUENAME" , name); |
1058 | code_.SetValue("VALUETYPE" , GenerateVerifierType(field)); |
1059 | code_.SetValue("OFFSET" , name); |
1060 | code_.SetValue("ISREQUIRED" , field.IsRequired() ? "true" : "false" ); |
1061 | |
1062 | if (IsUnion(field.value.type)) { |
1063 | GenerateUnionTypeVerifier(field); |
1064 | continue; |
1065 | } |
1066 | |
1067 | code_ += |
1068 | "try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: " |
1069 | "\"{{VALUENAME}}\", required: {{ISREQUIRED}}, type: " |
1070 | "{{VALUETYPE}}.self)" ; |
1071 | } |
1072 | code_ += "_v.finish()" ; |
1073 | Outdent(); |
1074 | code_ += "}" ; |
1075 | } |
1076 | |
1077 | void GenerateUnionTypeVerifier(const FieldDef &field) { |
1078 | auto is_vector = IsVector(field.value.type) || IsArray(field.value.type); |
1079 | if (field.value.type.base_type == BASE_TYPE_UTYPE || |
1080 | (is_vector && |
1081 | field.value.type.VectorType().base_type == BASE_TYPE_UTYPE)) |
1082 | return; |
1083 | EnumDef &union_def = *field.value.type.enum_def; |
1084 | code_.SetValue("VALUETYPE" , NameWrappedInNameSpace(union_def)); |
1085 | code_.SetValue("FUNCTION_NAME" , is_vector ? "visitUnionVector" : "visit" ); |
1086 | code_ += |
1087 | "try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, " |
1088 | "unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: " |
1089 | "\"{{VALUENAME}}Type\", fieldName: \"{{VALUENAME}}\", required: " |
1090 | "{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in" ; |
1091 | Indent(); |
1092 | code_ += "switch key {" ; |
1093 | for (auto it = union_def.Vals().begin(); it != union_def.Vals().end(); |
1094 | ++it) { |
1095 | const auto &ev = **it; |
1096 | |
1097 | auto name = Name(ev); |
1098 | auto type = GenType(ev.union_type); |
1099 | code_.SetValue("KEY" , name); |
1100 | code_.SetValue("VALUETYPE" , type); |
1101 | code_ += "case .{{KEY}}:" ; |
1102 | Indent(); |
1103 | if (ev.union_type.base_type == BASE_TYPE_NONE) { |
1104 | code_ += "break // NOTE - SWIFT doesnt support none" ; |
1105 | } else if (ev.union_type.base_type == BASE_TYPE_STRING) { |
1106 | code_ += |
1107 | "try ForwardOffset<String>.verify(&verifier, at: pos, of: " |
1108 | "String.self)" ; |
1109 | } else { |
1110 | code_.SetValue("MAINTYPE" , ev.union_type.struct_def->fixed |
1111 | ? type |
1112 | : "ForwardOffset<" + type + ">" ); |
1113 | code_ += |
1114 | "try {{MAINTYPE}}.verify(&verifier, at: pos, of: " |
1115 | "{{VALUETYPE}}.self)" ; |
1116 | } |
1117 | Outdent(); |
1118 | } |
1119 | code_ += "}" ; |
1120 | Outdent(); |
1121 | code_ += "})" ; |
1122 | } |
1123 | |
1124 | std::string GenerateVerifierType(const FieldDef &field) { |
1125 | auto type = field.value.type; |
1126 | auto is_vector = IsVector(type) || IsArray(type); |
1127 | |
1128 | if (is_vector) { |
1129 | auto vector_type = field.value.type.VectorType(); |
1130 | return "ForwardOffset<Vector<" + |
1131 | GenerateNestedVerifierTypes(vector_type) + ", " + |
1132 | GenType(vector_type) + ">>" ; |
1133 | } |
1134 | |
1135 | return GenerateNestedVerifierTypes(field.value.type); |
1136 | } |
1137 | |
1138 | std::string GenerateNestedVerifierTypes(const Type &type) { |
1139 | auto string_type = GenType(type); |
1140 | |
1141 | if (IsScalar(type.base_type)) { return string_type; } |
1142 | |
1143 | if (IsString(type)) { return "ForwardOffset<" + string_type + ">" ; } |
1144 | |
1145 | if (type.struct_def && type.struct_def->fixed) { return string_type; } |
1146 | |
1147 | return "ForwardOffset<" + string_type + ">" ; |
1148 | } |
1149 | |
1150 | void GenByKeyFunctions(const FieldDef &key_field) { |
1151 | code_.SetValue("TYPE" , GenType(key_field.value.type)); |
1152 | code_ += |
1153 | "{{ACCESS_TYPE}} func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? " |
1154 | "{ \\" ; |
1155 | code_ += GenOffset() + |
1156 | "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: " |
1157 | "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }" ; |
1158 | } |
1159 | |
1160 | void GenEnum(const EnumDef &enum_def) { |
1161 | if (enum_def.generated) return; |
1162 | auto is_private_access = enum_def.attributes.Lookup("private" ); |
1163 | code_.SetValue("ENUM_TYPE" , |
1164 | enum_def.is_union ? "UnionEnum" : "Enum, Verifiable" ); |
1165 | code_.SetValue("ACCESS_TYPE" , is_private_access ? "internal" : "public" ); |
1166 | code_.SetValue("ENUM_NAME" , NameWrappedInNameSpace(enum_def)); |
1167 | code_.SetValue("BASE_TYPE" , GenTypeBasic(enum_def.underlying_type, false)); |
1168 | GenComment(enum_def.doc_comment); |
1169 | code_ += |
1170 | "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, {{ENUM_TYPE}} {" ; |
1171 | Indent(); |
1172 | code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}" ; |
1173 | if (enum_def.is_union) { |
1174 | code_ += "" ; |
1175 | code_ += "{{ACCESS_TYPE}} init?(value: T) {" ; |
1176 | Indent(); |
1177 | code_ += "self.init(rawValue: value)" ; |
1178 | Outdent(); |
1179 | code_ += "}\n" ; |
1180 | } |
1181 | code_ += |
1182 | "{{ACCESS_TYPE}} static var byteSize: Int { return " |
1183 | "MemoryLayout<{{BASE_TYPE}}>.size " |
1184 | "}" ; |
1185 | code_ += |
1186 | "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }" ; |
1187 | for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { |
1188 | const auto &ev = **it; |
1189 | auto name = Name(ev); |
1190 | code_.SetValue("KEY" , name); |
1191 | code_.SetValue("VALUE" , enum_def.ToString(ev)); |
1192 | GenComment(ev.doc_comment); |
1193 | code_ += "case {{KEY}} = {{VALUE}}" ; |
1194 | } |
1195 | code_ += "" ; |
1196 | AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max" ); |
1197 | AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min" ); |
1198 | Outdent(); |
1199 | code_ += "}\n" ; |
1200 | if (parser_.opts.gen_json_coders) EnumEncoder(enum_def); |
1201 | code_ += "" ; |
1202 | if (parser_.opts.generate_object_based_api && enum_def.is_union) { |
1203 | code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {" ; |
1204 | Indent(); |
1205 | code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}" ; |
1206 | code_ += "{{ACCESS_TYPE}} var value: NativeObject?" ; |
1207 | code_ += |
1208 | "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {" ; |
1209 | Indent(); |
1210 | code_ += "self.type = type" ; |
1211 | code_ += "self.value = v" ; |
1212 | Outdent(); |
1213 | code_ += "}" ; |
1214 | code_ += |
1215 | "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> " |
1216 | "Offset {" ; |
1217 | Indent(); |
1218 | BuildUnionEnumSwitchCaseWritter(enum_def); |
1219 | Outdent(); |
1220 | code_ += "}" ; |
1221 | Outdent(); |
1222 | code_ += "}" ; |
1223 | } |
1224 | } |
1225 | |
1226 | void EnumEncoder(const EnumDef &enum_def) { |
1227 | code_ += "extension {{ENUM_NAME}}: Encodable {" ; |
1228 | Indent(); |
1229 | code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {" ; |
1230 | Indent(); |
1231 | code_ += "var container = encoder.singleValueContainer()" ; |
1232 | code_ += "switch self {" ; |
1233 | for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { |
1234 | const auto &ev = **it; |
1235 | auto name = Name(ev); |
1236 | code_.SetValue("KEY" , name); |
1237 | code_.SetValue("RAWKEY" , ev.name); |
1238 | code_ += "case .{{KEY}}: try container.encode(\"{{RAWKEY}}\")" ; |
1239 | } |
1240 | code_ += "}" ; |
1241 | Outdent(); |
1242 | code_ += "}" ; |
1243 | Outdent(); |
1244 | code_ += "}" ; |
1245 | } |
1246 | |
1247 | // MARK: - Object API |
1248 | |
1249 | void (std::string name) { |
1250 | code_ += "\n" ; |
1251 | code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + name + " {" ; |
1252 | Indent(); |
1253 | code_ += "return " + name + "(&self)" ; |
1254 | Outdent(); |
1255 | code_ += "}" ; |
1256 | code_ += |
1257 | "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, " |
1258 | "obj: " |
1259 | "inout " + |
1260 | name + "?) -> Offset {" ; |
1261 | Indent(); |
1262 | code_ += "guard var obj = obj else { return Offset() }" ; |
1263 | code_ += "return pack(&builder, obj: &obj)" ; |
1264 | Outdent(); |
1265 | code_ += "}" ; |
1266 | code_ += "" ; |
1267 | code_ += |
1268 | "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, " |
1269 | "obj: " |
1270 | "inout " + |
1271 | name + ") -> Offset {" ; |
1272 | Indent(); |
1273 | } |
1274 | |
1275 | void GenerateObjectAPIStructConstructor(const StructDef &struct_def) { |
1276 | code_ += |
1277 | "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {" ; |
1278 | Indent(); |
1279 | for (auto it = struct_def.fields.vec.begin(); |
1280 | it != struct_def.fields.vec.end(); ++it) { |
1281 | auto &field = **it; |
1282 | if (field.deprecated) continue; |
1283 | |
1284 | auto name = Name(field); |
1285 | auto type = GenType(field.value.type); |
1286 | code_.SetValue("VALUENAME" , name); |
1287 | if (IsStruct(field.value.type)) { |
1288 | code_ += "var _v{{VALUENAME}} = _t.{{VALUENAME}}" ; |
1289 | code_ += "_{{VALUENAME}} = _v{{VALUENAME}}.unpack()" ; |
1290 | continue; |
1291 | } |
1292 | std::string is_enum = IsEnum(field.value.type) ? ".value" : "" ; |
1293 | code_ += "_{{VALUENAME}} = _t.{{VALUENAME}}" + is_enum; |
1294 | } |
1295 | Outdent(); |
1296 | code_ += "}\n" ; |
1297 | } |
1298 | |
1299 | void GenObjectAPI(const StructDef &struct_def) { |
1300 | code_ += "{{ACCESS_TYPE}} class " + ObjectAPIName("{{STRUCTNAME}}" ) + |
1301 | ": NativeObject {\n" ; |
1302 | std::vector<std::string> buffer_constructor; |
1303 | std::vector<std::string> base_constructor; |
1304 | Indent(); |
1305 | for (auto it = struct_def.fields.vec.begin(); |
1306 | it != struct_def.fields.vec.end(); ++it) { |
1307 | auto &field = **it; |
1308 | if (field.deprecated) continue; |
1309 | BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor, |
1310 | base_constructor); |
1311 | } |
1312 | code_ += "" ; |
1313 | BuildObjectConstructor(buffer_constructor, |
1314 | "_ _t: inout " + NameWrappedInNameSpace(struct_def)); |
1315 | BuildObjectConstructor(base_constructor); |
1316 | if (!struct_def.fixed) |
1317 | code_ += |
1318 | "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return " |
1319 | "serialize(type: " |
1320 | "{{STRUCTNAME}}.self) }\n" ; |
1321 | Outdent(); |
1322 | code_ += "}" ; |
1323 | } |
1324 | |
1325 | void GenerateObjectAPITableExtension(const StructDef &struct_def) { |
1326 | GenerateObjectAPIExtensionHeader(ObjectAPIName("{{STRUCTNAME}}" )); |
1327 | std::vector<std::string> unpack_body; |
1328 | std::string builder = ", &builder)" ; |
1329 | for (auto it = struct_def.fields.vec.begin(); |
1330 | it != struct_def.fields.vec.end(); ++it) { |
1331 | auto &field = **it; |
1332 | if (field.deprecated) continue; |
1333 | auto name = Name(field); |
1334 | auto type = GenType(field.value.type); |
1335 | std::string check_if_vector = |
1336 | (IsVector(field.value.type) || IsArray(field.value.type)) |
1337 | ? "VectorOf(" |
1338 | : "(" ; |
1339 | std::string body = "add" + check_if_vector + name + ": " ; |
1340 | switch (field.value.type.base_type) { |
1341 | case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); |
1342 | case BASE_TYPE_VECTOR: { |
1343 | GenerateVectorObjectAPITableExtension(field, name, type); |
1344 | unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name + |
1345 | builder); |
1346 | break; |
1347 | } |
1348 | case BASE_TYPE_UNION: { |
1349 | code_ += "let __" + name + " = obj." + name + |
1350 | "?.pack(builder: &builder) ?? Offset()" ; |
1351 | unpack_body.push_back("if let o = obj." + name + "?.type {" ); |
1352 | unpack_body.push_back(" {{STRUCTNAME}}.add(" + name + "Type: o" + |
1353 | builder); |
1354 | unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + name + |
1355 | builder); |
1356 | unpack_body.push_back("}\n" ); |
1357 | break; |
1358 | } |
1359 | case BASE_TYPE_STRUCT: { |
1360 | if (field.value.type.struct_def && |
1361 | field.value.type.struct_def->fixed) { |
1362 | // This is a Struct (IsStruct), not a table. We create |
1363 | // a native swift object in this case. |
1364 | std::string code; |
1365 | GenerateStructArgs(*field.value.type.struct_def, &code, "" , "" , |
1366 | "$0" , true); |
1367 | code = code.substr(0, code.size() - 2); |
1368 | unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name + |
1369 | builder); |
1370 | } else { |
1371 | code_ += "let __" + name + " = " + type + |
1372 | ".pack(&builder, obj: &obj." + name + ")" ; |
1373 | unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name + |
1374 | builder); |
1375 | } |
1376 | break; |
1377 | } |
1378 | case BASE_TYPE_STRING: { |
1379 | unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name + |
1380 | builder); |
1381 | if (field.IsRequired()) { |
1382 | code_ += |
1383 | "let __" + name + " = builder.create(string: obj." + name + ")" ; |
1384 | } else { |
1385 | BuildingOptionalObjects(name, "builder.create(string: s)" ); |
1386 | } |
1387 | break; |
1388 | } |
1389 | case BASE_TYPE_UTYPE: break; |
1390 | default: |
1391 | unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name + |
1392 | builder); |
1393 | } |
1394 | } |
1395 | code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)" ; |
1396 | for (auto it = unpack_body.begin(); it < unpack_body.end(); it++) |
1397 | code_ += *it; |
1398 | code_ += |
1399 | "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: " |
1400 | "__root)" ; |
1401 | Outdent(); |
1402 | code_ += "}" ; |
1403 | } |
1404 | |
1405 | void GenerateVectorObjectAPITableExtension(const FieldDef &field, |
1406 | const std::string &name, |
1407 | const std::string &type) { |
1408 | auto vectortype = field.value.type.VectorType(); |
1409 | switch (vectortype.base_type) { |
1410 | case BASE_TYPE_UNION: { |
1411 | code_ += "var __" + name + "__: [Offset] = []" ; |
1412 | code_ += "for i in obj." + name + " {" ; |
1413 | Indent(); |
1414 | code_ += "guard let off = i?.pack(builder: &builder) else { continue }" ; |
1415 | code_ += "__" + name + "__.append(off)" ; |
1416 | Outdent(); |
1417 | code_ += "}" ; |
1418 | code_ += "let __" + name + " = builder.createVector(ofOffsets: __" + |
1419 | name + "__)" ; |
1420 | code_ += "let __" + name + "Type = builder.createVector(obj." + name + |
1421 | ".compactMap { $0?.type })" ; |
1422 | break; |
1423 | } |
1424 | case BASE_TYPE_UTYPE: break; |
1425 | case BASE_TYPE_STRUCT: { |
1426 | if (field.value.type.struct_def && |
1427 | !field.value.type.struct_def->fixed) { |
1428 | code_ += "var __" + name + "__: [Offset] = []" ; |
1429 | code_ += "for var i in obj." + name + " {" ; |
1430 | Indent(); |
1431 | code_ += |
1432 | "__" + name + "__.append(" + type + ".pack(&builder, obj: &i))" ; |
1433 | Outdent(); |
1434 | code_ += "}" ; |
1435 | code_ += "let __" + name + " = builder.createVector(ofOffsets: __" + |
1436 | name + "__)" ; |
1437 | } else { |
1438 | code_ += "{{STRUCTNAME}}.startVectorOf" + MakeCamel(name, true) + |
1439 | "(obj." + name + ".count, in: &builder)" ; |
1440 | std::string code; |
1441 | GenerateStructArgs(*field.value.type.struct_def, &code, "" , "" , "_o" , |
1442 | true); |
1443 | code = code.substr(0, code.size() - 2); |
1444 | code_ += "for i in obj." + name + " {" ; |
1445 | Indent(); |
1446 | code_ += "guard let _o = i else { continue }" ; |
1447 | code_ += "builder.create(struct: _o)" ; |
1448 | Outdent(); |
1449 | code_ += "}" ; |
1450 | code_ += "let __" + name + " = builder.endVector(len: obj." + name + |
1451 | ".count)" ; |
1452 | } |
1453 | break; |
1454 | } |
1455 | case BASE_TYPE_STRING: { |
1456 | code_ += "let __" + name + " = builder.createVector(ofStrings: obj." + |
1457 | name + ".compactMap({ $0 }) )" ; |
1458 | break; |
1459 | } |
1460 | default: { |
1461 | code_ += "let __" + name + " = builder.createVector(obj." + name + ")" ; |
1462 | break; |
1463 | } |
1464 | } |
1465 | } |
1466 | |
1467 | void BuildingOptionalObjects(const std::string &name, |
1468 | const std::string &body_front) { |
1469 | code_ += "let __" + name + ": Offset" ; |
1470 | code_ += "if let s = obj." + name + " {" ; |
1471 | Indent(); |
1472 | code_ += "__" + name + " = " + body_front; |
1473 | Outdent(); |
1474 | code_ += "} else {" ; |
1475 | Indent(); |
1476 | code_ += "__" + name + " = Offset()" ; |
1477 | Outdent(); |
1478 | code_ += "}" ; |
1479 | code_ += "" ; |
1480 | } |
1481 | |
1482 | void BuildObjectConstructor(const std::vector<std::string> &body, |
1483 | const std::string & = "" ) { |
1484 | code_.SetValue("HEADER" , header); |
1485 | code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {" ; |
1486 | Indent(); |
1487 | for (auto it = body.begin(); it < body.end(); ++it) code_ += *it; |
1488 | Outdent(); |
1489 | code_ += "}\n" ; |
1490 | } |
1491 | |
1492 | void BuildObjectAPIConstructorBody( |
1493 | const FieldDef &field, bool is_fixed, |
1494 | std::vector<std::string> &buffer_constructor, |
1495 | std::vector<std::string> &base_constructor) { |
1496 | auto name = Name(field); |
1497 | auto type = GenType(field.value.type); |
1498 | code_.SetValue("VALUENAME" , name); |
1499 | code_.SetValue("VALUETYPE" , type); |
1500 | std::string is_required = field.IsRequired() ? "" : "?" ; |
1501 | |
1502 | switch (field.value.type.base_type) { |
1503 | case BASE_TYPE_STRUCT: { |
1504 | type = GenType(field.value.type, true); |
1505 | code_.SetValue("VALUETYPE" , type); |
1506 | auto optional = |
1507 | (field.value.type.struct_def && field.value.type.struct_def->fixed); |
1508 | std::string question_mark = |
1509 | (field.IsRequired() || (optional && is_fixed) ? "" : "?" ); |
1510 | |
1511 | code_ += |
1512 | "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark; |
1513 | base_constructor.push_back("" + name + " = " + type + "()" ); |
1514 | |
1515 | if (field.value.type.struct_def->fixed) { |
1516 | buffer_constructor.push_back("" + name + " = _t." + name); |
1517 | } else { |
1518 | buffer_constructor.push_back("var __" + name + " = _t." + name); |
1519 | buffer_constructor.push_back( |
1520 | "" + name + " = __" + name + |
1521 | (field.IsRequired() ? "!" : question_mark) + ".unpack()" ); |
1522 | } |
1523 | break; |
1524 | } |
1525 | case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); |
1526 | case BASE_TYPE_VECTOR: { |
1527 | BuildObjectAPIConstructorBodyVectors(field, name, buffer_constructor, |
1528 | base_constructor, " " ); |
1529 | break; |
1530 | } |
1531 | case BASE_TYPE_STRING: { |
1532 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required; |
1533 | buffer_constructor.push_back(name + " = _t." + name); |
1534 | |
1535 | if (field.IsRequired()) { |
1536 | std::string default_value = |
1537 | field.IsDefault() ? field.value.constant : "" ; |
1538 | base_constructor.push_back(name + " = \"" + default_value + "\"" ); |
1539 | break; |
1540 | } |
1541 | if (field.IsDefault() && !field.IsRequired()) { |
1542 | std::string value = field.IsDefault() ? field.value.constant : "nil" ; |
1543 | base_constructor.push_back(name + " = \"" + value + "\"" ); |
1544 | } |
1545 | break; |
1546 | } |
1547 | case BASE_TYPE_UTYPE: break; |
1548 | case BASE_TYPE_UNION: { |
1549 | BuildUnionEnumSwitchCase(*field.value.type.enum_def, name, |
1550 | buffer_constructor); |
1551 | break; |
1552 | } |
1553 | default: { |
1554 | buffer_constructor.push_back(name + " = _t." + name); |
1555 | std::string nullable = field.IsOptional() ? "?" : "" ; |
1556 | if (IsScalar(field.value.type.base_type) && |
1557 | !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) { |
1558 | code_ += |
1559 | "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + nullable; |
1560 | if (!field.IsOptional()) |
1561 | base_constructor.push_back(name + " = " + field.value.constant); |
1562 | break; |
1563 | } |
1564 | |
1565 | if (IsEnum(field.value.type)) { |
1566 | auto default_value = IsEnum(field.value.type) |
1567 | ? GenEnumDefaultValue(field) |
1568 | : field.value.constant; |
1569 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" ; |
1570 | base_constructor.push_back(name + " = " + default_value); |
1571 | break; |
1572 | } |
1573 | |
1574 | if (IsBool(field.value.type.base_type)) { |
1575 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable; |
1576 | std::string default_value = |
1577 | "0" == field.value.constant ? "false" : "true" ; |
1578 | if (!field.IsOptional()) |
1579 | base_constructor.push_back(name + " = " + default_value); |
1580 | } |
1581 | } |
1582 | } |
1583 | } |
1584 | |
1585 | void BuildObjectAPIConstructorBodyVectors( |
1586 | const FieldDef &field, const std::string &name, |
1587 | std::vector<std::string> &buffer_constructor, |
1588 | std::vector<std::string> &base_constructor, |
1589 | const std::string &indentation) { |
1590 | auto vectortype = field.value.type.VectorType(); |
1591 | |
1592 | if (vectortype.base_type != BASE_TYPE_UTYPE) { |
1593 | buffer_constructor.push_back(name + " = []" ); |
1594 | buffer_constructor.push_back("for index in 0..<_t." + name + "Count {" ); |
1595 | base_constructor.push_back(name + " = []" ); |
1596 | } |
1597 | |
1598 | switch (vectortype.base_type) { |
1599 | case BASE_TYPE_STRUCT: { |
1600 | code_.SetValue("VALUETYPE" , GenType(vectortype, true)); |
1601 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]" ; |
1602 | if (!vectortype.struct_def->fixed) { |
1603 | buffer_constructor.push_back(indentation + "var __v_ = _t." + name + |
1604 | "(at: index)" ); |
1605 | buffer_constructor.push_back(indentation + name + |
1606 | ".append(__v_?.unpack())" ); |
1607 | } else { |
1608 | buffer_constructor.push_back(indentation + name + ".append(_t." + |
1609 | name + "(at: index))" ); |
1610 | } |
1611 | break; |
1612 | } |
1613 | case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); |
1614 | case BASE_TYPE_VECTOR: { |
1615 | break; |
1616 | } |
1617 | case BASE_TYPE_UNION: { |
1618 | BuildUnionEnumSwitchCase(*field.value.type.enum_def, name, |
1619 | buffer_constructor, indentation, true); |
1620 | break; |
1621 | } |
1622 | case BASE_TYPE_UTYPE: break; |
1623 | default: { |
1624 | code_.SetValue( |
1625 | "VALUETYPE" , |
1626 | (IsString(vectortype) ? "String?" : GenType(vectortype))); |
1627 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]" ; |
1628 | |
1629 | if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) { |
1630 | auto default_value = IsEnum(field.value.type) |
1631 | ? GenEnumDefaultValue(field) |
1632 | : field.value.constant; |
1633 | buffer_constructor.push_back(indentation + name + ".append(_t." + |
1634 | name + "(at: index)!)" ); |
1635 | break; |
1636 | } |
1637 | buffer_constructor.push_back(indentation + name + ".append(_t." + name + |
1638 | "(at: index))" ); |
1639 | break; |
1640 | } |
1641 | } |
1642 | if (vectortype.base_type != BASE_TYPE_UTYPE) |
1643 | buffer_constructor.push_back("}" ); |
1644 | } |
1645 | |
1646 | void BuildUnionEnumSwitchCaseWritter(const EnumDef &ev) { |
1647 | auto field_name = Name(ev); |
1648 | code_.SetValue("VALUETYPE" , field_name); |
1649 | code_ += "switch type {" ; |
1650 | for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) { |
1651 | auto field = **it; |
1652 | auto ev_name = Name(field); |
1653 | auto type = GenType(field.union_type); |
1654 | auto is_struct = IsStruct(field.union_type) ? type + Mutable() : type; |
1655 | if (field.union_type.base_type == BASE_TYPE_NONE) { continue; } |
1656 | code_ += "case ." + ev_name + ":" ; |
1657 | Indent(); |
1658 | code_ += "var __obj = value as? " + GenType(field.union_type, true); |
1659 | code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)" ; |
1660 | Outdent(); |
1661 | } |
1662 | code_ += "default: return Offset()" ; |
1663 | code_ += "}" ; |
1664 | } |
1665 | |
1666 | void BuildUnionEnumSwitchCase(const EnumDef &ev, const std::string &name, |
1667 | std::vector<std::string> &buffer_constructor, |
1668 | const std::string &indentation = "" , |
1669 | const bool is_vector = false) { |
1670 | auto field_name = NameWrappedInNameSpace(ev); |
1671 | code_.SetValue("VALUETYPE" , field_name); |
1672 | code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: \\" ; |
1673 | code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?" ; |
1674 | |
1675 | auto vector_reader = is_vector ? "(at: index" : "" ; |
1676 | buffer_constructor.push_back(indentation + "switch _t." + name + "Type" + |
1677 | vector_reader + (is_vector ? ")" : "" ) + " {" ); |
1678 | |
1679 | for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) { |
1680 | auto field = **it; |
1681 | auto ev_name = Name(field); |
1682 | if (field.union_type.base_type == BASE_TYPE_NONE) { continue; } |
1683 | auto type = IsStruct(field.union_type) |
1684 | ? GenType(field.union_type) + Mutable() |
1685 | : GenType(field.union_type); |
1686 | buffer_constructor.push_back(indentation + "case ." + ev_name + ":" ); |
1687 | buffer_constructor.push_back( |
1688 | indentation + " var _v = _t." + name + (is_vector ? "" : "(" ) + |
1689 | vector_reader + (is_vector ? ", " : "" ) + "type: " + type + ".self)" ); |
1690 | auto constructor = |
1691 | field_name + "Union(_v?.unpack(), type: ." + ev_name + ")" ; |
1692 | buffer_constructor.push_back( |
1693 | indentation + " " + name + |
1694 | (is_vector ? ".append(" + constructor + ")" : " = " + constructor)); |
1695 | } |
1696 | buffer_constructor.push_back(indentation + "default: break" ); |
1697 | buffer_constructor.push_back(indentation + "}" ); |
1698 | } |
1699 | |
1700 | void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) { |
1701 | auto current_value = str; |
1702 | code_.SetValue(type, current_value); |
1703 | code_ += "{{ACCESS_TYPE}} static var " + type + |
1704 | ": {{ENUM_NAME}} { return .{{" + type + "}} }" ; |
1705 | } |
1706 | |
1707 | void GenLookup(const FieldDef &key_field) { |
1708 | code_.SetValue("OFFSET" , NumToString(key_field.value.offset)); |
1709 | std::string offset_reader = |
1710 | "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, " |
1711 | "fbb: fbb)" ; |
1712 | |
1713 | code_.SetValue("TYPE" , GenType(key_field.value.type)); |
1714 | code_ += |
1715 | "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, " |
1716 | "fbb: " |
1717 | "ByteBuffer) -> {{VALUENAME}}? {" ; |
1718 | Indent(); |
1719 | if (IsString(key_field.value.type)) |
1720 | code_ += "let key = key.utf8.map { $0 }" ; |
1721 | code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))" ; |
1722 | code_ += "var start: Int32 = 0" ; |
1723 | code_ += "while span != 0 {" ; |
1724 | Indent(); |
1725 | code_ += "var middle = span / 2" ; |
1726 | code_ += |
1727 | "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)" ; |
1728 | if (IsString(key_field.value.type)) { |
1729 | code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)" ; |
1730 | } else { |
1731 | code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" + |
1732 | offset_reader + "))" ; |
1733 | } |
1734 | |
1735 | code_ += "if comp > 0 {" ; |
1736 | Indent(); |
1737 | code_ += "span = middle" ; |
1738 | Outdent(); |
1739 | code_ += "} else if comp < 0 {" ; |
1740 | Indent(); |
1741 | code_ += "middle += 1" ; |
1742 | code_ += "start += middle" ; |
1743 | code_ += "span -= middle" ; |
1744 | Outdent(); |
1745 | code_ += "} else {" ; |
1746 | Indent(); |
1747 | code_ += "return {{VALUENAME}}(fbb, o: tableOffset)" ; |
1748 | Outdent(); |
1749 | code_ += "}" ; |
1750 | Outdent(); |
1751 | code_ += "}" ; |
1752 | code_ += "return nil" ; |
1753 | Outdent(); |
1754 | code_ += "}" ; |
1755 | } |
1756 | |
1757 | inline void GenPadding(const FieldDef &field, int *id) { |
1758 | if (field.padding) { |
1759 | for (int i = 0; i < 4; i++) { |
1760 | if (static_cast<int>(field.padding) & (1 << i)) { |
1761 | auto bits = (1 << i) * 8; |
1762 | code_ += "private let padding" + NumToString((*id)++) + "__: UInt" + |
1763 | NumToString(bits) + " = 0" ; |
1764 | } |
1765 | } |
1766 | FLATBUFFERS_ASSERT(!(field.padding & ~0xF)); |
1767 | } |
1768 | } |
1769 | |
1770 | void (const std::vector<std::string> &dc) { |
1771 | if (dc.begin() == dc.end()) { |
1772 | // Don't output empty comment blocks with 0 lines of comment content. |
1773 | return; |
1774 | } |
1775 | for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; } |
1776 | } |
1777 | |
1778 | std::string GenOffset() { |
1779 | return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); " ; |
1780 | } |
1781 | |
1782 | std::string GenReaderMainBody(const std::string &optional = "" ) { |
1783 | return "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + optional + |
1784 | " { " ; |
1785 | } |
1786 | |
1787 | std::string GenReader(const std::string &type, |
1788 | const std::string &at = "{{OFFSET}}" ) { |
1789 | return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")" ; |
1790 | } |
1791 | |
1792 | std::string GenConstructor(const std::string &offset) { |
1793 | return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }" ; |
1794 | } |
1795 | |
1796 | std::string GenMutate(const std::string &offset, |
1797 | const std::string &get_offset, bool isRaw = false) { |
1798 | return "@discardableResult {{ACCESS_TYPE}} func mutate({{VALUENAME}}: " |
1799 | "{{VALUETYPE}}) -> Bool {" + |
1800 | get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" + |
1801 | (isRaw ? ".rawValue" : "" ) + ", index: " + offset + ") }" ; |
1802 | } |
1803 | |
1804 | std::string GenMutateArray() { |
1805 | return "{{ACCESS_TYPE}} func mutate({{VALUENAME}}: {{VALUETYPE}}, at " |
1806 | "index: " |
1807 | "Int32) -> Bool { " + |
1808 | GenOffset() + |
1809 | "return {{ACCESS}}.directMutate({{VALUENAME}}, index: " |
1810 | "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }" ; |
1811 | } |
1812 | |
1813 | std::string GenEnumDefaultValue(const FieldDef &field) { |
1814 | auto &value = field.value; |
1815 | FLATBUFFERS_ASSERT(value.type.enum_def); |
1816 | auto &enum_def = *value.type.enum_def; |
1817 | // Vector of enum defaults are always "[]" which never works. |
1818 | const std::string constant = IsVector(value.type) ? "0" : value.constant; |
1819 | auto enum_val = enum_def.FindByValue(constant); |
1820 | std::string name; |
1821 | if (enum_val) { |
1822 | name = Name(*enum_val); |
1823 | } else { |
1824 | const auto &ev = **enum_def.Vals().begin(); |
1825 | name = Name(ev); |
1826 | } |
1827 | return "." + name; |
1828 | } |
1829 | |
1830 | std::string GenEnumConstructor(const std::string &at) { |
1831 | return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE" , at) + ") " ; |
1832 | } |
1833 | |
1834 | std::string ValidateFunc() { |
1835 | return "static func validateVersion() { FlatBuffersVersion_2_0_0() }" ; |
1836 | } |
1837 | |
1838 | std::string GenType(const Type &type, |
1839 | const bool should_consider_suffix = false) const { |
1840 | return IsScalar(type.base_type) |
1841 | ? GenTypeBasic(type) |
1842 | : (IsArray(type) ? GenType(type.VectorType()) |
1843 | : GenTypePointer(type, should_consider_suffix)); |
1844 | } |
1845 | |
1846 | std::string GenTypePointer(const Type &type, |
1847 | const bool should_consider_suffix) const { |
1848 | switch (type.base_type) { |
1849 | case BASE_TYPE_STRING: return "String" ; |
1850 | case BASE_TYPE_VECTOR: return GenType(type.VectorType()); |
1851 | case BASE_TYPE_STRUCT: { |
1852 | auto &struct_ = *type.struct_def; |
1853 | if (should_consider_suffix && !struct_.fixed) { |
1854 | return WrapInNameSpace(struct_.defined_namespace, |
1855 | ObjectAPIName(Name(struct_))); |
1856 | } |
1857 | return WrapInNameSpace(struct_.defined_namespace, Name(struct_)); |
1858 | } |
1859 | case BASE_TYPE_UNION: |
1860 | default: return "FlatbuffersInitializable" ; |
1861 | } |
1862 | } |
1863 | |
1864 | std::string GenTypeBasic(const Type &type) const { |
1865 | return GenTypeBasic(type, true); |
1866 | } |
1867 | |
1868 | std::string ObjectAPIName(const std::string &name) const { |
1869 | return parser_.opts.object_prefix + name + parser_.opts.object_suffix; |
1870 | } |
1871 | |
1872 | void Indent() { code_.IncrementIdentLevel(); } |
1873 | |
1874 | void Outdent() { code_.DecrementIdentLevel(); } |
1875 | |
1876 | std::string NameWrappedInNameSpace(const EnumDef &enum_def) const { |
1877 | return WrapInNameSpace(enum_def.defined_namespace, Name(enum_def)); |
1878 | } |
1879 | |
1880 | std::string NameWrappedInNameSpace(const StructDef &struct_def) const { |
1881 | return WrapInNameSpace(struct_def.defined_namespace, Name(struct_def)); |
1882 | } |
1883 | |
1884 | std::string GenTypeBasic(const Type &type, bool can_override) const { |
1885 | // clang-format off |
1886 | static const char * const swift_type[] = { |
1887 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ |
1888 | CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \ |
1889 | #STYPE, |
1890 | FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) |
1891 | #undef FLATBUFFERS_TD |
1892 | }; |
1893 | // clang-format on |
1894 | if (can_override) { |
1895 | if (type.enum_def) return NameWrappedInNameSpace(*type.enum_def); |
1896 | if (type.base_type == BASE_TYPE_BOOL) return "Bool" ; |
1897 | } |
1898 | return swift_type[static_cast<int>(type.base_type)]; |
1899 | } |
1900 | |
1901 | std::string EscapeKeyword(const std::string &name) const { |
1902 | return keywords_.find(name) == keywords_.end() ? name : name + "_" ; |
1903 | } |
1904 | |
1905 | std::string Mutable() const { return "_Mutable" ; } |
1906 | |
1907 | std::string Name(const EnumVal &ev) const { |
1908 | auto name = ev.name; |
1909 | if (isupper(name.front())) { |
1910 | std::transform(name.begin(), name.end(), name.begin(), CharToLower); |
1911 | } |
1912 | return EscapeKeyword(MakeCamel(name, false)); |
1913 | } |
1914 | |
1915 | std::string Name(const Definition &def) const { |
1916 | return EscapeKeyword(MakeCamel(def.name, false)); |
1917 | } |
1918 | }; |
1919 | } // namespace swift |
1920 | bool GenerateSwift(const Parser &parser, const std::string &path, |
1921 | const std::string &file_name) { |
1922 | swift::SwiftGenerator generator(parser, path, file_name); |
1923 | return generator.generate(); |
1924 | } |
1925 | } // namespace flatbuffers |
1926 | |