[Swift] Swift implementation 🎉🎉 (#5603)

* Implemented the swift version of Flatbuffers

Implemented serailzing, reading, and mutating data from object monster

Fixes mis-aligned pointer issue

Fixes issue when shared strings are removed from table

Adds swift enum, structs code gen

Fixed namespace issues + started implementing the table gen

Added Mutate function to the code generator

Generated linux test cases

Fixed an issue with bools, and structs readers in table writer

Swift docker image added

Updated the test cases, and removed a method parameters in swift

Fixed createVector api when called with scalars

Fixed issues with scalar arrays, and fixed the code gen namespaces, added sample_binary.swift

Cleaned up project

Added enum vectors, and their readers

Refactored code

Added swift into the support document

Added documentation in docs, and fixed a small issue with Data() not being returned correctly

Fixes Lowercase issue, and prevents generating lookups for deprecated keys

* Made all the required funcs to have const + removed unneeded code + fix lowercase func

* Removed transform from lowercased and moved it to function

* Fixes an issue with iOS allocation from read

* Refactored cpp code to be more readable

* casts position into int for position

* Fix enums issue, moves scalar writer code to use memcpy

* Removed c_str from struct function

* Fixed script to generate new objects when ran on travis ci: fix

* Handles deallocating space allocated for structs

* Updated the test cases to adhere to the fileprivate lookup, no mutation for unions, and updated the names of the vector functions
This commit is contained in:
mustiikhalil
2020-01-09 23:12:10 +03:00
committed by Wouter van Oortmerssen
parent 55686100aa
commit 04d80f255d
41 changed files with 4015 additions and 40 deletions

View File

@@ -56,6 +56,7 @@ cc_library(
"idl_gen_python.cpp",
"idl_gen_rust.cpp",
"idl_gen_text.cpp",
"idl_gen_swift.cpp",
"util.cpp",
],
hdrs = [

View File

@@ -105,6 +105,9 @@ int main(int argc, const char *argv[]) {
{ flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema",
true, nullptr, flatbuffers::IDLOptions::kJsonSchema,
"Generate Json schema", nullptr },
{ flatbuffers::GenerateSwift, nullptr, "--swift", "swift",
true, nullptr, flatbuffers::IDLOptions::kSwift,
"Generate Swift files for tables/structs", nullptr },
};
flatbuffers::FlatCompiler::InitParams params;

View File

@@ -141,7 +141,7 @@ class KotlinGenerator : public BaseGenerator {
// clang-format off
static const char * const kotlin_typename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, ...) \
#KTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD

758
src/idl_gen_swift.cpp Normal file
View File

@@ -0,0 +1,758 @@
#include <unordered_set>
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
namespace swift {
inline std::string GenIndirect(const std::string &reading) {
return "{{ACCESS}}.indirect(" + reading + ")";
}
inline std::string GenArrayMainBody(const std::string &optional) {
return "\tpublic func {{VALUENAME}}(at index: Int32) -> {{VALUETYPE}}" +
optional + " { ";
}
inline char LowerCase(char c) {
return static_cast<char>(::tolower(static_cast<unsigned char>(c)));
}
class SwiftGenerator : public BaseGenerator {
private:
const Namespace *cur_name_space_;
CodeWriter code_;
std::unordered_set<std::string> keywords_;
std::set<std::string> namespaces_;
int namespace_depth;
public:
SwiftGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "", "."),
cur_name_space_(nullptr) {
namespace_depth = 0;
static const char *const keywords[] = {
"enum", "private", "public", "internal", "fileprivate", "static", "var",
"URL", "struct", "let", "class", "Any", "nil", nullptr,
};
for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
}
bool generate() {
code_.Clear();
code_.SetValue("ACCESS", "_accessor");
code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n";
code_ += "import FlatBuffers\n";
// Generate code for all the enum declarations.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
const auto &enum_def = **it;
if (!enum_def.generated) {
SetNameSpace(enum_def.defined_namespace);
GenEnum(enum_def);
}
}
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (struct_def.fixed && !struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenStructReader(struct_def);
}
}
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (struct_def.fixed && !struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenStructWriter(struct_def);
}
}
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (!struct_def.fixed && !struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenTable(struct_def);
}
}
if (cur_name_space_) SetNameSpace(nullptr);
const auto filename = GeneratedFileName(path_, file_name_);
const auto final_code = code_.ToString();
return SaveFile(filename.c_str(), final_code, false);
}
void mark(const std::string &str) {
code_.SetValue("MARKVALUE", str);
code_ += "\n// MARK: - {{MARKVALUE}}\n";
}
// Generates the create function for swift
void GenStructWriter(const StructDef &struct_def) {
code_.SetValue("STRUCTNAME", Name(struct_def));
std::string static_type = this->namespace_depth == 0 ? "" : "static ";
code_ += "public " + static_type + "func create{{STRUCTNAME}}(\\";
std::string func_header = "";
GenerateStructArgs(struct_def, &func_header, "");
code_ += func_header.substr(0, func_header.size() - 2) + "\\";
code_ += ") -> UnsafeMutableRawPointer {";
code_ +=
"\tlet memory = UnsafeMutableRawPointer.allocate(byteCount: "
"{{STRUCTNAME}}.size, alignment: {{STRUCTNAME}}.alignment)";
code_ +=
"\tmemory.initializeMemory(as: UInt8.self, repeating: 0, count: "
"{{STRUCTNAME}}.size)";
GenerateStructBody(struct_def, "");
code_ += "\treturn memory";
code_ += "}\n";
}
void GenerateStructBody(const StructDef &struct_def,
const std::string &nameprefix, int offset = 0) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto name = nameprefix + Name(field);
const auto &field_type = field.value.type;
auto type = GenTypeBasic(field_type, false);
if (IsStruct(field.value.type)) {
GenerateStructBody(*field_type.struct_def, (nameprefix + field.name),
static_cast<int>(field.value.offset));
} else {
auto off = NumToString(offset + field.value.offset);
code_ += "\tmemory.storeBytes(of: " + name +
(field_type.enum_def ? ".rawValue" : "") +
", toByteOffset: " + off + ", as: " + type + ".self)";
}
}
}
void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
const std::string &nameprefix) {
auto &code = *code_ptr;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
const auto &field_type = field.value.type;
if (IsStruct(field.value.type)) {
GenerateStructArgs(*field_type.struct_def, code_ptr,
(nameprefix + field.name));
} else {
auto name = Name(field);
auto type = GenType(field.value.type);
code += nameprefix + name + ": " + type;
code += ", ";
}
}
}
void GenObjectHeader(const StructDef &struct_def) {
code_.SetValue("STRUCTNAME", Name(struct_def));
code_.SetValue("PROTOCOL",
struct_def.fixed ? "Readable" : "FlatBufferObject");
code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
code_ += "public struct {{STRUCTNAME}}: {{PROTOCOL}} {";
code_ += "\tprivate var {{ACCESS}}: {{OBJECTTYPE}}";
if (struct_def.fixed) {
code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize));
code_.SetValue("MINALIGN", NumToString(struct_def.minalign));
code_ += "\tpublic static var size = {{BYTESIZE}}";
code_ += "\tpublic static var alignment = {{MINALIGN}}\t";
} else {
if (parser_.file_identifier_.length()) {
code_.SetValue("FILENAME", parser_.file_identifier_);
code_ +=
"\tpublic static func finish(_ fbb: FlatBufferBuilder, end: "
"Offset<UOffset>, prefix: Bool = false) { fbb.finish(offset: end, "
"fileId: "
"\"{{FILENAME}}\", addPrefix: prefix) }";
}
code_ +=
"\tpublic static func getRootAs{{STRUCTNAME}}(bb: ByteBuffer) -> "
"{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
"Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
"Int32(bb.reader))) }\n";
code_ += "\tprivate init(_ t: Table) { {{ACCESS}} = t }";
}
code_ +=
"\tpublic init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
"{{OBJECTTYPE}}(bb: "
"bb, position: o) }";
code_ += "";
}
// Generates the reader for swift
void GenTable(const StructDef &struct_def) {
GenObjectHeader(struct_def);
GenTableReader(struct_def);
GenTableWriter(struct_def);
code_ += "}\n";
}
void GenTableReader(const StructDef &struct_def) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
GenTableReaderFields(field);
}
}
void GenTableWriter(const StructDef &struct_def) {
flatbuffers::FieldDef *key_field = nullptr;
code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
code_ +=
"\tpublic static func start{{STRUCTNAME}}(_ fbb: FlatBufferBuilder) -> "
"UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
std::vector<std::string> require_fields;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
if (field.key) key_field = &field;
if (field.required)
require_fields.push_back(NumToString(field.value.offset));
GenTableWriterFields(
field, static_cast<int>(it - struct_def.fields.vec.begin()));
}
code_ +=
"\tpublic static func end{{STRUCTNAME}}(_ fbb: FlatBufferBuilder, "
"start: "
"UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(offset: "
"fbb.endTable(at: start))\\";
if (require_fields.capacity() != 0) {
std::string fields = "";
for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
fields += *it + ", ";
code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
}
code_ += "; return end }";
std::string spacing = "\t\t";
if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
code_.SetValue("VALUENAME", struct_def.name);
code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
code_ +=
"\tpublic static func "
"sortVectorOf{{VALUENAME}}(offsets:[Offset<UOffset>], "
"_ fbb: FlatBufferBuilder) -> Offset<UOffset> {";
code_ += spacing + "var off = offsets";
code_ +=
spacing +
"off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
"{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
"{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
code_ += spacing + "return fbb.createVector(ofOffsets: off)";
code_ += "\t}";
GenLookup(*key_field);
}
}
void GenTableWriterFields(const FieldDef &field, const int position) {
std::string builder_string = ", _ fbb: FlatBufferBuilder) { fbb.add(";
auto name = Name(field);
auto type = GenType(field.value.type);
code_.SetValue("VALUENAME", name);
code_.SetValue("VALUETYPE", type);
code_.SetValue("OFFSET", NumToString(position));
code_.SetValue("CONSTANT", field.value.constant);
std::string check_if_vector =
(field.value.type.base_type == BASE_TYPE_VECTOR ||
field.value.type.base_type == BASE_TYPE_ARRAY)
? "VectorOf"
: "";
code_ +=
"\tpublic static func add" + check_if_vector + "({{VALUENAME}}: \\";
if (IsScalar(field.value.type.base_type) &&
!IsBool(field.value.type.base_type)) {
auto is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
code_ += "{{VALUETYPE}}" + builder_string + "element: {{VALUENAME}}" +
is_enum + ", def: {{CONSTANT}}, at: {{OFFSET}}) }";
return;
}
if (IsBool(field.value.type.base_type)) {
code_.SetValue("VALUETYPE", "Bool");
code_.SetValue("CONSTANT",
"0" == field.value.constant ? "false" : "true");
code_ += "{{VALUETYPE}}" + builder_string +
"condition: {{VALUENAME}}, def: {{CONSTANT}}, at: {{OFFSET}}) }";
return;
}
auto offset_type = field.value.type.base_type == BASE_TYPE_STRING
? "Offset<String>"
: "Offset<UOffset>";
auto reader_type =
IsStruct(field.value.type) && field.value.type.struct_def->fixed
? "structOffset: {{OFFSET}}) }"
: "offset: {{VALUENAME}}, at: {{OFFSET}}) }";
code_ += offset_type + builder_string + reader_type;
}
void GenTableReaderFields(const FieldDef &field) {
auto offset = NumToString(field.value.offset);
auto name = Name(field);
auto type = GenType(field.value.type);
code_.SetValue("VALUENAME", name);
code_.SetValue("VALUETYPE", type);
code_.SetValue("OFFSET", offset);
code_.SetValue("CONSTANT", field.value.constant);
std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
!IsBool(field.value.type.base_type)) {
code_ += GenReaderMainBody() + GenOffset() + const_string +
GenReader("VALUETYPE", "o") + " }";
if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
return;
}
if (IsBool(field.value.type.base_type)) {
code_.SetValue("VALUETYPE", "Bool");
code_ += GenReaderMainBody() + "\\";
code_.SetValue("VALUETYPE", "Byte");
code_ += GenOffset() +
"return o == 0 ? false : 0 != " + GenReader("VALUETYPE", "o") +
" }";
if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
return;
}
if (IsEnum(field.value.type)) {
auto default_value = GenEnumDefaultValue(field);
code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
code_ += GenReaderMainBody() + "\\";
code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
GenEnumConstructor("o") + "?? " + default_value + " }";
if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
code_ += GenMutate("o", GenOffset(), true);
return;
}
if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
code_.SetValue("VALUETYPE", GenType(field.value.type));
code_.SetValue("CONSTANT", "nil");
code_ += GenReaderMainBody("?") + GenOffset() + const_string +
GenConstructor("o + {{ACCESS}}.postion");
return;
}
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
code_.SetValue("VALUETYPE", GenType(field.value.type));
code_.SetValue("CONSTANT", "nil");
code_ += GenReaderMainBody("?") + GenOffset() + const_string +
GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
break;
case BASE_TYPE_STRING:
code_.SetValue("VALUETYPE", GenType(field.value.type));
code_.SetValue("CONSTANT", "nil");
code_ += GenReaderMainBody("?") + GenOffset() + const_string +
"{{ACCESS}}.string(at: o) }";
code_ +=
"\tpublic var {{VALUENAME}}SegmentArray: [UInt8]? { return "
"{{ACCESS}}.getVector(at: {{OFFSET}}) }";
break;
case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
case BASE_TYPE_VECTOR:
GenTableReaderVectorFields(field, const_string);
break;
case BASE_TYPE_UNION:
code_.SetValue("CONSTANT", "nil");
code_ +=
"\tpublic func {{VALUENAME}}<T: FlatBufferObject>(type: "
"T.Type) -> T? { " +
GenOffset() + const_string + "{{ACCESS}}.union(o) }";
break;
default: FLATBUFFERS_ASSERT(0);
}
}
void GenTableReaderVectorFields(const FieldDef &field,
const std::string &const_string) {
auto vectortype = field.value.type.VectorType();
code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
code_ += "\tpublic var {{VALUENAME}}Count: Int32 { " + GenOffset() +
const_string + "{{ACCESS}}.vector(count: o) }";
code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) == true
? field.value.constant
: "nil");
auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
nullable = IsEnum(vectortype) == true ? "?" : nullable;
if (vectortype.base_type != BASE_TYPE_UNION) {
code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
} else {
code_ +=
"\tpublic func {{VALUENAME}}<T: FlatBufferObject>(at index: "
"Int32, type: T.Type) -> T? { " +
GenOffset() + "\\";
}
if (IsBool(vectortype.base_type)) {
code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
code_.SetValue("VALUETYPE", "Byte");
}
if (!IsEnum(vectortype))
code_ +=
const_string + (IsBool(vectortype.base_type) ? "0 != " : "") + "\\";
if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
!IsBool(field.value.type.base_type)) {
code_ +=
"{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
"{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
code_ +=
"\tpublic var {{VALUENAME}}: [{{VALUETYPE}}] { return "
"{{ACCESS}}.getVector(at: {{OFFSET}}) ?? [] }";
if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
return;
}
if (vectortype.base_type == BASE_TYPE_STRUCT &&
field.value.type.struct_def->fixed) {
code_ += GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
return;
}
if (vectortype.base_type == BASE_TYPE_STRING) {
code_ +=
"{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
"index * {{SIZE}}) }";
return;
}
if (IsEnum(vectortype)) {
code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
code_ += "return o == 0 ? " + GenEnumDefaultValue(field) +
" : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
"{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
"index * {{SIZE}})) }";
return;
}
if (vectortype.base_type == BASE_TYPE_UNION) {
code_ +=
"{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
"index * {{SIZE}}) }";
return;
}
if (vectortype.base_type == BASE_TYPE_STRUCT &&
!field.value.type.struct_def->fixed) {
code_ += GenConstructor(
"{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
"{{SIZE}})");
auto &sd = *field.value.type.struct_def;
auto &fields = sd.fields.vec;
for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
auto &key_field = **kit;
if (key_field.key) {
GenByKeyFunctions(key_field);
break;
}
}
}
}
void GenByKeyFunctions(const FieldDef &key_field) {
code_.SetValue("TYPE", GenType(key_field.value.type));
code_ +=
"\tpublic func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? { \\";
code_ += GenOffset() +
"return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
"{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
}
// Generates the reader for swift
void GenStructReader(const StructDef &struct_def) {
GenObjectHeader(struct_def);
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto offset = NumToString(field.value.offset);
auto name = Name(field);
auto type = GenType(field.value.type);
code_.SetValue("VALUENAME", name);
code_.SetValue("VALUETYPE", type);
code_.SetValue("OFFSET", offset);
if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
code_ +=
GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
if (parser_.opts.mutable_buffer) code_ += GenMutate("{{OFFSET}}", "");
} else if (IsEnum(field.value.type)) {
code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
code_ += GenReaderMainBody() + "return " +
GenEnumConstructor("{{OFFSET}}") + "?? " +
GenEnumDefaultValue(field) + " }";
} else if (IsStruct(field.value.type)) {
code_.SetValue("VALUETYPE", GenType(field.value.type));
code_ += GenReaderMainBody() + "return " +
GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
}
}
code_ += "}\n";
}
void GenEnum(const EnumDef &enum_def) {
if (enum_def.generated) return;
code_.SetValue("ENUM_NAME", GenEnumDecl(enum_def));
code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
code_ += "public {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { ";
code_ += "\tpublic typealias T = {{BASE_TYPE}}";
code_ +=
"\tpublic static var byteSize: Int { return "
"MemoryLayout<{{BASE_TYPE}}>.size "
"}";
code_ += "\tpublic var value: {{BASE_TYPE}} { return self.rawValue }";
std::string enum_code = "\tcase ";
int keyCount = 0;
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
const auto &ev = **it;
auto key = "KEY" + NumToString(keyCount);
auto value = "VALUE" + NumToString(keyCount);
auto name = Name(ev);
std::transform(name.begin(), name.end(), name.begin(), LowerCase);
code_.SetValue(key, name);
code_.SetValue(value, enum_def.ToString(ev));
enum_code += "{{" + key + "}} = {{" + value + "}}, ";
keyCount++;
}
code_ += enum_code.substr(0, enum_code.size() - 2);
code_ += "}\n";
}
void GenLookup(const FieldDef &key_field) {
code_.SetValue("OFFSET", NumToString(key_field.value.offset));
auto offset_reader =
"Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
"fbb: fbb)";
std::string spacing = "\t\t";
std::string double_spacing = spacing + "\t";
code_.SetValue("TYPE", GenType(key_field.value.type));
code_ +=
"\tfileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
"fbb: "
"ByteBuffer) -> {{VALUENAME}}? {";
if (key_field.value.type.base_type == BASE_TYPE_STRING)
code_ += spacing + "let key = key.utf8.map { $0 }";
code_ += spacing +
"var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
code_ += spacing + "var start: Int32 = 0";
code_ += spacing + "while span != 0 {";
code_ += double_spacing + "var middle = span / 2";
code_ +=
double_spacing +
"let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
if (key_field.value.type.base_type == BASE_TYPE_STRING) {
code_ += double_spacing + "let comp = Table.compare(" + offset_reader +
", key, fbb: fbb)";
} else {
code_ += double_spacing +
"let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
offset_reader + "))";
}
code_ += double_spacing + "if comp > 0 {";
code_ += double_spacing + "\tspan = middle";
code_ += double_spacing + "} else if comp < 0 {";
code_ += double_spacing + "\tmiddle += 1";
code_ += double_spacing + "\tstart += middle";
code_ += double_spacing + "\tspan -= middle";
code_ += double_spacing + "} else {";
code_ += double_spacing + "\treturn {{VALUENAME}}(fbb, o: tableOffset)";
code_ += double_spacing + "}";
code_ += spacing + "}";
code_ += spacing + "return nil";
code_ += "\t}";
}
std::string GenOffset() { return "let o = {{ACCESS}}.offset({{OFFSET}}); "; }
std::string GenReaderMainBody(const std::string &optional = "") {
return "\tpublic var {{VALUENAME}}: {{VALUETYPE}}" + optional + " { ";
}
std::string GenReader(const std::string &type,
const std::string &at = "{{OFFSET}}") {
return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
}
std::string GenConstructor(const std::string &offset) {
return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
}
std::string GenMutate(const std::string &offset,
const std::string &get_offset, bool isRaw = false) {
return "\tpublic func mutate({{VALUENAME}}: {{VALUETYPE}}) -> Bool {" +
get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
(isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
}
std::string GenMutateArray() {
return "\tpublic func mutate({{VALUENAME}}: {{VALUETYPE}}, at index: "
"Int32) -> Bool { " +
GenOffset() +
"return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
"{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
}
std::string GenEnumDefaultValue(const FieldDef &field) {
auto &value = field.value;
FLATBUFFERS_ASSERT(value.type.enum_def);
auto &enum_def = *value.type.enum_def;
auto enum_val = enum_def.FindByValue(value.constant);
std::string name;
if (enum_val) {
name = enum_val->name;
} else {
const auto &ev = **enum_def.Vals().begin();
name = ev.name;
}
std::transform(name.begin(), name.end(), name.begin(), LowerCase);
return "{{VALUETYPE}}." + name;
}
std::string GenEnumConstructor(const std::string &at) {
return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
}
std::string GenType(const Type &type) const {
return IsScalar(type.base_type)
? GenTypeBasic(type)
: (IsArray(type) ? GenType(type.VectorType())
: GenTypePointer(type));
}
std::string GenTypePointer(const Type &type) const {
switch (type.base_type) {
case BASE_TYPE_STRING: return "String";
case BASE_TYPE_VECTOR: return GenType(type.VectorType());
case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
case BASE_TYPE_UNION:
default: return "FlatBufferObject";
}
}
std::string GenTypeBasic(const Type &type) const {
return GenTypeBasic(type, true);
}
std::string GenTypeBasic(const Type &type, bool can_override) const {
// clang-format off
static const char * const swift_type[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
#STYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
// clang-format on
if (can_override) {
if (type.enum_def)
return WrapInNameSpace(type.enum_def->defined_namespace,
Name(*type.enum_def));
if (type.base_type == BASE_TYPE_BOOL) return "Bool";
}
return swift_type[static_cast<int>(type.base_type)];
}
std::string GenEnumDecl(const EnumDef &enum_def) const {
return "enum " + Name(enum_def);
}
std::string EscapeKeyword(const std::string &name) const {
return keywords_.find(name) == keywords_.end() ? name : name + "_";
}
std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
std::string Name(const Definition &def) const {
return EscapeKeyword(MakeCamel(def.name, false));
}
static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) {
return path + file_name + "_generated.swift";
}
// MARK: - Copied from the cpp implementation, needs revisiting
void SetNameSpace(const Namespace *ns) {
if (cur_name_space_ == ns) { return; }
// Compute the size of the longest common namespace prefix.
// If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
// the common prefix is A::B:: and we have old_size = 4, new_size = 5
// and common_prefix_size = 2
size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
size_t new_size = ns ? ns->components.size() : 0;
size_t common_prefix_size = 0;
while (common_prefix_size < old_size && common_prefix_size < new_size &&
ns->components[common_prefix_size] ==
cur_name_space_->components[common_prefix_size]) {
common_prefix_size++;
}
// Close cur_name_space in reverse order to reach the common prefix.
// In the previous example, D then C are closed.
for (size_t j = old_size; j > common_prefix_size; --j) {
if (namespace_depth != 0) {
code_ += "}";
namespace_depth -= 1;
}
mark(cur_name_space_->components[j - 1]);
}
if (old_size != common_prefix_size) { code_ += ""; }
// open namespace parts to reach the ns namespace
// in the previous example, E, then F, then G are opened
bool is_extension = false;
for (auto j = common_prefix_size; j < new_size; ++j) {
std::string name = ns->components[j];
if (namespaces_.find(name) == namespaces_.end()) {
code_ += "public enum " + name + " {";
namespace_depth += 1;
namespaces_.insert(name);
} else {
code_ += "}";
is_extension = true;
}
}
if (is_extension) {
code_.SetValue("EXTENSION", FullNamespace(".", *ns));
code_ += "extension {{EXTENSION}} {";
}
if (new_size != common_prefix_size) { code_ += ""; }
cur_name_space_ = ns;
}
};
} // namespace swift
bool GenerateSwift(const Parser &parser, const std::string &path,
const std::string &file_name) {
swift::SwiftGenerator generator(parser, path, file_name);
return generator.generate();
}
} // namespace flatbuffers

View File

@@ -2195,7 +2195,8 @@ bool Parser::SupportsAdvancedUnionFeatures() const {
(opts.lang_to_generate &
~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs |
IDLOptions::kPhp | IDLOptions::kJava | IDLOptions::kCSharp |
IDLOptions::kKotlin | IDLOptions::kBinary)) == 0;
IDLOptions::kKotlin | IDLOptions::kBinary | IDLOptions::kSwift)) ==
0;
}
bool Parser::SupportsAdvancedArrayFeatures() const {