mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 20:15:34 +00:00
903 lines
32 KiB
C++
903 lines
32 KiB
C++
/*
|
|
* Copyright 2020 Google Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#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, "", ".", "swift"),
|
|
cur_name_space_(nullptr) {
|
|
namespace_depth = 0;
|
|
static const char *const keywords[] = {
|
|
"associatedtype",
|
|
"class",
|
|
"deinit",
|
|
"enum",
|
|
"extension",
|
|
"fileprivate",
|
|
"func",
|
|
"import",
|
|
"init",
|
|
"inout",
|
|
"internal",
|
|
"let",
|
|
"open",
|
|
"operator",
|
|
"private",
|
|
"protocol",
|
|
"public",
|
|
"rethrows",
|
|
"static",
|
|
"struct",
|
|
"subscript",
|
|
"typealias",
|
|
"var",
|
|
"break",
|
|
"case",
|
|
"continue",
|
|
"default",
|
|
"defer",
|
|
"do",
|
|
"else",
|
|
"fallthrough",
|
|
"for",
|
|
"guard",
|
|
"if",
|
|
"in",
|
|
"repeat",
|
|
"return",
|
|
"switch",
|
|
"where",
|
|
"while",
|
|
"Any",
|
|
"catch",
|
|
"false",
|
|
"is",
|
|
"nil",
|
|
"super",
|
|
"self",
|
|
"Self",
|
|
"throw",
|
|
"throws",
|
|
"true",
|
|
"try",
|
|
"associativity",
|
|
"convenience",
|
|
"dynamic",
|
|
"didSet",
|
|
"final",
|
|
"get",
|
|
"infix",
|
|
"indirect",
|
|
"lazy",
|
|
"left",
|
|
"mutating",
|
|
"none",
|
|
"nonmutating",
|
|
"optional",
|
|
"override",
|
|
"postfix",
|
|
"precedence",
|
|
"prefix",
|
|
"Protocol",
|
|
"required",
|
|
"right",
|
|
"set",
|
|
"Type",
|
|
"unowned",
|
|
"weak",
|
|
"willSet",
|
|
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_, parser_.opts);
|
|
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) {
|
|
GenComment(struct_def.doc_comment);
|
|
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}} {\n";
|
|
code_ += ValidateFunc();
|
|
code_ += "\tpublic var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
|
|
code_ += "\n\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;
|
|
std::vector<std::string> require_fields;
|
|
std::string create_func_body;
|
|
std::string create_func_header;
|
|
auto should_generate_create = struct_def.fields.vec.size() != 0;
|
|
|
|
code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
|
|
code_ +=
|
|
"\tpublic static func start{{STRUCTNAME}}(_ fbb: FlatBufferBuilder) -> "
|
|
"UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
|
|
|
|
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, &create_func_body, &create_func_header,
|
|
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 }";
|
|
|
|
code_ +=
|
|
"\tpublic static func create{{STRUCTNAME}}(_ fbb: FlatBufferBuilder\\";
|
|
if (should_generate_create)
|
|
code_ += ",\n" +
|
|
create_func_header.substr(0, create_func_header.size() - 2) +
|
|
"\\";
|
|
code_ += ") -> Offset<UOffset> {";
|
|
code_ += "\t\tlet __start = {{STRUCTNAME}}.start{{STRUCTNAME}}(fbb)";
|
|
if (should_generate_create)
|
|
code_ += create_func_body.substr(0, create_func_body.size() - 1);
|
|
code_ += "\t\treturn {{STRUCTNAME}}.end{{STRUCTNAME}}(fbb, start: __start)";
|
|
code_ += "\t}";
|
|
|
|
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, std::string *create_body,
|
|
std::string *create_header, const int position) {
|
|
std::string builder_string = ", _ fbb: FlatBufferBuilder) { fbb.add(";
|
|
auto &create_func_body = *create_body;
|
|
auto &create_func_header = *create_header;
|
|
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("
|
|
: "(";
|
|
std::string body = "add" + check_if_vector + name + ": ";
|
|
code_ += "\tpublic static func " + body + "\\";
|
|
|
|
create_func_body += "\t\t{{STRUCTNAME}}." + body + name + ", fbb)\n";
|
|
|
|
if (IsScalar(field.value.type.base_type) &&
|
|
!IsBool(field.value.type.base_type)) {
|
|
auto default_value = IsEnum(field.value.type) ? GenEnumDefaultValue(field)
|
|
: field.value.constant;
|
|
auto is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
|
|
code_ += "{{VALUETYPE}}" + builder_string + "element: {{VALUENAME}}" +
|
|
is_enum + ", def: {{CONSTANT}}, at: {{OFFSET}}) }";
|
|
create_func_header +=
|
|
"\t\t" + name + ": " + type + " = " + default_value + ",\n";
|
|
return;
|
|
}
|
|
|
|
if (IsBool(field.value.type.base_type)) {
|
|
std::string default_value =
|
|
"0" == field.value.constant ? "false" : "true";
|
|
code_.SetValue("VALUETYPE", "Bool");
|
|
code_.SetValue("CONSTANT", default_value);
|
|
code_ += "{{VALUETYPE}}" + builder_string +
|
|
"condition: {{VALUENAME}}, def: {{CONSTANT}}, at: {{OFFSET}}) }";
|
|
create_func_header +=
|
|
"\t\t" + name + ": " + type + " = " + default_value + ",\n";
|
|
return;
|
|
}
|
|
|
|
auto offset_type = field.value.type.base_type == BASE_TYPE_STRING
|
|
? "Offset<String>"
|
|
: "Offset<UOffset>";
|
|
auto camel_case_name =
|
|
(field.value.type.base_type == BASE_TYPE_VECTOR ||
|
|
field.value.type.base_type == BASE_TYPE_ARRAY
|
|
? "vectorOf"
|
|
: "offsetOf") +
|
|
MakeCamel(name, true);
|
|
create_func_header += "\t\t" + camel_case_name + " " + name + ": " +
|
|
offset_type + " = Offset(),\n";
|
|
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}} : ";
|
|
GenComment(field.doc_comment, "\t");
|
|
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 ? {{VALUETYPE}}" + 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);
|
|
GenComment(field.doc_comment, "\t");
|
|
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", Name(enum_def));
|
|
code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
|
|
GenComment(enum_def.doc_comment);
|
|
code_ += "public enum {{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 }";
|
|
|
|
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
|
|
const auto &ev = **it;
|
|
auto name = Name(ev);
|
|
std::transform(name.begin(), name.end(), name.begin(), LowerCase);
|
|
code_.SetValue("KEY", name);
|
|
code_.SetValue("VALUE", enum_def.ToString(ev));
|
|
GenComment(ev.doc_comment, "\t");
|
|
code_ += "\tcase {{KEY}} = {{VALUE}}";
|
|
}
|
|
code_ += "\n";
|
|
AddMinOrMaxEnumValue(enum_def.MaxValue()->name, "max");
|
|
AddMinOrMaxEnumValue(enum_def.MinValue()->name, "min");
|
|
code_ += "}\n";
|
|
}
|
|
|
|
void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
|
|
auto current_value = str;
|
|
std::transform(current_value.begin(), current_value.end(),
|
|
current_value.begin(), LowerCase);
|
|
code_.SetValue(type, current_value);
|
|
code_ += "\tpublic static var " + type + ": {{ENUM_NAME}} { return .{{" +
|
|
type + "}} }";
|
|
}
|
|
|
|
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}";
|
|
}
|
|
|
|
void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
|
|
std::string text;
|
|
::flatbuffers::GenComment(dc, &text, nullptr, prefix);
|
|
code_ += text + "\\";
|
|
}
|
|
|
|
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 "." + name;
|
|
}
|
|
|
|
std::string GenEnumConstructor(const std::string &at) {
|
|
return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
|
|
}
|
|
|
|
std::string ValidateFunc() {
|
|
return "\tstatic func validateVersion() { FlatBuffersVersion_1_12_0() }";
|
|
}
|
|
|
|
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 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));
|
|
}
|
|
|
|
// 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
|