diff --git a/docs/source/SwiftUsage.md b/docs/source/SwiftUsage.md index fb8b1fd9b..d5640f6c9 100644 --- a/docs/source/SwiftUsage.md +++ b/docs/source/SwiftUsage.md @@ -23,11 +23,9 @@ GitHub page](https://github.com/google/flatbuffers/tree/master/swift). ## Testing the FlatBuffers Swift library The code to test the Swift library can be found at `flatbuffers/Flatbuffers.Test.Swift`. -The test code itself is located in [Flatbuffers.Test.Swift](https://github.com/google/ -flatbuffers/blob/master/tests/FlatBuffers.Test.Swift). +The test code itself is located in [Flatbuffers.Test.Swift](https://github.com/google/flatbuffers/blob/master/tests/FlatBuffers.Test.Swift). -To run the tests, use the [SwiftTest.sh](https://github.com/google/flatbuffers/ -blob/master/tests/FlatBuffers.Test.Swift/SwiftTest.sh) shell script. +To run the tests, use the [SwiftTest.sh](https://github.com/google/flatbuffers/blob/master/tests/FlatBuffers.Test.Swift/SwiftTest.sh) shell script. *Note: The shell script requires [Swift](https://swift.org) to be installed.* diff --git a/src/idl_gen_swift.cpp b/src/idl_gen_swift.cpp index 03ac2f217..b5225cf20 100644 --- a/src/idl_gen_swift.cpp +++ b/src/idl_gen_swift.cpp @@ -37,8 +37,85 @@ class SwiftGenerator : public BaseGenerator { 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, + "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); } @@ -160,6 +237,7 @@ class SwiftGenerator : public BaseGenerator { } 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"); @@ -357,7 +435,7 @@ class SwiftGenerator : public BaseGenerator { 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 + @@ -534,6 +612,7 @@ class SwiftGenerator : public BaseGenerator { 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") + " }"; @@ -555,9 +634,10 @@ class SwiftGenerator : public BaseGenerator { void GenEnum(const EnumDef &enum_def) { if (enum_def.generated) return; - code_.SetValue("ENUM_NAME", GenEnumDecl(enum_def)); + code_.SetValue("ENUM_NAME", Name(enum_def)); code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); - code_ += "public {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { "; + 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 " @@ -565,23 +645,30 @@ class SwiftGenerator : public BaseGenerator { "}"; 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_.SetValue("KEY", name); + code_.SetValue("VALUE", enum_def.ToString(ev)); + GenComment(ev.doc_comment, "\t"); + code_ += "\tcase {{KEY}} = {{VALUE}}"; } - code_ += enum_code.substr(0, enum_code.size() - 2); + 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 = @@ -629,6 +716,12 @@ class SwiftGenerator : public BaseGenerator { code_ += "\t}"; } + void GenComment(const std::vector &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 = "") { @@ -723,10 +816,6 @@ class SwiftGenerator : public BaseGenerator { return swift_type[static_cast(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 + "_"; } diff --git a/swift/Sources/FlatBuffers/ByteBuffer.swift b/swift/Sources/FlatBuffers/ByteBuffer.swift index b596ce46f..cbe3cd057 100644 --- a/swift/Sources/FlatBuffers/ByteBuffer.swift +++ b/swift/Sources/FlatBuffers/ByteBuffer.swift @@ -231,13 +231,14 @@ public final class ByteBuffer { public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer { return ByteBuffer(memory: _memory, count: _capacity, removing: _writerSize - removeBytes) } - - #if DEBUG - func debugMemory(str: String) { - let bufprt = UnsafeBufferPointer(start: _memory.assumingMemoryBound(to: UInt8.self), - count: _capacity) - let a = Array(bufprt) - print(str, a, " \nwith buffer size: \(a.count) and writer size: \(_writerSize)") - } - #endif +} + +extension ByteBuffer: CustomDebugStringConvertible { + + public var debugDescription: String { + """ + buffer located at: \(_memory), with capacity of \(_capacity) + { writerSize: \(_writerSize), readerSize: \(reader), writerIndex: \(writerIndex) } + """ + } } diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 023f37641..9a4ed3d0e 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -77,11 +77,8 @@ public final class FlatBufferBuilder { public func clearOffsets() { _vtable = [] } -} - -// MARK: - Create Tables - -extension FlatBufferBuilder { + + // MARK: - Create Tables /// Checks if the required fields were serialized into the buffer /// - Parameters: @@ -476,11 +473,16 @@ extension FlatBufferBuilder { _bb.push(value: element, len: MemoryLayout.size) return _bb.size } - - #if DEBUG - /// Used to debug the buffer and the implementation - public func debug(str: String = "normal memory: ") { - _bb.debugMemory(str: str) - } - #endif +} + +extension FlatBufferBuilder: CustomDebugStringConvertible { + + public var debugDescription: String { + """ + buffer debug: + \(_bb) + builder debug: + { finished: \(finished), serializeDefaults: \(serializeDefaults), isNested: \(isNested) } + """ + } } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift index faafdf075..fe317d472 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/monster_test_generated.swift @@ -5,39 +5,77 @@ import FlatBuffers public enum MyGame { public enum Example { +/// Composite components of Monster color. public enum Color: UInt8, Enum { public typealias T = UInt8 public static var byteSize: Int { return MemoryLayout.size } public var value: UInt8 { return self.rawValue } - case red = 1, green = 2, blue = 8 + case red = 1 + /// \brief color Green + /// Green is bit_flag with value (1u << 1) + case green = 2 + /// \brief color Blue (1u << 3) + case blue = 8 + + + public static var max: Color { return .blue } + public static var min: Color { return .red } } public enum Race: Int8, Enum { public typealias T = Int8 public static var byteSize: Int { return MemoryLayout.size } public var value: Int8 { return self.rawValue } - case none = -1, human = 0, dwarf = 1, elf = 2 + case none = -1 + case human = 0 + case dwarf = 1 + case elf = 2 + + + public static var max: Race { return .elf } + public static var min: Race { return .none } } public enum Any_: UInt8, Enum { public typealias T = UInt8 public static var byteSize: Int { return MemoryLayout.size } public var value: UInt8 { return self.rawValue } - case none = 0, monster = 1, testsimpletablewithenum = 2, mygame_example2_monster = 3 + case none = 0 + case monster = 1 + case testsimpletablewithenum = 2 + case mygame_example2_monster = 3 + + + public static var max: Any_ { return .mygame_example2_monster } + public static var min: Any_ { return .none } } public enum AnyUniqueAliases: UInt8, Enum { public typealias T = UInt8 public static var byteSize: Int { return MemoryLayout.size } public var value: UInt8 { return self.rawValue } - case none = 0, m = 1, ts = 2, m2 = 3 + case none = 0 + case m = 1 + case ts = 2 + case m2 = 3 + + + public static var max: AnyUniqueAliases { return .m2 } + public static var min: AnyUniqueAliases { return .none } } public enum AnyAmbiguousAliases: UInt8, Enum { public typealias T = UInt8 public static var byteSize: Int { return MemoryLayout.size } public var value: UInt8 { return self.rawValue } - case none = 0, m1 = 1, m2 = 2, m3 = 3 + case none = 0 + case m1 = 1 + case m2 = 2 + case m3 = 3 + + + public static var max: AnyAmbiguousAliases { return .m3 } + public static var min: AnyAmbiguousAliases { return .none } } public struct Test: Readable { @@ -279,6 +317,7 @@ public struct Referrable: FlatBufferObject { } } +/// an example documentation comment: monster object public struct Monster: FlatBufferObject { static func validateVersion() { FlatBuffersVersion_1_11_1() } @@ -309,6 +348,8 @@ public struct Monster: FlatBufferObject { public func test4(at index: Int32) -> MyGame.Example.Test? { let o = _accessor.offset(22); return o == 0 ? nil : MyGame.Example.Test(_accessor.bb, o: _accessor.vector(at: o) + index * 4) } public var testarrayofstringCount: Int32 { let o = _accessor.offset(24); return o == 0 ? 0 : _accessor.vector(count: o) } public func testarrayofstring(at index: Int32) -> String? { let o = _accessor.offset(24); return o == 0 ? nil : _accessor.directString(at: _accessor.vector(at: o) + index * 4) } + /// an example documentation comment: this will end up in the generated code + /// multiline too public var testarrayoftablesCount: Int32 { let o = _accessor.offset(26); return o == 0 ? 0 : _accessor.vector(count: o) } public func testarrayoftables(at index: Int32) -> MyGame.Example.Monster? { let o = _accessor.offset(26); return o == 0 ? nil : MyGame.Example.Monster(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) } public func testarrayoftablesBy(key: String) -> MyGame.Example.Monster? { let o = _accessor.offset(26); return o == 0 ? nil : MyGame.Example.Monster.lookupByKey(vector: _accessor.vector(at: o), key: key, fbb: _accessor.bb) } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift index fb445ed5d..c901729d0 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/union_vector_generated.swift @@ -6,7 +6,17 @@ public enum Character: UInt8, Enum { public typealias T = UInt8 public static var byteSize: Int { return MemoryLayout.size } public var value: UInt8 { return self.rawValue } - case none = 0, mulan = 1, rapunzel = 2, belle = 3, bookfan = 4, other = 5, unused = 6 + case none = 0 + case mulan = 1 + case rapunzel = 2 + case belle = 3 + case bookfan = 4 + case other = 5 + case unused = 6 + + + public static var max: Character { return .unused } + public static var min: Character { return .none } } public struct Rapunzel: Readable {