├── .gitignore ├── Package.swift ├── README.md ├── Sources ├── FlatBuffersSwiftCodeGen │ └── main.swift └── FlatBuffersSwiftCodeGenCore │ ├── ASTNode.swift │ ├── Comment.swift │ ├── Enum.swift │ ├── Field.swift │ ├── Ident.swift │ ├── MetaData.swift │ ├── Schema.swift │ ├── StringLiteral.swift │ ├── StructGen.swift │ ├── Table.swift │ ├── TableGen.swift │ ├── Type.swift │ ├── Union.swift │ └── ValueLiteral.swift ├── Tests ├── FlatBuffersSwiftCodeGenTests │ ├── ASTNodeTests.swift │ ├── CommentTests.swift │ ├── EnumTests.swift │ ├── FieldTests.swift │ ├── IdentTests.swift │ ├── MetaDataTests.swift │ ├── SchemaTests.swift │ ├── StringLiteralTests.swift │ ├── StructGenTest.swift │ ├── TableGenTests.swift │ ├── TableTests.swift │ ├── TypeTests.swift │ ├── UnionTests.swift │ ├── ValueLiteralTests.swift │ └── XCTestManifests.swift └── LinuxMain.swift ├── azure-pipelines.yml ├── fbsCG └── release.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "FlatBuffersSwiftCodeGen", 8 | dependencies: [ 9 | ], 10 | targets: [ 11 | .target( 12 | name: "FlatBuffersSwiftCodeGenCore", 13 | dependencies: []), 14 | .target( 15 | name: "FlatBuffersSwiftCodeGen", 16 | dependencies: ["FlatBuffersSwiftCodeGenCore"]), 17 | .testTarget( 18 | name: "FlatBuffersSwiftCodeGenTests", 19 | dependencies: ["FlatBuffersSwiftCodeGenCore"] 20 | ) 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlatBuffersSwiftCodeGen 2 | 3 | FlatBuffersSwiftCodeGen is a code generator for FlatBuffersSwift (https://github.com/mzaks/FlatBuffersSwift) 4 | 5 | ## Arguments description: 6 | - First argument is the path to `.fbs` file 7 | - Second argument is the path to `.swift` file you want to generate 8 | - Third argument is optional, it can be `download` which will avoid `import FlatBuffersSwift` statement in generated file and download _FlatBuffersSwift_ infrastructure files. Or you can tell the generator to just avoid `import FlatBuffersSwift` statement by writing `noImport` as third argument 9 | 10 | ## Example usage: 11 | `fbsCG contacts.fbs contacts.swift` 12 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGen/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import FlatBuffersSwiftCodeGenCore 11 | 12 | if CommandLine.arguments.count < 2 { 13 | print("⚠️ Please provide path to .fbs file as first argument") 14 | exit(1) 15 | } 16 | 17 | let fbsPath = CommandLine.arguments[1] 18 | let fbsUrl = URL(fileURLWithPath: fbsPath) 19 | 20 | guard let fileContent = try?Data(contentsOf: fbsUrl) else { 21 | print("⚠️ Could not read content of the .fbs file \(fbsUrl)") 22 | exit(1) 23 | } 24 | 25 | 26 | 27 | if CommandLine.arguments.count < 3 { 28 | print("⚠️ Please provide path to .swift file (which you want to generate) as second argument") 29 | exit(1) 30 | } 31 | 32 | let swiftPath = CommandLine.arguments[2] 33 | let swiftUrl = URL(fileURLWithPath: swiftPath) 34 | 35 | print("Generating: \(fbsPath) -> \(swiftPath)") 36 | 37 | 38 | 39 | let schema = fileContent.withUnsafeBytes { (p: UnsafePointer) -> Schema? in 40 | return Schema.with(pointer: p, length: fileContent.count)?.0 41 | } 42 | 43 | let withoutImport = CommandLine.arguments.count > 3 44 | && (CommandLine.arguments[3] == "download" || CommandLine.arguments[3] == "noImport") 45 | 46 | if let swiftFileContent = schema?.swift(withImport: !withoutImport) { 47 | try!swiftFileContent.data(using: .utf8)?.write(to: swiftUrl) 48 | print("✅ Completed") 49 | } else { 50 | print("❌ Could not generate") 51 | } 52 | 53 | if CommandLine.arguments.count > 3 54 | && CommandLine.arguments[3] == "download" { 55 | print("🕐 Downloading FlatBuffersBuilder") 56 | let builderData = try Data(contentsOf: URL(string: "https://raw.githubusercontent.com/mzaks/FlatBuffersSwift/1.0.1/FlatBuffersSwift/FlatBuffersBuilder.swift")!) 57 | try!builderData.write(to: swiftUrl.deletingLastPathComponent().appendingPathComponent("FlatBuffersBuilder.swift")) 58 | print("✅ Completed") 59 | print("🕐 Downloading FlatBuffersReader") 60 | let readerData = try Data(contentsOf: URL(string: "https://raw.githubusercontent.com/mzaks/FlatBuffersSwift/1.0.1/FlatBuffersSwift/FlatBuffersReader.swift")!) 61 | try!readerData.write(to: swiftUrl.deletingLastPathComponent().appendingPathComponent("FlatBuffersReader.swift")) 62 | print("✅ Completed") 63 | } 64 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/ASTNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ASTNode.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ASTNode { 12 | static func with(pointer: UnsafePointer, length: Int) -> (Self, UnsafePointer)? 13 | } 14 | 15 | public func eat(_ s: StaticString, from p: UnsafePointer, length: Int) -> UnsafePointer? { 16 | guard let p1 = eatWhiteSpace(p, length: length) else {return nil} 17 | let count = s.utf8CodeUnitCount 18 | guard count + p.distance(to: p1) <= length else {return nil} 19 | for i in 0 ..< count { 20 | if s.utf8Start.advanced(by: i).pointee != p1.advanced(by: i).pointee { 21 | return nil 22 | } 23 | } 24 | return p1.advanced(by: count) 25 | } 26 | 27 | public func eatWhiteSpace(_ p: UnsafePointer, length: Int) -> UnsafePointer? { 28 | var p1 = p 29 | while p1.pointee < 33 { 30 | p1 = p1.advanced(by: 1) 31 | if p.distance(to: p1) > length { 32 | return nil 33 | } 34 | } 35 | return p1 36 | } 37 | 38 | public func parserError(_ p: UnsafePointer, length: Int) -> Never { 39 | guard let value = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: p), length: length, encoding: .utf8, freeWhenDone: false) else { 40 | fatalError("Parser error unknown") 41 | } 42 | fatalError("parser error after: \(value)") 43 | } 44 | 45 | let A_Z = (UInt8(65)...90) 46 | let a_z = (UInt8(97)...122) 47 | let _0_9 = (UInt8(48)...57) 48 | let __ = UInt8(95) 49 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Comment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comment.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 30.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Comment { 12 | let value: String 13 | } 14 | 15 | extension Comment: ASTNode { 16 | static func with(pointer: UnsafePointer, length: Int) -> (Comment, UnsafePointer)? { 17 | guard let p1 = eat("//", from: pointer, length: length) else {return nil} 18 | var p2 = p1 19 | while p2.pointee != UInt8(10) 20 | && p2.pointee != UInt8(13) 21 | && p2.pointee != UInt8(0) 22 | && p1.distance(to: p2) < length { 23 | p2 = p2.advanced(by: 1) 24 | } 25 | guard let value = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: p1), length: p1.distance(to: p2), encoding: .utf8, freeWhenDone: false) else { 26 | return nil 27 | } 28 | return (Comment(value: value), p2) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Enum.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Enum.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 18.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct EnumCase { 12 | let ident: Ident 13 | let value: ValueLiteral? 14 | } 15 | 16 | extension EnumCase: ASTNode { 17 | static func with(pointer: UnsafePointer, length: Int) -> (EnumCase, UnsafePointer)? { 18 | guard let (name, p1) = Ident.with(pointer: pointer, length: length) else {return nil} 19 | var length = length - pointer.distance(to: p1) 20 | if let p2 = eat("=", from: p1, length: length) { 21 | length -= p1.distance(to: p2) 22 | if let r = ValueLiteral.with(pointer: p2, length: length) { 23 | return (EnumCase(ident: name, value: r.0), r.1) 24 | } else { 25 | return nil 26 | } 27 | } 28 | return (EnumCase(ident: name, value: nil), p1) 29 | } 30 | } 31 | 32 | struct Enum { 33 | let name: Ident 34 | let type: Type 35 | let cases: [EnumCase] 36 | let metaData: MetaData? 37 | let comments: [Comment] 38 | } 39 | 40 | extension Enum: ASTNode { 41 | static func with(pointer: UnsafePointer, length: Int) -> (Enum, UnsafePointer)? { 42 | var p0 = pointer 43 | var length = length 44 | var comments = [Comment]() 45 | while let r = Comment.with(pointer: p0, length: length) { 46 | comments.append(r.0) 47 | length -= p0.distance(to: r.1) 48 | p0 = r.1 49 | } 50 | guard let p1 = eat("enum", from: p0, length: length) else {return nil} 51 | length = length - p0.distance(to: p1) 52 | guard let (name, p2) = Ident.with(pointer: p1, length: length) else {return nil} 53 | length -= p1.distance(to: p2) 54 | guard let p2_01 = eat(":", from: p2, length: length) else {return nil} 55 | length = length - p2.distance(to: p2_01) 56 | guard let (type, p2_02) = Type.with(pointer: p2_01, length: length) else {return nil} 57 | length = length - p2_01.distance(to: p2_02) 58 | var p2_1 = p2_02 59 | var metaData: MetaData? = nil 60 | if let r = MetaData.with(pointer: p2_1, length: length) { 61 | metaData = r.0 62 | length -= p2_1.distance(to: r.1) 63 | p2_1 = r.1 64 | } 65 | guard let p3 = eat("{", from: p2_1, length: length) else {return nil} 66 | length -= p2_1.distance(to: p3) 67 | var cases = [EnumCase]() 68 | var p4 = p3 69 | while let (_case, _p4) = EnumCase.with(pointer: p4, length: length) { 70 | cases.append(_case) 71 | length -= p4.distance(to: _p4) 72 | p4 = _p4 73 | guard let _p5 = eat(",", from: p4, length: length) else {break} 74 | length -= p4.distance(to: _p5) 75 | p4 = _p5 76 | } 77 | guard let p5 = eat("}", from: p4, length: length) else {return nil} 78 | return (Enum(name: name, type: type, cases: cases, metaData: metaData, comments: comments), p5) 79 | } 80 | } 81 | 82 | extension Enum { 83 | var swift: String { 84 | if type.vector {fatalError("enum \(name.value) type cannot be a vector")} 85 | if type.string {fatalError("enum \(name.value) type cannot be a string")} 86 | if type.ref != nil {fatalError("enum \(name.value) type cannot be \(type.ref!.value)")} 87 | if type.scalar == .bool {fatalError("enum \(name.value) type cannot be bool")} 88 | if type.scalar == .f32 {fatalError("enum \(name.value) type cannot be float")} 89 | if type.scalar == .f64 {fatalError("enum \(name.value) type cannot be double")} 90 | if cases.isEmpty {fatalError("enum \(name.value) does not have cases")} 91 | if let v = cases[0].value, v.value != "0" {fatalError("enum \(name.value) first case is not 0")} 92 | func gen(_ cases: [EnumCase]) -> String{ 93 | let result: [String] = cases.map { 94 | var s = $0.ident.value 95 | if let v = $0.value { 96 | s = "\(s) = \(v.value)" 97 | } 98 | return s 99 | } 100 | return result.joined(separator: ", ") 101 | } 102 | return """ 103 | public enum \(self.name.value): \(type.swift), FlatBuffersEnum { 104 | case \(gen(cases)) 105 | public static func fromScalar(_ scalar: T) -> \(self.name.value)? where T : Scalar { 106 | guard let value = scalar as? RawValue else { 107 | return nil 108 | } 109 | return \(self.name.value)(rawValue: value) 110 | } 111 | } 112 | """ 113 | } 114 | 115 | func genFromJsonValue() -> String { 116 | func genCases(_ cases: [EnumCase]) -> String { 117 | var statements = [String]() 118 | for c in cases { 119 | statements.append(""" 120 | if string == "\(c.ident.value)" { 121 | return .\(c.ident.value) 122 | } 123 | """) 124 | } 125 | 126 | return statements.joined(separator: "\n") 127 | } 128 | return """ 129 | extension \(name.value) { 130 | static func from(jsonValue: Any?) -> \(name.value)? { 131 | if let string = jsonValue as? String { 132 | \(genCases(cases)) 133 | } 134 | if let int = jsonValue as? Int, 135 | let rawValue = \(type.scalar?.swift ?? "Int8")(exactly: int) { 136 | return \(name.value).init(rawValue: rawValue) 137 | } 138 | return nil 139 | } 140 | } 141 | """ 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Field.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Field.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Field { 12 | let name: Ident 13 | let type: Type 14 | let defaultValue: ValueLiteral? 15 | let defaultIdent: Ident? 16 | let metaData: MetaData? 17 | } 18 | 19 | extension Field: ASTNode { 20 | static func with(pointer p: UnsafePointer, length: Int) -> (Field, UnsafePointer)? { 21 | var p0 = p 22 | var length = length 23 | var comments = [Comment]() 24 | while let r = Comment.with(pointer: p0, length: length) { 25 | comments.append(r.0) 26 | length -= p0.distance(to: r.1) 27 | p0 = r.1 28 | } 29 | guard let (name, p1) = Ident.with(pointer: p0, length: length) else {return nil} 30 | length = length - p0.distance(to: p1) 31 | guard let p2 = eat(":", from: p1, length: length) else {return nil} 32 | length -= p1.distance(to: p2) 33 | guard let (type, p3) = Type.with(pointer: p2, length: length) else {return nil} 34 | length -= p2.distance(to: p3) 35 | var p5 = p3 36 | var defaultValue: ValueLiteral? = nil 37 | var defaultIdent: Ident? = nil 38 | if let p4 = eat("=", from: p3, length: length) { 39 | length -= p3.distance(to: p4) 40 | if let r = ValueLiteral.with(pointer: p4, length: length) { 41 | defaultValue = r.0 42 | p5 = r.1 43 | } else if let r = Ident.with(pointer: p4, length: length) { 44 | defaultIdent = r.0 45 | p5 = r.1 46 | } else { 47 | return nil 48 | } 49 | length -= p4.distance(to:p5) 50 | } 51 | var p6 = p5 52 | var metaData: MetaData? = nil 53 | if let r = MetaData.with(pointer: p6, length: length) { 54 | metaData = r.0 55 | length -= p6.distance(to: r.1) 56 | p6 = r.1 57 | } 58 | guard let p7 = eat(";", from: p6, length: length) else {return nil} 59 | return (Field(name: name, type: type, defaultValue: defaultValue, defaultIdent: defaultIdent, metaData: metaData), p7) 60 | } 61 | } 62 | 63 | extension Field { 64 | var id: String? { 65 | let idMeta = metaData?.values.first { (arg0) -> Bool in 66 | let (ident, _) = arg0 67 | return ident.value == "id" 68 | } 69 | return idMeta?.1?.value 70 | } 71 | var isDeprecated: Bool { 72 | let deprecatedMetaData = metaData?.values.first { (arg0) -> Bool in 73 | let (ident, _) = arg0 74 | return ident.value == "deprecated" 75 | } 76 | return deprecatedMetaData != nil 77 | } 78 | var fieldName: String { 79 | return isDeprecated ? "__\(name.value)" : name.value 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Ident.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Ident.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Ident { 12 | let value: String 13 | } 14 | 15 | extension Ident: ASTNode { 16 | static func with(pointer p: UnsafePointer, length: Int) -> (Ident, UnsafePointer)? { 17 | guard let p1 = eatWhiteSpace(p, length: length) else {return nil} 18 | guard A_Z.contains(p1.pointee) || a_z.contains(p1.pointee) || __ == p1.pointee else { 19 | return nil 20 | } 21 | var p2 = p1 22 | while A_Z.contains(p2.pointee) 23 | || a_z.contains(p2.pointee) 24 | || _0_9.contains(p2.pointee) 25 | || __ == p2.pointee { 26 | p2 = p2.advanced(by: 1) 27 | } 28 | guard let value = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: p1), length: p1.distance(to: p2), encoding: .utf8, freeWhenDone: false) else { 29 | return nil 30 | } 31 | return (Ident(value: value), p2) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/MetaData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MetaData.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 17.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct MetaData { 12 | let values: [(Ident, ValueLiteral?)] 13 | } 14 | 15 | extension MetaData: ASTNode { 16 | static func with(pointer: UnsafePointer, length: Int) -> (MetaData, UnsafePointer)? { 17 | guard let p1 = eat("(", from: pointer, length: length) else {return nil} 18 | var length = length - pointer.distance(to: p1) 19 | var values = [(Ident, ValueLiteral?)]() 20 | var p2 = p1 21 | while let (name, _p2) = Ident.with(pointer: p2, length: length) { 22 | length -= p2.distance(to: _p2) 23 | p2 = _p2 24 | var value : ValueLiteral? 25 | if let _p3 = eat(":", from: p2, length: length) { 26 | length -= p2.distance(to: _p3) 27 | p2 = _p3 28 | if let (_value, _p4) = ValueLiteral.with(pointer: p2, length: length) { 29 | value = _value 30 | length -= p2.distance(to: _p4) 31 | p2 = _p4 32 | } 33 | } 34 | values.append((name, value)) 35 | guard let _p5 = eat(",", from: p2, length: length) else {break} 36 | length -= p2.distance(to: _p5) 37 | p2 = _p5 38 | } 39 | 40 | if values.isEmpty { 41 | return nil 42 | } 43 | 44 | guard let p3 = eat(")", from: p2, length: length) else {return nil} 45 | 46 | return (MetaData(values: values), p3) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Schema.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Schema.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 19.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Include { 12 | let path: StringLiteral 13 | } 14 | extension Include: ASTNode { 15 | static func with(pointer: UnsafePointer, length: Int) -> (Include, UnsafePointer)? { 16 | guard let r = parse("include", pointer: pointer, length: length) else { 17 | return nil 18 | } 19 | return (Include(path: r.0), r.1) 20 | } 21 | } 22 | 23 | struct Attribute { 24 | let value: StringLiteral 25 | } 26 | extension Attribute: ASTNode { 27 | static func with(pointer: UnsafePointer, length: Int) -> (Attribute, UnsafePointer)? { 28 | guard let r = parse("attribute", pointer: pointer, length: length) else { 29 | return nil 30 | } 31 | return (Attribute(value: r.0), r.1) 32 | } 33 | } 34 | 35 | struct FileExtension { 36 | let value: StringLiteral 37 | } 38 | extension FileExtension: ASTNode { 39 | static func with(pointer: UnsafePointer, length: Int) -> (FileExtension, UnsafePointer)? { 40 | guard let r = parse("file_extension", pointer: pointer, length: length) else { 41 | return nil 42 | } 43 | return (FileExtension(value: r.0), r.1) 44 | } 45 | } 46 | 47 | struct FileIdent { 48 | let value: StringLiteral 49 | } 50 | extension FileIdent: ASTNode { 51 | static func with(pointer: UnsafePointer, length: Int) -> (FileIdent, UnsafePointer)? { 52 | guard let r = parse("file_identifier", pointer: pointer, length: length) else { 53 | return nil 54 | } 55 | return (FileIdent(value: r.0), r.1) 56 | } 57 | } 58 | 59 | fileprivate func parse(_ prefix: StaticString, pointer: UnsafePointer, length: Int) -> (StringLiteral, UnsafePointer)? { 60 | var p0 = pointer 61 | var length = length 62 | var comments = [Comment]() 63 | while let r = Comment.with(pointer: p0, length: length) { 64 | comments.append(r.0) 65 | length -= p0.distance(to: r.1) 66 | p0 = r.1 67 | } 68 | guard let p1 = eat(prefix, from: p0, length: length) else {return nil} 69 | length = length - p0.distance(to: p1) 70 | guard let (value, p2) = StringLiteral.with(pointer: p1, length: length) else {return nil} 71 | length -= p1.distance(to: p2) 72 | guard let p3 = eat(";", from: p2, length: length) else {return nil} 73 | return (value, p3) 74 | } 75 | 76 | struct Namespace { 77 | let parts: [Ident] 78 | } 79 | extension Namespace: ASTNode { 80 | static func with(pointer: UnsafePointer, length: Int) -> (Namespace, UnsafePointer)? { 81 | var p0 = pointer 82 | var length = length 83 | var comments = [Comment]() 84 | while let r = Comment.with(pointer: p0, length: length) { 85 | comments.append(r.0) 86 | length -= p0.distance(to: r.1) 87 | p0 = r.1 88 | } 89 | guard let p1 = eat("namespace", from: p0, length: length) else {return nil} 90 | length = length - p0.distance(to: p1) 91 | var p2 = p1 92 | var parts = [Ident]() 93 | while let (part, _p2) = Ident.with(pointer: p2, length: length) { 94 | length -= p2.distance(to: _p2) 95 | parts.append(part) 96 | p2 = _p2 97 | guard let _p3 = eat(".", from: p2, length: length) else {break} 98 | length -= p2.distance(to: _p3) 99 | p2 = _p3 100 | } 101 | guard let p3 = eat(";", from: p2, length: length) else {return nil} 102 | return (Namespace(parts: parts), p3) 103 | } 104 | } 105 | 106 | struct RootType { 107 | let ident: Ident 108 | } 109 | extension RootType: ASTNode { 110 | static func with(pointer: UnsafePointer, length: Int) -> (RootType, UnsafePointer)? { 111 | var p0 = pointer 112 | var length = length 113 | var comments = [Comment]() 114 | while let r = Comment.with(pointer: p0, length: length) { 115 | comments.append(r.0) 116 | length -= p0.distance(to: r.1) 117 | p0 = r.1 118 | } 119 | guard let p1 = eat("root_type", from: p0, length: length) else {return nil} 120 | length = length - p0.distance(to: p1) 121 | guard let (ident, p2) = Ident.with(pointer: p1, length: length) else {return nil} 122 | length -= p1.distance(to: p2) 123 | guard let p3 = eat(";", from: p2, length: length) else {return nil} 124 | return (RootType(ident: ident), p3) 125 | } 126 | } 127 | 128 | public struct Schema { 129 | let includes: [Include] 130 | let namespace: Namespace? 131 | let rootType: RootType? 132 | let fileIdent: FileIdent? 133 | let fileExtansion: FileExtension? 134 | let attributes: [Attribute] 135 | let tables: [Table] 136 | let structs: [Struct] 137 | let enums: [Enum] 138 | let unions: [Union] 139 | } 140 | 141 | extension Schema: ASTNode { 142 | public static func with(pointer: UnsafePointer, length: Int) -> (Schema, UnsafePointer)? { 143 | var includes: [Include] = [] 144 | var namespace: Namespace? 145 | var rootType: RootType? 146 | var fileIdent: FileIdent? 147 | var fileExtension: FileExtension? 148 | var attributes: [Attribute] = [] 149 | var tables: [Table] = [] 150 | var structs: [Struct] = [] 151 | var enums: [Enum] = [] 152 | var unions: [Union] = [] 153 | 154 | var p1 = pointer 155 | var length = length 156 | while(true) { 157 | if let r = Include.with(pointer: p1, length: length) { 158 | length -= p1.distance(to: r.1) 159 | includes.append(r.0) 160 | p1 = r.1 161 | continue 162 | } 163 | if let r = Namespace.with(pointer: p1, length: length) { 164 | length -= p1.distance(to: r.1) 165 | guard namespace == nil else {return nil} 166 | namespace = r.0 167 | p1 = r.1 168 | continue 169 | } 170 | if let r = RootType.with(pointer: p1, length: length) { 171 | length -= p1.distance(to: r.1) 172 | guard rootType == nil else {return nil} 173 | rootType = r.0 174 | p1 = r.1 175 | continue 176 | } 177 | if let r = FileIdent.with(pointer: p1, length: length) { 178 | length -= p1.distance(to: r.1) 179 | guard fileIdent == nil else {return nil} 180 | fileIdent = r.0 181 | p1 = r.1 182 | continue 183 | } 184 | if let r = FileExtension.with(pointer: p1, length: length) { 185 | length -= p1.distance(to: r.1) 186 | guard fileExtension == nil else {return nil} 187 | fileExtension = r.0 188 | p1 = r.1 189 | continue 190 | } 191 | if let r = Attribute.with(pointer: p1, length: length) { 192 | length -= p1.distance(to: r.1) 193 | attributes.append(r.0) 194 | p1 = r.1 195 | continue 196 | } 197 | if let r = Table.with(pointer: p1, length: length) { 198 | length -= p1.distance(to: r.1) 199 | tables.append(r.0) 200 | p1 = r.1 201 | continue 202 | } 203 | if let r = Struct.with(pointer: p1, length: length) { 204 | length -= p1.distance(to: r.1) 205 | structs.append(r.0) 206 | p1 = r.1 207 | continue 208 | } 209 | if let r = Enum.with(pointer: p1, length: length) { 210 | length -= p1.distance(to: r.1) 211 | enums.append(r.0) 212 | p1 = r.1 213 | continue 214 | } 215 | if let r = Union.with(pointer: p1, length: length) { 216 | length -= p1.distance(to: r.1) 217 | unions.append(r.0) 218 | p1 = r.1 219 | continue 220 | } 221 | break 222 | } 223 | 224 | return (Schema( 225 | includes: includes, 226 | namespace: namespace, 227 | rootType: rootType, 228 | fileIdent: fileIdent, 229 | fileExtansion: fileExtension, 230 | attributes: attributes, 231 | tables: tables, 232 | structs: structs, 233 | enums: enums, 234 | unions: unions 235 | ), p1) 236 | } 237 | } 238 | 239 | struct IdentLookup { 240 | let structs: [String: Struct] 241 | let tables: [String:Table] 242 | let enums: [String: Enum] 243 | let unions: [String: Union] 244 | } 245 | 246 | extension Schema { 247 | var identLookup: IdentLookup { 248 | var structs = [String:Struct]() 249 | var tables = [String:Table]() 250 | var enums = [String: Enum]() 251 | var unions = [String: Union]() 252 | 253 | for s in self.structs { 254 | structs[s.name.value] = s 255 | } 256 | for t in self.tables { 257 | tables[t.name.value] = t 258 | } 259 | for e in self.enums { 260 | enums[e.name.value] = e 261 | } 262 | for u in self.unions { 263 | unions[u.name.value] = u 264 | } 265 | 266 | return IdentLookup(structs: structs, tables: tables, enums: enums, unions: unions) 267 | } 268 | 269 | var hasRecursions: Bool { 270 | let lookup = identLookup 271 | guard let rootType = rootType?.ident.value, 272 | let rootTable = lookup.tables[rootType] else { 273 | return false 274 | } 275 | 276 | return rootTable.findCycle(lookup: lookup, visited: []) 277 | } 278 | 279 | class StringBuilder { 280 | var value: String = "" 281 | func append(_ s : String) { 282 | value += s 283 | value += "\n" 284 | } 285 | } 286 | 287 | class Visited { 288 | var set: Set = [] 289 | func insert(_ s: String) { 290 | set.insert(s) 291 | } 292 | } 293 | 294 | public func swift(withImport: Bool = true) -> String { 295 | let lookup = identLookup 296 | var result = StringBuilder() 297 | result.append("import Foundation") 298 | if (withImport){ 299 | result.append("import FlatBuffersSwift") 300 | } 301 | result.append("") 302 | 303 | var visited = Visited() 304 | guard let rootType = rootType?.ident.value, 305 | let rootTable = lookup.tables[rootType] else { 306 | fatalError("Root type \(self.rootType?.ident.value ?? "nil") is not a table") 307 | } 308 | func trace(result: StringBuilder, node: ASTNode, visited: Visited) { 309 | if let table = node as? Table { 310 | guard visited.set.contains(table.name.value) == false else { 311 | return 312 | } 313 | visited.insert(table.name.value) 314 | if table.name.value == rootType, 315 | let fileIdentifier = fileIdent?.value.value { 316 | result.append(table.swift(lookup: lookup, isRoot: table.name.value == rootType, fileIdentifier: fileIdentifier)) 317 | } else { 318 | result.append(table.swift(lookup: lookup, isRoot: table.name.value == rootType)) 319 | } 320 | 321 | for f in table.fields { 322 | if let ref = f.type.ref?.value { 323 | if let t = lookup.tables[ref] { 324 | trace(result: result, node: t, visited: visited) 325 | } else if let s = lookup.structs[ref] { 326 | trace(result: result, node: s, visited: visited) 327 | } else if let e = lookup.enums[ref] { 328 | trace(result: result, node: e, visited: visited) 329 | } else if let u = lookup.unions[ref] { 330 | trace(result: result, node: u, visited: visited) 331 | } 332 | } 333 | } 334 | } else if let e = node as? Enum { 335 | guard visited.set.contains(e.name.value) == false else { 336 | return 337 | } 338 | visited.insert(e.name.value) 339 | result.append(e.swift) 340 | result.append(e.genFromJsonValue()) 341 | } else if let s = node as? Struct { 342 | guard visited.set.contains(s.name.value) == false else { 343 | return 344 | } 345 | visited.insert(s.name.value) 346 | result.append(s.swift) 347 | result.append(s.genFromJsonObjectExtension(lookup)) 348 | for f in s.fields { 349 | if let ref = f.type.ref?.value, 350 | let _s = lookup.structs[ref] { 351 | trace(result: result, node: _s, visited: visited) 352 | } 353 | } 354 | } else if let u = node as? Union { 355 | guard visited.set.contains(u.name.value) == false else { 356 | return 357 | } 358 | visited.insert(u.name.value) 359 | result.append(u.swift) 360 | result.append(u.genFromJsonExtension()) 361 | for u_case in u.cases { 362 | if let t = lookup.tables[u_case.value] { 363 | trace(result: result, node: t, visited: visited) 364 | } 365 | } 366 | } 367 | } 368 | trace(result: result, node: rootTable, visited: visited) 369 | if self.hasRecursions { 370 | result.append(""" 371 | fileprivate func performLateBindings(_ builder : FlatBuffersBuilder) throws { 372 | for binding in builder.deferedBindings { 373 | if let offset = builder.cache[ObjectIdentifier(binding.object)] { 374 | try builder.update(offset: offset, atCursor: binding.cursor) 375 | } else { 376 | throw FlatBuffersBuildError.couldNotPerformLateBinding 377 | } 378 | } 379 | builder.deferedBindings.removeAll() 380 | } 381 | """) 382 | } 383 | 384 | return result.value 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/StringLiteral.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringLiteral.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct StringLiteral { 12 | let value: String 13 | } 14 | 15 | extension StringLiteral: ASTNode { 16 | static func with(pointer: UnsafePointer, length: Int) -> (StringLiteral, UnsafePointer)? { 17 | guard let p1 = eat("\"", from: pointer, length: length) else {return nil} 18 | var p2 = p1 19 | while p2.pointee != UInt8(34) && p1.distance(to: p2) < length { 20 | p2 = p2.advanced(by: 1) 21 | } 22 | guard let p3 = eat("\"", from: p2, length: length) else {return nil} 23 | guard let value = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: p1), length: p1.distance(to: p2), encoding: .utf8, freeWhenDone: false) else { 24 | return nil 25 | } 26 | return (StringLiteral(value: value), p3) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/StructGen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Struct.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 22.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Struct { 12 | var swift: String { 13 | if fields.isEmpty {fatalError("struct \(name.value) has no fields")} 14 | for field in fields { 15 | if field.defaultIdent != nil || field.defaultValue != nil {fatalError("struct \(name.value).\(field.name.value) has a default value")} 16 | if field.type.string {fatalError("struct \(name.value).\(field.name.value) is a string")} 17 | if field.type.ref?.value == name.value {fatalError("struct \(name.value).\(field.name.value) is recursive")} 18 | } 19 | func genFields(_ fields: [Field]) -> String { 20 | let fieldStrings = fields.map { 21 | " public let \($0.name.value): \($0.type.swift)" 22 | } 23 | return fieldStrings.joined(separator: "\n") 24 | } 25 | func genEquals(_ fields: [Field], _ typeName: String) -> String { 26 | let fieldStrings = fields.map { 27 | return "v1.\($0.name.value)==v2.\($0.name.value)" 28 | } 29 | return """ 30 | public static func ==(v1:\(typeName), v2:\(typeName)) -> Bool { 31 | return \(fieldStrings.joined(separator: " && ")) 32 | } 33 | """ 34 | } 35 | return """ 36 | public struct \(name.value): Scalar { 37 | \(genFields(fields)) 38 | \(genEquals(fields, name.value)) 39 | } 40 | """ 41 | } 42 | 43 | func genFromJsonObjectExtension(_ lookup: IdentLookup) -> String { 44 | if fields.isEmpty { 45 | return "" 46 | } 47 | 48 | func genGuardStatement(_ scalar: Type.Scalar, _ name: String) -> String { 49 | switch scalar { 50 | case .bool: 51 | return """ 52 | guard let \(name) = object["\(name)"] as? Bool else { return nil } 53 | """ 54 | case .f32: 55 | return """ 56 | guard let \(name)Double = object["\(name)"] as? Double, let \(name) = Optional.some(\(scalar.swift)(\(name)Double)) else { return nil } 57 | """ 58 | case .f64: 59 | return """ 60 | guard let \(name) = object["\(name)"] as? Double else { return nil } 61 | """ 62 | case .i16, .i32, .i64, .i8, .u16, .u32, .u64, .u8: 63 | return """ 64 | guard let \(name)Int = object["\(name)"] as? Int, let \(name) = \(scalar.swift)(exactly: \(name)Int) else { return nil } 65 | """ 66 | } 67 | } 68 | 69 | func genGuardStatements(_ fields: [Field]) -> String { 70 | var statements = [String]() 71 | for f in fields { 72 | if let scalar = f.type.scalar { 73 | statements.append(" \(genGuardStatement(scalar, f.fieldName))") 74 | } else if f.type.isStruct(lookup), 75 | let typeName = f.type.ref?.value { 76 | statements.append(""" 77 | guard let \(f.fieldName) = \(typeName).from(jsonObject: object["\(f.fieldName)"] as? [String: Any]) else { return nil } 78 | """) 79 | } else if f.type.isEnum(lookup), 80 | let typeName = f.type.ref?.value { 81 | statements.append(""" 82 | guard let \(f.fieldName) = \(typeName).from(jsonValue: object["\(f.fieldName)"]) else { return nil } 83 | """) 84 | } 85 | } 86 | return statements.joined(separator: "\n") 87 | } 88 | 89 | func genInitParamStatements(_ fields: [Field]) -> String { 90 | var statements = [String]() 91 | for f in fields { 92 | statements.append(" \(f.fieldName): \(f.fieldName)") 93 | } 94 | return statements.joined(separator: ",\n") 95 | } 96 | 97 | return """ 98 | extension \(name.value) { 99 | static func from(jsonObject: [String: Any]?) -> \(name.value)? { 100 | guard let object = jsonObject else { return nil } 101 | \(genGuardStatements(fields)) 102 | return \(name.value)( 103 | \(genInitParamStatements(fields)) 104 | ) 105 | } 106 | } 107 | """ 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Table.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Table.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Table { 12 | let name: Ident 13 | let fields: [Field] 14 | let metaData: MetaData? 15 | let comments: [Comment] 16 | } 17 | 18 | struct Struct { 19 | let name: Ident 20 | let fields: [Field] 21 | let metaData: MetaData? 22 | let comments: [Comment] 23 | } 24 | 25 | extension Table: ASTNode { 26 | static func with(pointer: UnsafePointer, length: Int) -> (Table, UnsafePointer)? { 27 | guard let r = parse("table", pointer: pointer, length: length) else { 28 | return nil 29 | } 30 | return (Table(name: r.0.name, fields: r.0.fields, metaData: r.0.metaData, comments: r.0.comments), r.1) 31 | } 32 | } 33 | 34 | extension Struct: ASTNode { 35 | static func with(pointer: UnsafePointer, length: Int) -> (Struct, UnsafePointer)? { 36 | guard let r = parse("struct", pointer: pointer, length: length) else { 37 | return nil 38 | } 39 | return (Struct(name: r.0.name, fields: r.0.fields, metaData: r.0.metaData, comments: r.0.comments), r.1) 40 | } 41 | } 42 | 43 | fileprivate func parse(_ prefix: StaticString, pointer: UnsafePointer, length: Int) -> ((name: Ident, fields: [Field], metaData: MetaData?, comments: [Comment]), UnsafePointer)? { 44 | var p0 = pointer 45 | var length = length 46 | var comments = [Comment]() 47 | while let r = Comment.with(pointer: p0, length: length) { 48 | comments.append(r.0) 49 | length -= p0.distance(to: r.1) 50 | p0 = r.1 51 | } 52 | guard let p1 = eat(prefix, from: p0, length: length) else {return nil} 53 | length = length - p0.distance(to: p1) 54 | guard let (name, p2) = Ident.with(pointer: p1, length: length) else {parserError(pointer, length: pointer.distance(to: p1))} 55 | length -= p1.distance(to: p2) 56 | var p2_1 = p2 57 | var metaData: MetaData? = nil 58 | if let r = MetaData.with(pointer: p2_1, length: length) { 59 | metaData = r.0 60 | length -= p2_1.distance(to: r.1) 61 | p2_1 = r.1 62 | } 63 | guard let p3 = eat("{", from: p2_1, length: length) else {parserError(pointer, length: pointer.distance(to: p2_1))} 64 | length -= p2_1.distance(to: p3) 65 | var fields = [Field]() 66 | var p4 = p3 67 | while let (field, _p4) = Field.with(pointer: p4, length: length) { 68 | fields.append(field) 69 | length -= p4.distance(to: _p4) 70 | p4 = _p4 71 | } 72 | guard let p5 = eat("}", from: p4, length: length) else {parserError(pointer, length: pointer.distance(to: p4))} 73 | return ((name: name, fields: fields, metaData: metaData, comments: comments), p5) 74 | } 75 | 76 | extension Table { 77 | func computeFieldNamesWithVTableIndex(lookup: IdentLookup, withUniontypes: Bool = true) -> [(name: String, index: Int, root: Field)] { 78 | var result = [(name: String, index: Int, root: Field)]() 79 | var bonus = 0 80 | let sorted = sortedFields 81 | for i in 0.. [(name: String, index: Int, root: Field)] { 106 | return computeFieldNamesWithVTableIndex(lookup: lookup).sorted { (v1, v2) -> Bool in 107 | return v1.root.type.swiftSize(lookup: lookup) < v2.root.type.swiftSize(lookup: lookup) 108 | } 109 | } 110 | 111 | private var sortedFields: [Field] { 112 | let ids = fields.compactMap { (f) -> (Int, Field)? in 113 | if let id = f.id, let index = Int(id) { 114 | return (index, f) 115 | } 116 | return nil 117 | } 118 | if ids.isEmpty { 119 | return fields 120 | } 121 | if ids.count < fields.count { 122 | fatalError("Not all fields in table \(name.value) have id attribute") 123 | } 124 | return ids.sorted { (v1, v2) -> Bool in 125 | return v1.0 < v2.0 126 | }.map { (v) -> Field in 127 | return v.1 128 | } 129 | } 130 | } 131 | 132 | extension Struct { 133 | func swiftSize(lookup: IdentLookup) -> Int { 134 | return size(lookup: lookup, visited: []) 135 | } 136 | fileprivate func size(lookup: IdentLookup, visited: Set) -> Int { 137 | // ⚠️ this implementation does not take memory alignment into consideration 138 | var result = 0 139 | for f in fields { 140 | if let scalar = f.type.scalar { 141 | result += scalar.swiftSize 142 | continue 143 | } 144 | if let ref = f.type.ref, f.type.vector == false { 145 | if let _enum = lookup.enums[ref.value] { 146 | result += _enum.type.swiftSize(lookup: lookup) 147 | continue 148 | } 149 | if let _struct = lookup.structs[ref.value] { 150 | let name = _struct.name.value 151 | if visited.contains(name){ 152 | fatalError("Recursion!!! Struct \(name) already visited") 153 | } 154 | var newVisited = visited 155 | newVisited.insert(name) 156 | result += _struct.size(lookup: lookup, visited: newVisited) 157 | continue 158 | } 159 | } 160 | fatalError("field \(f.fieldName) is not of fixed size") 161 | } 162 | return result 163 | } 164 | } 165 | 166 | extension Table { 167 | func findCycle(lookup: IdentLookup, visited: Set) -> Bool { 168 | if visited.contains(name.value) { 169 | return true 170 | } 171 | var newVisited = visited 172 | newVisited.insert(name.value) 173 | 174 | for f in fields { 175 | if let ref = f.type.ref?.value { 176 | if let t = lookup.tables[ref] { 177 | if t.findCycle(lookup: lookup, visited: newVisited) { 178 | return true 179 | } 180 | } else if let u = lookup.unions[ref] { 181 | for u_case in u.cases { 182 | guard let t = lookup.tables[u_case.value] else { 183 | fatalError("Union case \(u_case.value) is not a table") 184 | } 185 | if t.findCycle(lookup: lookup, visited: newVisited) { 186 | return true 187 | } 188 | } 189 | } 190 | } 191 | } 192 | return false 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/TableGen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableGen.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 22.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Table { 12 | 13 | public func swift(lookup: IdentLookup, isRoot: Bool = false, fileIdentifier: String = "nil") -> String { 14 | return """ 15 | \(swiftClass(lookup:lookup)) 16 | \(readerProtocolExtension(lookup:lookup)) 17 | \(fromDataExtenstion(lookup:lookup, isRoot: isRoot)) 18 | \(insertExtenstion(lookup:lookup)) 19 | \(insertMethod(lookup:lookup, isRoot: isRoot, fileIdentifier: fileIdentifier)) 20 | \(genFromJsonObjectExtension(lookup)) 21 | """ 22 | } 23 | 24 | public func readerProtocolExtension(lookup: IdentLookup) -> String { 25 | func gen(_ fieldEnum: (String, Int, Field)) -> String { 26 | let fieldName = fieldEnum.0 27 | let index = fieldEnum.1 28 | let field = fieldEnum.2 29 | return """ 30 | public var \(fieldName): \(protocolType(field.type, lookup)) { 31 | \(guardForOffset(field, index, lookup)) 32 | return \(accessorReturnExpression(field, index, lookup)) 33 | } 34 | """ 35 | } 36 | let computedFields = computeFieldNamesWithVTableIndex( 37 | lookup: lookup, 38 | withUniontypes: false) 39 | return """ 40 | extension \(name.value).Direct { 41 | public init?(reader: R, myOffset: Offset? = nil) { 42 | guard let reader = reader as? T else { 43 | return nil 44 | } 45 | self._reader = reader 46 | if let myOffset = myOffset { 47 | self._myOffset = myOffset 48 | } else { 49 | if let rootOffset = reader.rootObjectOffset { 50 | self._myOffset = rootOffset 51 | } else { 52 | return nil 53 | } 54 | } 55 | } 56 | public var hashValue: Int { return Int(_myOffset) } 57 | public static func ==(t1 : \(name.value).Direct, t2 : \(name.value).Direct) -> Bool { 58 | return t1._reader.isEqual(other: t2._reader) && t1._myOffset == t2._myOffset 59 | } 60 | \(computedFields.map{return gen($0)}.joined(separator: "\n")) 61 | } 62 | """ 63 | } 64 | 65 | public func swiftClass(lookup: IdentLookup) -> String { 66 | func genFields(fields: [Field]) -> String { 67 | let fieldDefs = fields.map { (field) -> String in 68 | return " public var \(field.fieldName): \(field.type.swiftWithOptional)" 69 | } 70 | return fieldDefs.joined(separator: "\n") 71 | } 72 | func genInitParams(fields: [Field]) -> String { 73 | let params = fields.map { (field) -> String in 74 | var defaultValue = field.defaultValue?.value ?? field.type.defaultValue(lookup: lookup) 75 | if let defaultIdent = field.defaultIdent?.value { 76 | defaultValue = field.type.swift + "." + defaultIdent 77 | } 78 | return "\(field.fieldName): \(field.type.swiftWithOptional) = \(defaultValue)" 79 | } 80 | return params.joined(separator: ", ") 81 | } 82 | func genInitAssignments(fields: [Field]) -> String { 83 | let statements = fields.map { (field) -> String in 84 | 85 | return " self.\(field.fieldName) = \(field.fieldName)" 86 | } 87 | return statements.joined(separator: "\n") 88 | } 89 | return """ 90 | public final class \(name.value) { 91 | \(genFields(fields: fields)) 92 | public init(\(genInitParams(fields: fields))) { 93 | \(genInitAssignments(fields: fields)) 94 | } 95 | public struct Direct : Hashable, FlatBuffersDirectAccess { 96 | fileprivate let _reader : T 97 | fileprivate let _myOffset : Offset 98 | } 99 | } 100 | """ 101 | } 102 | 103 | public func fromDataExtenstion(lookup: IdentLookup, isRoot: Bool = false) -> String { 104 | func genPub() -> String { 105 | if isRoot { 106 | return """ 107 | public static func from(data: Data) -> \(name.value)? { 108 | let reader = FlatBuffersMemoryReader(data: data, withoutCopy: false) 109 | return \(name.value).from(selfReader: Direct(reader: reader)) 110 | } 111 | """ 112 | } 113 | return "" 114 | } 115 | func genAssignmentStatements(fields: [Field]) -> String { 116 | let statements = fields.map { (field) -> String in 117 | let name = field.fieldName 118 | if field.type.scalar != nil { 119 | if field.type.vector { 120 | return " o.\(name) = selfReader.\(name).compactMap{$0}" 121 | } 122 | return " o.\(name) = selfReader.\(name)" 123 | } else if field.type.string { 124 | if field.type.vector { 125 | return " o.\(name) = selfReader.\(name).compactMap{ $0§ }" 126 | } 127 | return " o.\(name) = selfReader.\(name)§" 128 | } else if let ref = field.type.ref { 129 | if let t = lookup.tables[ref.value] { 130 | if field.type.vector { 131 | return " o.\(name) = selfReader.\(name).compactMap{ \(t.name.value).from(selfReader:$0) }" 132 | } 133 | return " o.\(name) = \(t.name.value).from(selfReader:selfReader.\(name))" 134 | } else if let u = lookup.unions[ref.value] { 135 | if field.type.vector { 136 | fatalError("Union vector nos supported yet") 137 | } 138 | return " o.\(name) = \(u.name.value).from(selfReader: selfReader.\(field.fieldName))" 139 | } else { 140 | if field.type.vector { 141 | return " o.\(name) = selfReader.\(name).compactMap{$0}" 142 | } 143 | return " o.\(name) = selfReader.\(name)" 144 | } 145 | } 146 | fatalError("Unexpected case") 147 | } 148 | return statements.joined(separator: "\n") 149 | } 150 | return """ 151 | extension \(name.value) { 152 | \(genPub()) 153 | fileprivate static func from(selfReader: Direct?) -> \(name.value)? { 154 | guard let selfReader = selfReader else { 155 | return nil 156 | } 157 | if let o = selfReader._reader.cache?.objectPool[selfReader._myOffset] as? \(name.value) { 158 | return o 159 | } 160 | let o = \(name.value)() 161 | selfReader._reader.cache?.objectPool[selfReader._myOffset] = o 162 | \(genAssignmentStatements(fields: fields)) 163 | 164 | return o 165 | } 166 | } 167 | """ 168 | } 169 | 170 | public func insertExtenstion(lookup: IdentLookup) -> String { 171 | func parameters(values: [(name: String, index: Int, root: Field)]) -> String { 172 | let results = values.filter({ (v) -> Bool in 173 | return v.root.isDeprecated == false 174 | }).map { (v) -> String in 175 | return "\(v.name): \(v.root.type.swiftFB(lookup: lookup)) = \(v.root.type.defaultValueFB(lookup: lookup))" 176 | } 177 | return results.joined(separator: ", ") 178 | } 179 | func insertStatements(values: [(name: String, index: Int, root: Field)]) -> String { 180 | let results = values.filter({ (v) -> Bool in 181 | return v.root.isDeprecated == false 182 | }).map { (v) -> String in 183 | if v.root.type.string || 184 | v.root.type.vector { 185 | return """ 186 | if let \(v.name) = \(v.name) { 187 | valueCursors[\(v.index)] = try self.insert(offset: \(v.name), toStartedObjectAt: \(v.index)) 188 | } 189 | """ 190 | } 191 | if let ref = v.root.type.ref { 192 | if lookup.tables[ref.value] != nil || 193 | lookup.unions[ref.value] != nil { 194 | return """ 195 | if let \(v.name) = \(v.name) { 196 | valueCursors[\(v.index)] = try self.insert(offset: \(v.name), toStartedObjectAt: \(v.index)) 197 | } 198 | """ 199 | } 200 | if lookup.structs[ref.value] != nil { 201 | return """ 202 | if let \(v.name) = \(v.name) { 203 | self.insert(value: \(v.name)) 204 | valueCursors[\(v.index)] = try self.insertCurrentOffsetAsProperty(toStartedObjectAt: \(v.index)) 205 | } 206 | """ 207 | } 208 | if lookup.enums[ref.value] != nil { 209 | return " valueCursors[\(v.index)] = try self.insert(value: \(v.name).rawValue, defaultValue: \(v.root.type.defaultValueFB(lookup: lookup)).rawValue, toStartedObjectAt: \(v.index))" 210 | } 211 | } 212 | 213 | if v.root.type.scalar != nil { 214 | return " valueCursors[\(v.index)] = try self.insert(value: \(v.name), defaultValue: \(v.root.type.defaultValueFB(lookup: lookup)), toStartedObjectAt: \(v.index))" 215 | } 216 | fatalError("Unexpected case") 217 | } 218 | return results.joined(separator: "\n") 219 | } 220 | let sorted = self.computeFieldNamesWithVTableIndex(lookup: lookup) 221 | let sortedBySize = self.computeFieldNamesWithVTableIndexSortedBySize(lookup: lookup) 222 | 223 | return """ 224 | extension FlatBuffersBuilder { 225 | public func insert\(name.value)(\(parameters(values: sorted))) throws -> (Offset, [Int?]) { 226 | var valueCursors = [Int?](repeating: nil, count: \(sorted.count)) 227 | try self.startObject(withPropertyCount: \(sorted.count)) 228 | \(insertStatements(values: sortedBySize)) 229 | return try (self.endObject(), valueCursors) 230 | } 231 | } 232 | """ 233 | } 234 | 235 | public func insertMethod(lookup: IdentLookup, isRoot: Bool = false, fileIdentifier: String) -> String { 236 | func genOffsetAssignements(_ fields: [Field]) -> String { 237 | 238 | let statements = fields.map { (f) -> String in 239 | if f.type.vector { 240 | if f.type.scalar != nil || f.type.isStruct(lookup) || f.type.isEnum(lookup) { 241 | let typeName: String 242 | if let scalar = f.type.scalar { 243 | typeName = scalar.swift 244 | } else if let ref = f.type.ref?.value{ 245 | typeName = ref 246 | } else { 247 | fatalError("Unexpected case") 248 | } 249 | 250 | let dataObject = f.type.isEnum(lookup) ? "o.rawValue" : "o" 251 | 252 | return """ 253 | let \(f.fieldName): Offset? 254 | if self.\(f.fieldName).isEmpty { 255 | \(f.fieldName) = nil 256 | } else { 257 | try builder.startVector(count: self.\(f.fieldName).count, elementSize: MemoryLayout<\(typeName)>.stride) 258 | for o in self.\(f.fieldName).reversed() { 259 | builder.insert(value: \(dataObject)) 260 | } 261 | \(f.fieldName) = builder.endVector() 262 | } 263 | """ 264 | } 265 | if f.type.string || f.type.isTable(lookup) { 266 | let insertStm = f.type.string ? "builder.insert(value: $0)" : "$0.insert(builder)" 267 | let isRecursive = f.type.isRecursive(lookup) 268 | let insertElementStm = isRecursive ? """ 269 | let cursor = try builder.insert(offset: o) 270 | if o == 0 { 271 | builder.deferedBindings.append((object: self.\(f.fieldName).reversed()[index], cursor: cursor)) 272 | } 273 | """ 274 | : """ 275 | try builder.insert(offset: o) 276 | """ 277 | return """ 278 | let \(f.fieldName): Offset? 279 | if self.\(f.fieldName).isEmpty { 280 | \(f.fieldName) = nil 281 | } else { 282 | let offsets = try self.\(f.fieldName).reversed().map{ try \(insertStm) } 283 | try builder.startVector(count: self.\(f.fieldName).count, elementSize: MemoryLayout.stride) 284 | for (\(isRecursive ? "index" : "_" ), o) in offsets.enumerated() { 285 | \(insertElementStm) 286 | } 287 | \(f.fieldName) = builder.endVector() 288 | } 289 | """ 290 | } 291 | } 292 | if f.type.string { 293 | return " let \(f.fieldName) = self.\(f.fieldName) == nil ? nil : try builder.insert(value: self.\(f.fieldName))" 294 | } 295 | if f.type.isTable(lookup) { 296 | return " let \(f.fieldName) = try self.\(f.fieldName)?.insert(builder)" 297 | } 298 | if f.type.isUnion(lookup) { 299 | return """ 300 | let \(f.fieldName) = try self.\(f.fieldName)?.insert(builder) 301 | let \(f.fieldName)_type = self.\(f.fieldName)?.unionCase ?? 0 302 | """ 303 | } 304 | fatalError("Unexpected Case") 305 | } 306 | return statements.joined(separator: "\n") 307 | } 308 | 309 | func genCheckForLateBindings(lookup: IdentLookup, sorted: [(name: String, index: Int, root: Field)]) -> String { 310 | let statements = sorted.compactMap { f -> String? in 311 | if f.root.type.vector { 312 | return nil 313 | } 314 | guard f.root.type.isRecursive(lookup) else { return nil } 315 | let isUnion = f.root.type.isUnion(lookup) 316 | return """ 317 | if \(f.root.fieldName) == 0, 318 | let o = self.\(f.root.fieldName), 319 | let cursor = valueCursors[\(f.index)] { 320 | builder.deferedBindings.append((\(isUnion ? "o.value" : "o"), cursor)) 321 | } 322 | """ 323 | } 324 | return statements.joined(separator: "\n") 325 | } 326 | 327 | func parameters(values: [(name: String, index: Int, root: Field)]) -> String { 328 | let results = values.filter({ (v) -> Bool in 329 | return v.root.isDeprecated == false 330 | }).map { (v) -> String in 331 | var rightHand = v.name 332 | if !v.root.type.vector { 333 | if v.root.type.isEnum(lookup) { 334 | rightHand = "\(v.name) ?? \(v.root.type.defaultValueFB(lookup: lookup))" 335 | } 336 | } 337 | 338 | return " \(v.name): \(rightHand)" 339 | } 340 | return results.joined(separator: ",\n") 341 | } 342 | 343 | let isRecursive = findCycle(lookup: lookup, visited: []) 344 | 345 | func inserRootMethods(_ fileIdentifier: String) -> String { 346 | if isRoot { 347 | let escapedFileIdentifier = fileIdentifier == "nil" ? fileIdentifier : "\"\(fileIdentifier)\"" 348 | return """ 349 | public func makeData(withOptions options : FlatBuffersBuilderOptions = FlatBuffersBuilderOptions()) throws -> Data { 350 | let builder = FlatBuffersBuilder(options: options) 351 | let offset = try insert(builder) 352 | try builder.finish(offset: offset, fileIdentifier: \(escapedFileIdentifier)) 353 | \(isRecursive ? "try performLateBindings(builder)" : "") 354 | return builder.makeData 355 | } 356 | """ 357 | } else { 358 | return "" 359 | } 360 | } 361 | 362 | let monitorProgressStart = isRecursive ? """ 363 | if builder.inProgress.contains(ObjectIdentifier(self)){ 364 | return 0 365 | } 366 | builder.inProgress.insert(ObjectIdentifier(self)) 367 | """ : "" 368 | 369 | let monitorProgressEnd = isRecursive ? """ 370 | builder.inProgress.remove(ObjectIdentifier(self)) 371 | """ : "" 372 | 373 | let offsetBasedFields = fields.filter { (f) -> Bool in 374 | if f.type.string || f.type.vector { 375 | return true 376 | } 377 | if let ref = f.type.ref?.value { 378 | return lookup.tables[ref] != nil || 379 | lookup.unions[ref] != nil 380 | } 381 | 382 | return false 383 | } 384 | 385 | let sorted = self.computeFieldNamesWithVTableIndex(lookup: lookup) 386 | 387 | let hasRecursiveProperties = isRecursive && sorted.filter{ $0.root.type.vector == false && $0.root.type.isRecursive(lookup)}.isEmpty == false 388 | 389 | return """ 390 | extension \(name.value) { 391 | func insert(_ builder : FlatBuffersBuilder) throws -> Offset { 392 | if builder.options.uniqueTables { 393 | if let myOffset = builder.cache[ObjectIdentifier(self)] { 394 | return myOffset 395 | } 396 | } 397 | \(monitorProgressStart) 398 | \(genOffsetAssignements(offsetBasedFields)) 399 | let (myOffset, \(hasRecursiveProperties ? "valueCursors" : "_")) = try builder.insert\(name.value)( 400 | \(parameters(values: sorted)) 401 | ) 402 | \(isRecursive ? genCheckForLateBindings(lookup: lookup, sorted: sorted) : "") 403 | if builder.options.uniqueTables { 404 | builder.cache[ObjectIdentifier(self)] = myOffset 405 | } 406 | \(monitorProgressEnd) 407 | return myOffset 408 | } 409 | \(inserRootMethods(fileIdentifier)) 410 | } 411 | """ 412 | } 413 | 414 | private func protocolType(_ type : Type, _ lookup: IdentLookup) -> String { 415 | 416 | if type.string { 417 | if type.vector { 418 | return "FlatBuffersStringVector" 419 | } 420 | return "UnsafeBufferPointer?" 421 | } 422 | if let ref = type.ref { 423 | let t = Type(scalar: nil, vector: false, ref: ref, string: false) 424 | if lookup.tables[ref.value] != nil { 425 | if type.vector { 426 | return "FlatBuffersTableVector<\(t.swift+".Direct"), T>" 427 | } 428 | return t.swift + ".Direct?" 429 | } else if lookup.structs[ref.value] != nil { 430 | if type.vector { 431 | return "FlatBuffersScalarVector<\(t.swift), T>" 432 | } 433 | return t.swift + "?" 434 | } else if let e = lookup.enums[ref.value] { 435 | if type.vector { 436 | return "FlatBuffersEnumVector<\(e.type.swift), T, \(ref.value)>" 437 | } 438 | return ref.value + "?" 439 | } else if let _ = lookup.unions[ref.value] { 440 | if type.vector { 441 | fatalError("Union Vector is not supported yet") 442 | } 443 | return ref.value + ".Direct?" 444 | } 445 | 446 | fatalError("Unexpected Type") 447 | } 448 | if type.scalar != nil && type.vector { 449 | let t = Type(scalar: type.scalar, vector: false, ref: nil, string: false) 450 | return "FlatBuffersScalarVector<\(t.swift), T>" 451 | } 452 | return type.swift 453 | 454 | } 455 | 456 | private func guardForOffset(_ field: Field, _ index: Int, _ lookup: IdentLookup) -> String { 457 | if field.type.vector { 458 | return "" 459 | } 460 | guard field.type.string || field.type.ref != nil else { 461 | return "" 462 | } 463 | if let ref = field.type.ref, lookup.tables[ref.value] == nil { 464 | return "" 465 | } 466 | return " guard let offset = _reader.offset(objectOffset: _myOffset, propertyIndex:\(index)) else {return nil}" 467 | } 468 | 469 | private func accessorReturnExpression(_ field: Field, _ index: Int, _ lookup: IdentLookup) -> String { 470 | let index = field.id ?? index.description 471 | if let scalar = field.type.scalar { 472 | if field.type.vector { 473 | return "FlatBuffersScalarVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:\(index)))" 474 | } 475 | let defaultValue = field.defaultValue?.value ?? scalar.defaultValue 476 | return "_reader.get(objectOffset: _myOffset, propertyIndex: \(index), defaultValue: \(defaultValue))" 477 | } 478 | if field.type.string { 479 | if field.type.vector { 480 | return "FlatBuffersStringVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:\(index)))" 481 | } 482 | return "_reader.stringBuffer(stringOffset: offset)" 483 | } 484 | if let ref = field.type.ref { 485 | let t = Type(scalar: nil, vector: false, ref: ref, string: false) 486 | if lookup.tables[ref.value] != nil { 487 | if field.type.vector { 488 | return "FlatBuffersTableVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:\(index)))" 489 | } 490 | return t.swift + ".Direct(reader: _reader, myOffset: offset)" 491 | } else if lookup.structs[ref.value] != nil { 492 | if field.type.vector { 493 | return "FlatBuffersScalarVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:\(index)))" 494 | } 495 | return "_reader.get(objectOffset: _myOffset, propertyIndex: \(index))" 496 | } else if let e = lookup.enums[ref.value] { 497 | if field.type.vector { 498 | return "FlatBuffersEnumVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:\(index)))" 499 | } 500 | let defaultCase = field.defaultIdent?.value ?? e.cases[0].ident.value 501 | let enumName = e.name.value 502 | return "\(enumName)(rawValue:_reader.get(objectOffset: _myOffset, propertyIndex: \(index), defaultValue: \(enumName).\(defaultCase).rawValue))" 503 | } else if lookup.unions[ref.value] != nil { 504 | if field.type.vector { 505 | fatalError("Vector of unions is not supported yet") 506 | } 507 | return t.swift + ".Direct.from(reader: _reader, propertyIndex : \(index), objectOffset : _myOffset)" 508 | } 509 | } 510 | fatalError("Unexpeceted type") 511 | } 512 | 513 | func genFromJsonObjectExtension(_ lookup: IdentLookup) -> String { 514 | func genAssignementStatements(_ fields: [Field]) -> String { 515 | var statements = [String]() 516 | for f in fields { 517 | if f.type.string { 518 | if f.type.vector { 519 | statements.append(""" 520 | let \(f.fieldName) = object["\(f.fieldName)"] as? [String] ?? [] 521 | """) 522 | } else { 523 | statements.append(""" 524 | let \(f.fieldName) = object["\(f.fieldName)"] as? String 525 | """) 526 | } 527 | } else if f.type.isEnum(lookup), let typeName = f.type.ref?.value { 528 | if f.type.vector { 529 | statements.append(""" 530 | let \(f.fieldName) = ((object["\(f.fieldName)"] as? [Any]) ?? []).compactMap { \(typeName).from(jsonValue: $0)} 531 | """) 532 | } else { 533 | statements.append(""" 534 | let \(f.fieldName) = \(typeName).from(jsonValue: object["\(f.fieldName)"]) 535 | """) 536 | } 537 | } else if f.type.isStruct(lookup) || f.type.isTable(lookup), let typeName = f.type.ref?.value { 538 | if f.type.vector { 539 | statements.append(""" 540 | let \(f.fieldName) = ((object["\(f.fieldName)"] as? [[String: Any]]) ?? []).compactMap { \(typeName).from(jsonObject: $0)} 541 | """) 542 | } else { 543 | statements.append(""" 544 | let \(f.fieldName) = \(typeName).from(jsonObject: object["\(f.fieldName)"] as? [String: Any]) 545 | """) 546 | } 547 | } else if let scalar = f.type.scalar { 548 | if f.type.vector { 549 | switch scalar { 550 | case .bool: 551 | statements.append(""" 552 | let \(f.fieldName) = object["\(f.fieldName)"] as? [Bool] ?? [] 553 | """) 554 | case .f32, .f64: 555 | statements.append(""" 556 | let \(f.fieldName) = (object["\(f.fieldName)"] as? [Double] ?? []).compactMap { \(scalar.swift)(exactly: $0) } 557 | """) 558 | case .i8, .i16, .i32, .i64, .u8, .u16, .u32, .u64: 559 | statements.append(""" 560 | let \(f.fieldName) = (object["\(f.fieldName)"] as? [Int] ?? []).compactMap { \(scalar.swift)(exactly: $0) } 561 | """) 562 | } 563 | } else { 564 | switch scalar { 565 | case .bool: 566 | statements.append(""" 567 | let \(f.fieldName) = object["\(f.fieldName)"] as? Bool 568 | """) 569 | case .f32: 570 | statements.append(""" 571 | let \(f.fieldName) = object["\(f.fieldName)"] as? Double).flatMap { \(scalar.swift)($0) } ?? \(f.defaultValue?.value ?? "0") 572 | """) 573 | case .f64: 574 | statements.append(""" 575 | let \(f.fieldName) = object["\(f.fieldName)"] as? Double 576 | """) 577 | case .i8, .i16, .i32, .i64, .u8, .u16, .u32, .u64: 578 | statements.append(""" 579 | let \(f.fieldName) = (object["\(f.fieldName)"] as? Int).flatMap { \(scalar.swift)(exactly: $0) } ?? \(f.defaultValue?.value ?? "0") 580 | """) 581 | } 582 | } 583 | } else if f.type.isUnion(lookup), let typeName = f.type.ref?.value { 584 | if f.type.vector { 585 | fatalError("Unsupported type") 586 | } else { 587 | statements.append(""" 588 | let \(f.fieldName) = \(typeName).from(type:object["\(f.fieldName)_type"] as? String, jsonObject: object["\(f.fieldName)"] as? [String: Any]) 589 | """) 590 | } 591 | } else { 592 | fatalError("Unsupported type") 593 | } 594 | 595 | } 596 | return statements.joined(separator: "\n") 597 | } 598 | 599 | func genInitParamStatements(_ fields: [Field]) -> String { 600 | var statements = [String]() 601 | for f in fields { 602 | statements.append(" \(f.fieldName): \(f.fieldName)") 603 | } 604 | return statements.joined(separator: ",\n") 605 | } 606 | 607 | return """ 608 | extension \(name.value) { 609 | public static func from(jsonObject: [String: Any]?) -> \(name.value)? { 610 | guard let object = jsonObject else { return nil } 611 | \(genAssignementStatements(fields)) 612 | return \(name.value) ( 613 | \(genInitParamStatements(fields)) 614 | ) 615 | } 616 | } 617 | """ 618 | } 619 | } 620 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Type.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Type.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Type { 12 | let scalar: Scalar? 13 | let vector: Bool 14 | let ref: Ident? 15 | let string: Bool 16 | enum Scalar { 17 | case i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, bool 18 | var swift: String { 19 | switch self { 20 | case .i8: 21 | return "Int8" 22 | case .u8: 23 | return "UInt8" 24 | case .i16: 25 | return "Int16" 26 | case .u16: 27 | return "UInt16" 28 | case .i32: 29 | return "Int32" 30 | case .u32: 31 | return "UInt32" 32 | case .i64: 33 | return "Int64" 34 | case .u64: 35 | return "UInt64" 36 | case .f32: 37 | return "Float32" 38 | case .f64: 39 | return "Float64" 40 | case .bool: 41 | return "Bool" 42 | } 43 | } 44 | var defaultValue: String { 45 | return self == .bool ? "false" : "0" 46 | } 47 | var swiftSize: Int { 48 | switch self { 49 | case .i8: 50 | return 1 51 | case .u8: 52 | return 1 53 | case .i16: 54 | return 2 55 | case .u16: 56 | return 2 57 | case .i32: 58 | return 4 59 | case .u32: 60 | return 4 61 | case .i64: 62 | return 8 63 | case .u64: 64 | return 8 65 | case .f32: 66 | return 4 67 | case .f64: 68 | return 8 69 | case .bool: 70 | return 1 71 | } 72 | } 73 | } 74 | var swift: String { 75 | var value = "" 76 | if string { 77 | value = "String" 78 | } else if let ref = ref { 79 | value = ref.value 80 | } else if let scalar = scalar { 81 | value = scalar.swift 82 | } 83 | if vector { 84 | return "[\(value)]" 85 | } 86 | return value 87 | } 88 | func swiftFB(lookup: IdentLookup) -> String { 89 | var value = "" 90 | if string { 91 | value = "Offset?" 92 | } else if let ref = ref { 93 | if lookup.enums[ref.value] != nil{ 94 | value = ref.value 95 | } else if lookup.structs[ref.value] != nil { 96 | value = ref.value + "?" 97 | } else { 98 | value = "Offset?" 99 | } 100 | } else if let scalar = scalar { 101 | value = scalar.swift 102 | } 103 | if vector { 104 | return "Offset?" 105 | } 106 | return value 107 | } 108 | var swiftWithOptional: String { 109 | let value = swift 110 | if vector == false { 111 | if string { 112 | return "String?" 113 | } else if let ref = ref { 114 | return ref.value + "?" 115 | } 116 | } 117 | return value 118 | } 119 | func defaultValue(lookup: IdentLookup) -> String { 120 | if vector { 121 | return "[]" 122 | } else if let ref = ref { 123 | if let e = lookup.enums[ref.value]{ 124 | return e.name.value + "." + e.cases[0].ident.value 125 | } 126 | return "nil" 127 | } else if let scalar = scalar { 128 | return scalar.defaultValue 129 | } else if string { 130 | return "nil" 131 | } 132 | fatalError("Unexpected case") 133 | } 134 | func defaultValueFB(lookup: IdentLookup) -> String { 135 | if vector { 136 | return "nil" 137 | } else if let ref = ref { 138 | if let e = lookup.enums[ref.value]{ 139 | return e.name.value + "." + e.cases[0].ident.value 140 | } 141 | return "nil" 142 | } else if let scalar = scalar { 143 | return scalar.defaultValue 144 | } else if string { 145 | return "nil" 146 | } 147 | fatalError("Unexpected case") 148 | } 149 | 150 | func swiftSize(lookup: IdentLookup) -> Int { 151 | if string || vector { 152 | return 4 153 | } 154 | if let scalar = self.scalar { 155 | return scalar.swiftSize 156 | } 157 | if let ref = self.ref { 158 | if lookup.tables[ref.value] != nil || lookup.unions[ref.value] != nil { 159 | return 4 160 | } 161 | if let _enum = lookup.enums[ref.value] { 162 | return _enum.type.swiftSize(lookup:lookup) 163 | } 164 | if let _struct = lookup.structs[ref.value] { 165 | return _struct.swiftSize(lookup:lookup) 166 | } 167 | } 168 | fatalError("Unexpected case") 169 | } 170 | 171 | func isTable(_ lookup: IdentLookup) -> Bool { 172 | if let ref = ref?.value { 173 | return lookup.tables[ref] != nil 174 | } 175 | return false 176 | } 177 | func isUnion(_ lookup: IdentLookup) -> Bool { 178 | if let ref = ref?.value { 179 | return lookup.unions[ref] != nil 180 | } 181 | return false 182 | } 183 | func isStruct(_ lookup: IdentLookup) -> Bool { 184 | if let ref = ref?.value { 185 | return lookup.structs[ref] != nil 186 | } 187 | return false 188 | } 189 | func isEnum(_ lookup: IdentLookup) -> Bool { 190 | if let ref = ref?.value { 191 | return lookup.enums[ref] != nil 192 | } 193 | return false 194 | } 195 | func isRecursive(_ lookup: IdentLookup) -> Bool { 196 | guard let ref = ref?.value else { return false } 197 | if let table = lookup.tables[ref] { 198 | return table.findCycle(lookup: lookup, visited: []) 199 | } 200 | if let union = lookup.unions[ref]{ 201 | for indent in union.cases { 202 | if let table = lookup.tables[indent.value] { 203 | if table.findCycle(lookup: lookup, visited: []) { 204 | return true 205 | } 206 | } 207 | } 208 | } 209 | return false 210 | } 211 | } 212 | 213 | extension Type: ASTNode { 214 | static func with(pointer p: UnsafePointer, length: Int) -> (Type, UnsafePointer)? { 215 | guard let p1 = eatWhiteSpace(p, length: length) else {return nil} 216 | var length = length - p.distance(to: p1) 217 | if let p2 = eat("[", from: p1, length: length) { 218 | length -= 1 219 | if let (t, p3) = Type.with(pointer: p2, length: length) { 220 | length -= p2.distance(to: p3) 221 | if let p4 = eat("]", from: p3, length: length) { 222 | return (Type(scalar: t.scalar, vector: true, ref: t.ref, string: t.string), p4) 223 | } 224 | } 225 | return nil 226 | } 227 | if let p2 = eat("bool", from: p1, length: length) { 228 | return (Type(scalar: .bool, vector: false, ref: nil, string: false), p2) 229 | } 230 | if let p2 = eat("byte", from: p1, length: length) { 231 | return (Type(scalar: .i8, vector: false, ref: nil, string: false), p2) 232 | } 233 | if let p2 = eat("int8", from: p1, length: length) { 234 | return (Type(scalar: .i8, vector: false, ref: nil, string: false), p2) 235 | } 236 | if let p2 = eat("ubyte", from: p1, length: length) { 237 | return (Type(scalar: .u8, vector: false, ref: nil, string: false), p2) 238 | } 239 | if let p2 = eat("uint8", from: p1, length: length) { 240 | return (Type(scalar: .u8, vector: false, ref: nil, string: false), p2) 241 | } 242 | if let p2 = eat("short", from: p1, length: length) { 243 | return (Type(scalar: .i16, vector: false, ref: nil, string: false), p2) 244 | } 245 | if let p2 = eat("int16", from: p1, length: length) { 246 | return (Type(scalar: .i16, vector: false, ref: nil, string: false), p2) 247 | } 248 | if let p2 = eat("ushort", from: p1, length: length) { 249 | return (Type(scalar: .u16, vector: false, ref: nil, string: false), p2) 250 | } 251 | if let p2 = eat("uint16", from: p1, length: length) { 252 | return (Type(scalar: .u16, vector: false, ref: nil, string: false), p2) 253 | } 254 | if let p2 = eat("int32", from: p1, length: length) { 255 | return (Type(scalar: .i32, vector: false, ref: nil, string: false), p2) 256 | } 257 | if let p2 = eat("uint32", from: p1, length: length) { 258 | return (Type(scalar: .u32, vector: false, ref: nil, string: false), p2) 259 | } 260 | if let p2 = eat("long", from: p1, length: length) { 261 | return (Type(scalar: .i64, vector: false, ref: nil, string: false), p2) 262 | } 263 | if let p2 = eat("int64", from: p1, length: length) { 264 | return (Type(scalar: .i64, vector: false, ref: nil, string: false), p2) 265 | } 266 | if let p2 = eat("ulong", from: p1, length: length) { 267 | return (Type(scalar: .u64, vector: false, ref: nil, string: false), p2) 268 | } 269 | if let p2 = eat("uint64", from: p1, length: length) { 270 | return (Type(scalar: .u64, vector: false, ref: nil, string: false), p2) 271 | } 272 | if let p2 = eat("float32", from: p1, length: length) { 273 | return (Type(scalar: .f32, vector: false, ref: nil, string: false), p2) 274 | } 275 | if let p2 = eat("float64", from: p1, length: length) { 276 | return (Type(scalar: .f64, vector: false, ref: nil, string: false), p2) 277 | } 278 | 279 | if let p2 = eat("uint", from: p1, length: length) { 280 | return (Type(scalar: .u32, vector: false, ref: nil, string: false), p2) 281 | } 282 | if let p2 = eat("int", from: p1, length: length) { 283 | return (Type(scalar: .i32, vector: false, ref: nil, string: false), p2) 284 | } 285 | if let p2 = eat("float", from: p1, length: length) { 286 | return (Type(scalar: .f32, vector: false, ref: nil, string: false), p2) 287 | } 288 | if let p2 = eat("double", from: p1, length: length) { 289 | return (Type(scalar: .f64, vector: false, ref: nil, string: false), p2) 290 | } 291 | if let p2 = eat("string", from: p1, length: length) { 292 | return (Type(scalar: nil, vector: false, ref: nil, string: true), p2) 293 | } 294 | if let (name, p2) = Ident.with(pointer: p, length: length) { 295 | return (Type(scalar: nil, vector: false, ref: name, string: false), p2) 296 | } 297 | return nil 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/Union.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Union.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 19.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Union { 12 | let name: Ident 13 | let cases: [Ident] 14 | let metaData: MetaData? 15 | let comments: [Comment] 16 | } 17 | 18 | extension Union: ASTNode { 19 | static func with(pointer: UnsafePointer, length: Int) -> (Union, UnsafePointer)? { 20 | var p0 = pointer 21 | var length = length 22 | var comments = [Comment]() 23 | while let r = Comment.with(pointer: p0, length: length) { 24 | comments.append(r.0) 25 | length -= p0.distance(to: r.1) 26 | p0 = r.1 27 | } 28 | guard let p1 = eat("union", from: p0, length: length) else {return nil} 29 | length = length - p0.distance(to: p1) 30 | guard let (name, p2) = Ident.with(pointer: p1, length: length) else {return nil} 31 | length -= p1.distance(to: p2) 32 | var p2_1 = p2 33 | var metaData: MetaData? = nil 34 | if let r = MetaData.with(pointer: p2_1, length: length) { 35 | metaData = r.0 36 | length -= p2_1.distance(to: r.1) 37 | p2_1 = r.1 38 | } 39 | guard let p3 = eat("{", from: p2_1, length: length) else {return nil} 40 | length -= p2_1.distance(to: p3) 41 | var cases = [Ident]() 42 | var p4 = p3 43 | while let (_case, _p4) = Ident.with(pointer: p4, length: length) { 44 | cases.append(_case) 45 | length -= p4.distance(to: _p4) 46 | p4 = _p4 47 | guard let _p5 = eat(",", from: p4, length: length) else {break} 48 | length -= p4.distance(to: _p5) 49 | p4 = _p5 50 | } 51 | guard let p5 = eat("}", from: p4, length: length) else {return nil} 52 | return (Union(name: name, cases: cases, metaData: metaData, comments: comments), p5) 53 | } 54 | } 55 | 56 | extension Union { 57 | var swift: String { 58 | func genCases(_ cases: [Ident]) -> String { 59 | let theCases = cases.map { (ident) -> String in 60 | return "with\(ident.value)(\(ident.value))" 61 | } 62 | return theCases.joined(separator: ", ") 63 | } 64 | func genDirectCases(_ cases: [Ident]) -> String { 65 | let theCases = cases.map { (ident) -> String in 66 | return "with\(ident.value)(\(ident.value).Direct)" 67 | } 68 | return theCases.joined(separator: ", ") 69 | } 70 | func genSwitchCases(_ caases: [Ident]) -> String { 71 | let theCases = cases.map { (ident) -> String in 72 | return """ 73 | case .with\(ident.value)(let o): 74 | guard let o1 = \(ident.value).from(selfReader: o) else { 75 | return nil 76 | } 77 | return .with\(ident.value)(o1) 78 | """ 79 | } 80 | return theCases.joined(separator: "\n") 81 | } 82 | func genDirectSwitchCases(_ caases: [Ident], _ unionName: String) -> String { 83 | let theCases = cases.enumerated().map { (tuple) -> String in 84 | let ident = tuple.element 85 | let index = tuple.offset + 1 86 | return """ 87 | case \(index): 88 | guard let o = \(ident.value).Direct(reader: reader, myOffset: caseObjectOffset) else { 89 | return nil 90 | } 91 | return \(unionName).Direct.with\(ident.value)(o) 92 | """ 93 | } 94 | return theCases.joined(separator: "\n") 95 | } 96 | func genAsProperties(_ cases: [Ident]) -> String { 97 | let properties = cases.map { (ident) -> String in 98 | let name = ident.value 99 | return """ 100 | public var as\(name): \(name)? { 101 | switch self { 102 | case .with\(name)(let v): 103 | return v 104 | default: 105 | return nil 106 | } 107 | } 108 | """ 109 | } 110 | return properties.joined(separator: "\n") 111 | } 112 | func genValueProperty(_ cases: [Ident]) -> String { 113 | let caseStatements = cases.map { " case .with\($0.value)(let v): return v" }.joined(separator: "\n") 114 | return """ 115 | public var value: AnyObject { 116 | switch self { 117 | \(caseStatements) 118 | } 119 | } 120 | """ 121 | } 122 | func genDirectAsProperties(_ cases: [Ident]) -> String { 123 | let properties = cases.map { (ident) -> String in 124 | let name = ident.value 125 | return """ 126 | public var as\(name): \(name).Direct? { 127 | switch self { 128 | case .with\(name)(let v): 129 | return v 130 | default: 131 | return nil 132 | } 133 | } 134 | """ 135 | } 136 | return properties.joined(separator: "\n") 137 | } 138 | return """ 139 | public enum \(name.value) { 140 | case \(genCases(cases)) 141 | fileprivate static func from(selfReader: \(name.value).Direct?) -> \(name.value)? { 142 | guard let selfReader = selfReader else { 143 | return nil 144 | } 145 | switch selfReader { 146 | \(genSwitchCases(cases)) 147 | } 148 | } 149 | public enum Direct { 150 | case \(genDirectCases(cases)) 151 | fileprivate static func from(reader: R, propertyIndex : Int, objectOffset : Offset?) -> \(name.value).Direct? { 152 | guard let objectOffset = objectOffset else { 153 | return nil 154 | } 155 | let unionCase : Int8 = reader.get(objectOffset: objectOffset, propertyIndex: propertyIndex, defaultValue: 0) 156 | guard let caseObjectOffset : Offset = reader.offset(objectOffset: objectOffset, propertyIndex:propertyIndex + 1) else { 157 | return nil 158 | } 159 | switch unionCase { 160 | \(genDirectSwitchCases(cases, name.value)) 161 | default: 162 | break 163 | } 164 | return nil 165 | } 166 | \(genDirectAsProperties(cases)) 167 | } 168 | var unionCase: Int8 { 169 | switch self { 170 | \(cases.enumerated().map{" case .with\($0.element.value)(_): return \($0.offset + 1)"}.joined(separator: "\n")) 171 | } 172 | } 173 | func insert(_ builder: FlatBuffersBuilder) throws -> Offset { 174 | switch self { 175 | \(cases.enumerated().map{" case .with\($0.element.value)(let o): return try o.insert(builder)"}.joined(separator: "\n")) 176 | } 177 | } 178 | \(genAsProperties(cases)) 179 | \(genValueProperty(cases)) 180 | } 181 | """ 182 | } 183 | 184 | func genFromJsonExtension() -> String { 185 | 186 | func genSwitchCases(_ casses: [Ident]) -> String { 187 | var statements = [String]() 188 | for c in casses { 189 | statements.append(""" 190 | case "\(c.value)": 191 | guard let o = \(c.value).from(jsonObject: object) else { return nil } 192 | return \(name.value).with\(c.value)(o) 193 | """) 194 | } 195 | return statements.joined(separator: "\n") 196 | } 197 | 198 | return """ 199 | extension \(name.value) { 200 | static func from(type: String?, jsonObject: [String: Any]?) -> \(name.value)? { 201 | guard let type = type, let object = jsonObject else { return nil } 202 | switch type { 203 | \(genSwitchCases(cases)) 204 | default: 205 | return nil 206 | } 207 | } 208 | } 209 | """ 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Sources/FlatBuffersSwiftCodeGenCore/ValueLiteral.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ValueLiteral.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct ValueLiteral { 12 | let value: String 13 | } 14 | 15 | extension ValueLiteral: ASTNode { 16 | static func with(pointer: UnsafePointer, length: Int) -> (ValueLiteral, UnsafePointer)? { 17 | guard let p1 = eatWhiteSpace(pointer, length: length) else {return nil} 18 | var length = length - pointer.distance(to: p1) 19 | if let p2 = eat("\"", from: p1, length: length) { 20 | length -= p1.distance(to: p2) 21 | var p3 = p2 22 | while p3.pointee != UInt8(34) { 23 | p3 = p3.advanced(by: 1) 24 | if p2.distance(to: p3) > length { 25 | return nil 26 | } 27 | } 28 | guard let p4 = eat("\"", from: p3, length: length) else {return nil} 29 | guard let value = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: p1), length: p1.distance(to: p4), encoding: .utf8, freeWhenDone: false) else { 30 | return nil 31 | } 32 | return (ValueLiteral(value: value), p4) 33 | } 34 | if p1.pointee == UInt8(45) || _0_9.contains(p1.pointee) { 35 | var p2 = p1 36 | while p2.pointee == UInt8(45) // - 37 | || p2.pointee == UInt8(43) // + 38 | || p2.pointee == UInt8(46) // . 39 | || p2.pointee == UInt8(69) // E 40 | || p2.pointee == UInt8(101) // e 41 | || _0_9.contains(p2.pointee) { 42 | p2 = p2.advanced(by: 1) 43 | if p1.distance(to: p2) > length { 44 | return nil 45 | } 46 | } 47 | guard let value = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: p1), length: p1.distance(to: p2), encoding: .utf8, freeWhenDone: false) else { 48 | return nil 49 | } 50 | return (ValueLiteral(value: value), p2) 51 | } 52 | if let p2 = eat("true", from: p1, length: length) { 53 | return (ValueLiteral(value: "true"), p2) 54 | } 55 | if let p2 = eat("false", from: p1, length: length) { 56 | return (ValueLiteral(value: "false"), p2) 57 | } 58 | return nil 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/ASTNodeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ASTNodeTests.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class ASTNodeTests: XCTestCase { 14 | 15 | func testEmptyString() { 16 | let s: StaticString = """ 17 | 18 | 19 | \t 20 | """ 21 | let result = eatWhiteSpace(s.utf8Start, length: s.utf8CodeUnitCount) 22 | XCTAssertNil(result) 23 | } 24 | 25 | func testEatWhiteSpaceTillString() { 26 | let s: StaticString = """ 27 | 28 | 29 | \t 30 | foo 31 | """ 32 | let result = eatWhiteSpace(s.utf8Start, length: s.utf8CodeUnitCount) 33 | XCTAssertNotNil(result) 34 | XCTAssertEqual(s.utf8CodeUnitCount - 3, s.utf8Start.distance(to: result!)) 35 | } 36 | 37 | func testEatString(){ 38 | let s: StaticString = """ 39 | \t \n 40 | foo 41 | """ 42 | let result = eat("foo", from: s.utf8Start, length: s.utf8CodeUnitCount) 43 | XCTAssertNotNil(result) 44 | XCTAssertEqual(s.utf8CodeUnitCount, s.utf8Start.distance(to: result!)) 45 | } 46 | 47 | static var allTests = [ 48 | ("testEmptyString", testEmptyString), 49 | ("testEatWhiteSpaceTillString", testEatWhiteSpaceTillString), 50 | ("testEatString", testEatString) 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/CommentTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 30.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class CommentTests: XCTestCase { 14 | 15 | func testComment() { 16 | let s: StaticString = """ 17 | // hello there 18 | """ 19 | let result = Comment.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 20 | XCTAssertNotNil(result) 21 | XCTAssertEqual(result?.0.value, " hello there") 22 | } 23 | 24 | func testCommentWithSomeTextOnOtherLine() { 25 | let s: StaticString = "// this is something\nbla" 26 | let result = Comment.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 27 | XCTAssertNotNil(result) 28 | XCTAssertEqual(result?.0.value, " this is something") 29 | } 30 | 31 | static var allTests = [ 32 | ("testComment", testComment), 33 | ("testCommentWithSomeTextOnOtherLine", testCommentWithSomeTextOnOtherLine) 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/EnumTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EnumTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 18.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class EnumTests: XCTestCase { 14 | 15 | func testEnum() { 16 | let s: StaticString = """ 17 | // my comment 18 | enum Foo : byte (something) { 19 | bar1 = 1, bar2, bar3 20 | } 21 | """ 22 | let result = Enum.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 23 | XCTAssertNotNil(result) 24 | XCTAssertEqual(result?.0.name.value, "Foo") 25 | XCTAssertEqual(result?.0.type.scalar, .i8) 26 | XCTAssertEqual(result?.0.metaData?.values[0].0.value, "something") 27 | XCTAssertEqual(result?.0.cases.count, 3) 28 | XCTAssertEqual(result?.0.cases[0].ident.value, "bar1") 29 | XCTAssertEqual(result?.0.cases[0].value?.value, "1") 30 | XCTAssertEqual(result?.0.cases[1].ident.value, "bar2") 31 | XCTAssertNil(result?.0.cases[1].value) 32 | XCTAssertEqual(result?.0.cases[2].ident.value, "bar3") 33 | XCTAssertNil(result?.0.cases[2].value) 34 | XCTAssertEqual(result?.0.comments.count, 1) 35 | XCTAssertEqual(result?.0.comments[0].value, " my comment") 36 | } 37 | 38 | func testEnumToSwift() { 39 | let s: StaticString = """ 40 | enum Foo : byte { 41 | bar1, bar2 = 3, bar3 42 | } 43 | """ 44 | let result = Enum.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 45 | let stringResult = result?.0.swift 46 | let expected = """ 47 | public enum Foo: Int8, FlatBuffersEnum { 48 | case bar1, bar2 = 3, bar3 49 | public static func fromScalar(_ scalar: T) -> Foo? where T : Scalar { 50 | guard let value = scalar as? RawValue else { 51 | return nil 52 | } 53 | return Foo(rawValue: value) 54 | } 55 | } 56 | """ 57 | XCTAssertEqual(expected, stringResult) 58 | } 59 | 60 | func testEnumFromJsonValueExtension() { 61 | let s: StaticString = """ 62 | enum Foo : byte { 63 | bar1, bar2 = 3, bar3 64 | } 65 | """ 66 | let result = Enum.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 67 | let stringResult = result?.0.genFromJsonValue() 68 | let expected = """ 69 | extension Foo { 70 | static func from(jsonValue: Any?) -> Foo? { 71 | if let string = jsonValue as? String { 72 | if string == "bar1" { 73 | return .bar1 74 | } 75 | if string == "bar2" { 76 | return .bar2 77 | } 78 | if string == "bar3" { 79 | return .bar3 80 | } 81 | } 82 | if let int = jsonValue as? Int, 83 | let rawValue = Int8(exactly: int) { 84 | return Foo.init(rawValue: rawValue) 85 | } 86 | return nil 87 | } 88 | } 89 | """ 90 | print(stringResult!) 91 | XCTAssertEqual(expected, stringResult!) 92 | 93 | } 94 | 95 | static var allTests = [ 96 | ("testEnum", testEnum), 97 | ("testEnumToSwift", testEnumToSwift), 98 | ("testEnumFromJsonValueExtension", testEnumFromJsonValueExtension) 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/FieldTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FieldTests.swift 3 | // FlatBuffersSwift 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class FieldTests: XCTestCase { 14 | 15 | func testReadField() { 16 | let s: StaticString = """ 17 | foo: int; 18 | """ 19 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 20 | XCTAssertNotNil(result) 21 | XCTAssertEqual(result?.0.name.value, "foo") 22 | XCTAssertEqual(result?.0.type.scalar, .i32) 23 | } 24 | 25 | func testReadFieldWithMetaData() { 26 | let s: StaticString = """ 27 | foo: int (id: 2); 28 | """ 29 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 30 | XCTAssertNotNil(result) 31 | XCTAssertEqual(result?.0.name.value, "foo") 32 | XCTAssertEqual(result?.0.type.scalar, .i32) 33 | XCTAssertEqual(result?.0.metaData?.values[0].0.value, "id") 34 | XCTAssertEqual(result?.0.metaData?.values[0].1?.value, "2") 35 | } 36 | 37 | func testReadFieldWithDefault() { 38 | let s: StaticString = """ 39 | foo: int = 123; 40 | """ 41 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 42 | XCTAssertNotNil(result) 43 | XCTAssertEqual(result?.0.name.value, "foo") 44 | XCTAssertEqual(result?.0.type.scalar, .i32) 45 | XCTAssertEqual(result?.0.defaultValue?.value, "123") 46 | XCTAssertNil(result?.0.defaultIdent) 47 | XCTAssert(result!.0.isDeprecated == false) 48 | XCTAssertEqual(result!.0.fieldName, "foo") 49 | } 50 | 51 | func testReadFieldWithDefaultAndMetaData() { 52 | let s: StaticString = """ 53 | foo: int = 123 (deprecated); 54 | """ 55 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 56 | XCTAssertNotNil(result) 57 | XCTAssertEqual(result?.0.name.value, "foo") 58 | XCTAssertEqual(result?.0.type.scalar, .i32) 59 | XCTAssertEqual(result?.0.defaultValue?.value, "123") 60 | XCTAssertNil(result?.0.defaultIdent) 61 | XCTAssertEqual(result?.0.metaData?.values[0].0.value, "deprecated") 62 | XCTAssert(result!.0.isDeprecated) 63 | XCTAssertEqual(result!.0.fieldName, "__foo") 64 | } 65 | 66 | func testReadFieldWithDefaultIdent() { 67 | let s: StaticString = """ 68 | foo: Greeting = hi; 69 | """ 70 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 71 | XCTAssertNotNil(result) 72 | XCTAssertEqual(result?.0.name.value, "foo") 73 | XCTAssertEqual(result?.0.type.ref?.value, "Greeting") 74 | XCTAssertEqual(result?.0.defaultIdent?.value, "hi") 75 | XCTAssertNil(result?.0.defaultValue) 76 | } 77 | 78 | func testReadBadField0() { 79 | let s: StaticString = """ 80 | 81 | """ 82 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 83 | XCTAssertNil(result) 84 | 85 | } 86 | func testReadBadField1() { 87 | let s: StaticString = """ 88 | foo 89 | """ 90 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 91 | XCTAssertNil(result) 92 | 93 | } 94 | func testReadBadField2() { 95 | let s: StaticString = """ 96 | foo: 97 | """ 98 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 99 | XCTAssertNil(result) 100 | } 101 | func testReadBadField3() { 102 | let s: StaticString = """ 103 | foo:int 104 | """ 105 | let result = Field.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 106 | XCTAssertNil(result) 107 | } 108 | 109 | static var allTests = [ 110 | ("testReadField", testReadField), 111 | ("testReadFieldWithMetaData", testReadFieldWithMetaData), 112 | ("testReadFieldWithDefault", testReadFieldWithDefault), 113 | ("testReadFieldWithDefaultAndMetaData", testReadFieldWithDefaultAndMetaData), 114 | ("testReadFieldWithDefaultIdent", testReadFieldWithDefaultIdent), 115 | ("testReadBadField0", testReadBadField0), 116 | ("testReadBadField1", testReadBadField1), 117 | ("testReadBadField2", testReadBadField2), 118 | ("testReadBadField3", testReadBadField3), 119 | ] 120 | } 121 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/IdentTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IdentTests.swift 3 | // CodeGen 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Foundation 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | import XCTest 14 | 15 | class IdentTests: XCTestCase { 16 | 17 | func testReadLowerCaseIdent() { 18 | let s: StaticString = """ 19 | 20 | table 21 | """ 22 | let result = Ident.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 23 | XCTAssertNotNil(result) 24 | XCTAssertEqual(result?.0.value, "table") 25 | } 26 | 27 | func testReadCapitalisedIdent() { 28 | let s: StaticString = """ 29 | 30 | Table 31 | """ 32 | let result = Ident.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 33 | XCTAssertNotNil(result) 34 | XCTAssertEqual(result?.0.value, "Table") 35 | 36 | } 37 | 38 | func testReadUnderscoredIdent() { 39 | let s: StaticString = """ 40 | 41 | _Table 42 | """ 43 | let result = Ident.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 44 | XCTAssertNotNil(result) 45 | XCTAssertEqual(result?.0.value, "_Table") 46 | 47 | } 48 | 49 | func testReadComplexIdent() { 50 | let s: StaticString = """ 51 | 52 | _Table_01_FOR_my_own1234 53 | """ 54 | let result = Ident.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 55 | XCTAssertNotNil(result) 56 | XCTAssertEqual(result?.0.value, "_Table_01_FOR_my_own1234") 57 | 58 | } 59 | 60 | func testIgnoreIdentStartingWithNumber() { 61 | let s: StaticString = """ 62 | 63 | 1table 64 | """ 65 | let result = Ident.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 66 | XCTAssertNil(result) 67 | } 68 | 69 | static var allTests = [ 70 | ("testReadLowerCaseIdent", testReadLowerCaseIdent), 71 | ("testReadCapitalisedIdent", testReadCapitalisedIdent), 72 | ("testReadUnderscoredIdent", testReadUnderscoredIdent), 73 | ("testReadComplexIdent", testReadComplexIdent), 74 | ("testIgnoreIdentStartingWithNumber", testIgnoreIdentStartingWithNumber), 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/MetaDataTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MetaDataTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 17.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class MetaDataTests: XCTestCase { 14 | 15 | func testReadMetaData() { 16 | let s: StaticString = """ 17 | (deprecated, id:1, meta : "hi") 18 | """ 19 | let result = MetaData.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 20 | XCTAssertNotNil(result) 21 | XCTAssertEqual(result?.0.values.count, 3) 22 | XCTAssertEqual(result?.0.values[0].0.value, "deprecated") 23 | XCTAssertNil(result?.0.values[0].1) 24 | XCTAssertEqual(result?.0.values[1].0.value, "id") 25 | XCTAssertEqual(result?.0.values[1].1?.value, "1") 26 | XCTAssertEqual(result?.0.values[2].0.value, "meta") 27 | XCTAssertEqual(result?.0.values[2].1?.value, "\"hi\"") 28 | } 29 | 30 | static var allTests = [ 31 | ("testReadMetaData", testReadMetaData), 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/SchemaTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SchemaTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 19.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class SchemaTests: XCTestCase { 14 | 15 | func testSchema() { 16 | let s: StaticString = """ 17 | // sample 18 | 19 | namespace MyGame; 20 | 21 | attribute "priority"; 22 | 23 | enum Color : byte { Red = 1, Green, Blue } 24 | 25 | union Any { Monster, Weapon, Pickup } 26 | 27 | struct Vec3 { 28 | x:float; 29 | y:float; 30 | z:float; 31 | } 32 | 33 | table Monster { 34 | pos:Vec3; 35 | mana:short = 150; 36 | hp:short = 100; 37 | name:string; 38 | // this is a deprected field 39 | friendly:bool = false (deprecated, priority: 1); 40 | inventory:[ubyte]; 41 | color:Color = Blue; 42 | test:Any; 43 | } 44 | 45 | table T1 { 46 | name: string; 47 | } 48 | 49 | // anothe comment 50 | root_type Monster; 51 | """ 52 | let result = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 53 | XCTAssertNotNil(result) 54 | XCTAssertEqual(result?.0.rootType?.ident.value, "Monster") 55 | XCTAssertEqual(result?.0.namespace?.parts.count, 1) 56 | XCTAssertEqual(result?.0.namespace?.parts[0].value, "MyGame") 57 | XCTAssertEqual(result?.0.attributes.count, 1) 58 | XCTAssertEqual(result?.0.attributes[0].value.value, "priority") 59 | XCTAssertEqual(result?.0.enums.count, 1) 60 | XCTAssertEqual(result?.0.enums[0].name.value, "Color") 61 | XCTAssertEqual(result?.0.unions.count, 1) 62 | XCTAssertEqual(result?.0.unions[0].name.value, "Any") 63 | XCTAssertEqual(result?.0.structs.count, 1) 64 | XCTAssertEqual(result?.0.structs[0].name.value, "Vec3") 65 | XCTAssertEqual(result?.0.tables.count, 2) 66 | XCTAssertEqual(result?.0.tables[0].name.value, "Monster") 67 | XCTAssertEqual(result?.0.tables[1].name.value, "T1") 68 | } 69 | 70 | func testIdentLookup() { 71 | let s: StaticString = """ 72 | enum E1: byte {A, B} 73 | table T1 {n: int;} 74 | table T2 {b: bool;} 75 | struct S1 {a:int;} 76 | table T3 {t1: T1;} 77 | union U1 {T1, T2} 78 | enum E2: byte {A, B} 79 | root_type T1; 80 | """ 81 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 82 | let result = schema?.0.identLookup 83 | 84 | XCTAssertEqual(result?.tables.count, 3) 85 | XCTAssertNotNil(result?.tables["T1"]) 86 | XCTAssertNotNil(result?.tables["T2"]) 87 | XCTAssertNotNil(result?.tables["T3"]) 88 | XCTAssertEqual(result?.enums.count, 2) 89 | XCTAssertNotNil(result?.enums["E1"]) 90 | XCTAssertNotNil(result?.enums["E2"]) 91 | XCTAssertEqual(result?.structs.count, 1) 92 | XCTAssertNotNil(result?.structs["S1"]) 93 | XCTAssertEqual(result?.unions.count, 1) 94 | XCTAssertNotNil(result?.unions["U1"]) 95 | } 96 | 97 | func testHasRecursion1(){ 98 | let s: StaticString = """ 99 | table T1 {t: T2;} 100 | table T2 {b: bool;} 101 | root_type T1; 102 | """ 103 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 104 | let result = schema?.0.hasRecursions 105 | XCTAssert(result == false) 106 | } 107 | func testHasRecursion2(){ 108 | let s: StaticString = """ 109 | table T1 {t: T2;} 110 | table T2 {t: T1;} 111 | root_type T1; 112 | """ 113 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 114 | let result = schema?.0.hasRecursions 115 | XCTAssert(result == true) 116 | } 117 | 118 | func testHasRecursion3(){ 119 | let s: StaticString = """ 120 | table T1 {i: int; t: T2;} 121 | table T2 {b: bool; t: T1;} 122 | root_type T1; 123 | """ 124 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 125 | let result = schema?.0.hasRecursions 126 | XCTAssert(result == true) 127 | } 128 | 129 | func testHasRecursion4(){ 130 | let s: StaticString = """ 131 | table T1 {t1: T1;} 132 | table T2 {b: bool; t: T1;} 133 | root_type T1; 134 | """ 135 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 136 | let result = schema?.0.hasRecursions 137 | XCTAssert(result == true) 138 | } 139 | 140 | func testHasRecursion5(){ 141 | let s: StaticString = """ 142 | table T1 {t1: T11;} 143 | table T11 {i: int;} 144 | table T2 {b: bool; t: T1;} 145 | root_type T1; 146 | """ 147 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 148 | let result = schema?.0.hasRecursions 149 | XCTAssert(result == false) 150 | } 151 | 152 | func testHasRecursion6(){ 153 | let s: StaticString = """ 154 | table T1 {u: U;} 155 | table T11 {i: int;} 156 | table T2 {b: bool; t: T1;} 157 | union U {T11, T2} 158 | root_type T1; 159 | """ 160 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 161 | let result = schema?.0.hasRecursions 162 | XCTAssert(result == true) 163 | } 164 | 165 | func testGenerate(){ 166 | let s: StaticString = """ 167 | table T1 {u: U; s: S1;} 168 | table T11 {i: int; s: S1;e:E2;} 169 | table T2 {b: bool; t: T1;} 170 | union U {T11, T2} 171 | struct S1 {a:int;s:S2;} 172 | struct S2 {b:bool;e:E2;} 173 | table T3 {t1: T1;} 174 | enum E2: byte {A, B} 175 | root_type T1; 176 | """ 177 | let expected = """ 178 | import Foundation 179 | import FlatBuffersSwift 180 | 181 | public final class T1 { 182 | public var u: U? 183 | public var s: S1? 184 | public init(u: U? = nil, s: S1? = nil) { 185 | self.u = u 186 | self.s = s 187 | } 188 | public struct Direct : Hashable, FlatBuffersDirectAccess { 189 | fileprivate let _reader : T 190 | fileprivate let _myOffset : Offset 191 | } 192 | } 193 | extension T1.Direct { 194 | public init?(reader: R, myOffset: Offset? = nil) { 195 | guard let reader = reader as? T else { 196 | return nil 197 | } 198 | self._reader = reader 199 | if let myOffset = myOffset { 200 | self._myOffset = myOffset 201 | } else { 202 | if let rootOffset = reader.rootObjectOffset { 203 | self._myOffset = rootOffset 204 | } else { 205 | return nil 206 | } 207 | } 208 | } 209 | public var hashValue: Int { return Int(_myOffset) } 210 | public static func ==(t1 : T1.Direct, t2 : T1.Direct) -> Bool { 211 | return t1._reader.isEqual(other: t2._reader) && t1._myOffset == t2._myOffset 212 | } 213 | public var u: U.Direct? { 214 | 215 | return U.Direct.from(reader: _reader, propertyIndex : 0, objectOffset : _myOffset) 216 | } 217 | public var s: S1? { 218 | 219 | return _reader.get(objectOffset: _myOffset, propertyIndex: 2) 220 | } 221 | } 222 | extension T1 { 223 | public static func from(data: Data) -> T1? { 224 | let reader = FlatBuffersMemoryReader(data: data, withoutCopy: false) 225 | return T1.from(selfReader: Direct(reader: reader)) 226 | } 227 | fileprivate static func from(selfReader: Direct?) -> T1? { 228 | guard let selfReader = selfReader else { 229 | return nil 230 | } 231 | if let o = selfReader._reader.cache?.objectPool[selfReader._myOffset] as? T1 { 232 | return o 233 | } 234 | let o = T1() 235 | selfReader._reader.cache?.objectPool[selfReader._myOffset] = o 236 | o.u = U.from(selfReader: selfReader.u) 237 | o.s = selfReader.s 238 | 239 | return o 240 | } 241 | } 242 | extension FlatBuffersBuilder { 243 | public func insertT1(u_type: Int8 = 0, u: Offset? = nil, s: S1? = nil) throws -> (Offset, [Int?]) { 244 | var valueCursors = [Int?](repeating: nil, count: 3) 245 | try self.startObject(withPropertyCount: 3) 246 | valueCursors[0] = try self.insert(value: u_type, defaultValue: 0, toStartedObjectAt: 0) 247 | if let u = u { 248 | valueCursors[1] = try self.insert(offset: u, toStartedObjectAt: 1) 249 | } 250 | if let s = s { 251 | self.insert(value: s) 252 | valueCursors[2] = try self.insertCurrentOffsetAsProperty(toStartedObjectAt: 2) 253 | } 254 | return try (self.endObject(), valueCursors) 255 | } 256 | } 257 | extension T1 { 258 | func insert(_ builder : FlatBuffersBuilder) throws -> Offset { 259 | if builder.options.uniqueTables { 260 | if let myOffset = builder.cache[ObjectIdentifier(self)] { 261 | return myOffset 262 | } 263 | } 264 | if builder.inProgress.contains(ObjectIdentifier(self)){ 265 | return 0 266 | } 267 | builder.inProgress.insert(ObjectIdentifier(self)) 268 | let u = try self.u?.insert(builder) 269 | let u_type = self.u?.unionCase ?? 0 270 | let (myOffset, valueCursors) = try builder.insertT1( 271 | u_type: u_type, 272 | u: u, 273 | s: s 274 | ) 275 | if u == 0, 276 | let o = self.u, 277 | let cursor = valueCursors[1] { 278 | builder.deferedBindings.append((o.value, cursor)) 279 | } 280 | if builder.options.uniqueTables { 281 | builder.cache[ObjectIdentifier(self)] = myOffset 282 | } 283 | builder.inProgress.remove(ObjectIdentifier(self)) 284 | return myOffset 285 | } 286 | public func makeData(withOptions options : FlatBuffersBuilderOptions = FlatBuffersBuilderOptions()) throws -> Data { 287 | let builder = FlatBuffersBuilder(options: options) 288 | let offset = try insert(builder) 289 | try builder.finish(offset: offset, fileIdentifier: nil) 290 | try performLateBindings(builder) 291 | return builder.makeData 292 | } 293 | } 294 | extension T1 { 295 | public static func from(jsonObject: [String: Any]?) -> T1? { 296 | guard let object = jsonObject else { return nil } 297 | let u = U.from(type:object["u_type"] as? String, jsonObject: object["u"] as? [String: Any]) 298 | let s = S1.from(jsonObject: object["s"] as? [String: Any]) 299 | return T1 ( 300 | u: u, 301 | s: s 302 | ) 303 | } 304 | } 305 | public enum U { 306 | case withT11(T11), withT2(T2) 307 | fileprivate static func from(selfReader: U.Direct?) -> U? { 308 | guard let selfReader = selfReader else { 309 | return nil 310 | } 311 | switch selfReader { 312 | case .withT11(let o): 313 | guard let o1 = T11.from(selfReader: o) else { 314 | return nil 315 | } 316 | return .withT11(o1) 317 | case .withT2(let o): 318 | guard let o1 = T2.from(selfReader: o) else { 319 | return nil 320 | } 321 | return .withT2(o1) 322 | } 323 | } 324 | public enum Direct { 325 | case withT11(T11.Direct), withT2(T2.Direct) 326 | fileprivate static func from(reader: R, propertyIndex : Int, objectOffset : Offset?) -> U.Direct? { 327 | guard let objectOffset = objectOffset else { 328 | return nil 329 | } 330 | let unionCase : Int8 = reader.get(objectOffset: objectOffset, propertyIndex: propertyIndex, defaultValue: 0) 331 | guard let caseObjectOffset : Offset = reader.offset(objectOffset: objectOffset, propertyIndex:propertyIndex + 1) else { 332 | return nil 333 | } 334 | switch unionCase { 335 | case 1: 336 | guard let o = T11.Direct(reader: reader, myOffset: caseObjectOffset) else { 337 | return nil 338 | } 339 | return U.Direct.withT11(o) 340 | case 2: 341 | guard let o = T2.Direct(reader: reader, myOffset: caseObjectOffset) else { 342 | return nil 343 | } 344 | return U.Direct.withT2(o) 345 | default: 346 | break 347 | } 348 | return nil 349 | } 350 | public var asT11: T11.Direct? { 351 | switch self { 352 | case .withT11(let v): 353 | return v 354 | default: 355 | return nil 356 | } 357 | } 358 | public var asT2: T2.Direct? { 359 | switch self { 360 | case .withT2(let v): 361 | return v 362 | default: 363 | return nil 364 | } 365 | } 366 | } 367 | var unionCase: Int8 { 368 | switch self { 369 | case .withT11(_): return 1 370 | case .withT2(_): return 2 371 | } 372 | } 373 | func insert(_ builder: FlatBuffersBuilder) throws -> Offset { 374 | switch self { 375 | case .withT11(let o): return try o.insert(builder) 376 | case .withT2(let o): return try o.insert(builder) 377 | } 378 | } 379 | public var asT11: T11? { 380 | switch self { 381 | case .withT11(let v): 382 | return v 383 | default: 384 | return nil 385 | } 386 | } 387 | public var asT2: T2? { 388 | switch self { 389 | case .withT2(let v): 390 | return v 391 | default: 392 | return nil 393 | } 394 | } 395 | public var value: AnyObject { 396 | switch self { 397 | case .withT11(let v): return v 398 | case .withT2(let v): return v 399 | } 400 | } 401 | } 402 | extension U { 403 | static func from(type: String?, jsonObject: [String: Any]?) -> U? { 404 | guard let type = type, let object = jsonObject else { return nil } 405 | switch type { 406 | case "T11": 407 | guard let o = T11.from(jsonObject: object) else { return nil } 408 | return U.withT11(o) 409 | case "T2": 410 | guard let o = T2.from(jsonObject: object) else { return nil } 411 | return U.withT2(o) 412 | default: 413 | return nil 414 | } 415 | } 416 | } 417 | public final class T11 { 418 | public var i: Int32 419 | public var s: S1? 420 | public var e: E2? 421 | public init(i: Int32 = 0, s: S1? = nil, e: E2? = E2.A) { 422 | self.i = i 423 | self.s = s 424 | self.e = e 425 | } 426 | public struct Direct : Hashable, FlatBuffersDirectAccess { 427 | fileprivate let _reader : T 428 | fileprivate let _myOffset : Offset 429 | } 430 | } 431 | extension T11.Direct { 432 | public init?(reader: R, myOffset: Offset? = nil) { 433 | guard let reader = reader as? T else { 434 | return nil 435 | } 436 | self._reader = reader 437 | if let myOffset = myOffset { 438 | self._myOffset = myOffset 439 | } else { 440 | if let rootOffset = reader.rootObjectOffset { 441 | self._myOffset = rootOffset 442 | } else { 443 | return nil 444 | } 445 | } 446 | } 447 | public var hashValue: Int { return Int(_myOffset) } 448 | public static func ==(t1 : T11.Direct, t2 : T11.Direct) -> Bool { 449 | return t1._reader.isEqual(other: t2._reader) && t1._myOffset == t2._myOffset 450 | } 451 | public var i: Int32 { 452 | 453 | return _reader.get(objectOffset: _myOffset, propertyIndex: 0, defaultValue: 0) 454 | } 455 | public var s: S1? { 456 | 457 | return _reader.get(objectOffset: _myOffset, propertyIndex: 1) 458 | } 459 | public var e: E2? { 460 | 461 | return E2(rawValue:_reader.get(objectOffset: _myOffset, propertyIndex: 2, defaultValue: E2.A.rawValue)) 462 | } 463 | } 464 | extension T11 { 465 | 466 | fileprivate static func from(selfReader: Direct?) -> T11? { 467 | guard let selfReader = selfReader else { 468 | return nil 469 | } 470 | if let o = selfReader._reader.cache?.objectPool[selfReader._myOffset] as? T11 { 471 | return o 472 | } 473 | let o = T11() 474 | selfReader._reader.cache?.objectPool[selfReader._myOffset] = o 475 | o.i = selfReader.i 476 | o.s = selfReader.s 477 | o.e = selfReader.e 478 | 479 | return o 480 | } 481 | } 482 | extension FlatBuffersBuilder { 483 | public func insertT11(i: Int32 = 0, s: S1? = nil, e: E2 = E2.A) throws -> (Offset, [Int?]) { 484 | var valueCursors = [Int?](repeating: nil, count: 3) 485 | try self.startObject(withPropertyCount: 3) 486 | valueCursors[2] = try self.insert(value: e.rawValue, defaultValue: E2.A.rawValue, toStartedObjectAt: 2) 487 | valueCursors[0] = try self.insert(value: i, defaultValue: 0, toStartedObjectAt: 0) 488 | if let s = s { 489 | self.insert(value: s) 490 | valueCursors[1] = try self.insertCurrentOffsetAsProperty(toStartedObjectAt: 1) 491 | } 492 | return try (self.endObject(), valueCursors) 493 | } 494 | } 495 | extension T11 { 496 | func insert(_ builder : FlatBuffersBuilder) throws -> Offset { 497 | if builder.options.uniqueTables { 498 | if let myOffset = builder.cache[ObjectIdentifier(self)] { 499 | return myOffset 500 | } 501 | } 502 | 503 | 504 | let (myOffset, _) = try builder.insertT11( 505 | i: i, 506 | s: s, 507 | e: e ?? E2.A 508 | ) 509 | 510 | if builder.options.uniqueTables { 511 | builder.cache[ObjectIdentifier(self)] = myOffset 512 | } 513 | 514 | return myOffset 515 | } 516 | 517 | } 518 | extension T11 { 519 | public static func from(jsonObject: [String: Any]?) -> T11? { 520 | guard let object = jsonObject else { return nil } 521 | let i = (object["i"] as? Int).flatMap { Int32(exactly: $0) } ?? 0 522 | let s = S1.from(jsonObject: object["s"] as? [String: Any]) 523 | let e = E2.from(jsonValue: object["e"]) 524 | return T11 ( 525 | i: i, 526 | s: s, 527 | e: e 528 | ) 529 | } 530 | } 531 | public struct S1: Scalar { 532 | public let a: Int32 533 | public let s: S2 534 | public static func ==(v1:S1, v2:S1) -> Bool { 535 | return v1.a==v2.a && v1.s==v2.s 536 | } 537 | } 538 | extension S1 { 539 | static func from(jsonObject: [String: Any]?) -> S1? { 540 | guard let object = jsonObject else { return nil } 541 | guard let aInt = object["a"] as? Int, let a = Int32(exactly: aInt) else { return nil } 542 | guard let s = S2.from(jsonObject: object["s"] as? [String: Any]) else { return nil } 543 | return S1( 544 | a: a, 545 | s: s 546 | ) 547 | } 548 | } 549 | public struct S2: Scalar { 550 | public let b: Bool 551 | public let e: E2 552 | public static func ==(v1:S2, v2:S2) -> Bool { 553 | return v1.b==v2.b && v1.e==v2.e 554 | } 555 | } 556 | extension S2 { 557 | static func from(jsonObject: [String: Any]?) -> S2? { 558 | guard let object = jsonObject else { return nil } 559 | guard let b = object["b"] as? Bool else { return nil } 560 | guard let e = E2.from(jsonValue: object["e"]) else { return nil } 561 | return S2( 562 | b: b, 563 | e: e 564 | ) 565 | } 566 | } 567 | public enum E2: Int8, FlatBuffersEnum { 568 | case A, B 569 | public static func fromScalar(_ scalar: T) -> E2? where T : Scalar { 570 | guard let value = scalar as? RawValue else { 571 | return nil 572 | } 573 | return E2(rawValue: value) 574 | } 575 | } 576 | extension E2 { 577 | static func from(jsonValue: Any?) -> E2? { 578 | if let string = jsonValue as? String { 579 | if string == "A" { 580 | return .A 581 | } 582 | if string == "B" { 583 | return .B 584 | } 585 | } 586 | if let int = jsonValue as? Int, 587 | let rawValue = Int8(exactly: int) { 588 | return E2.init(rawValue: rawValue) 589 | } 590 | return nil 591 | } 592 | } 593 | public final class T2 { 594 | public var b: Bool 595 | public var t: T1? 596 | public init(b: Bool = false, t: T1? = nil) { 597 | self.b = b 598 | self.t = t 599 | } 600 | public struct Direct : Hashable, FlatBuffersDirectAccess { 601 | fileprivate let _reader : T 602 | fileprivate let _myOffset : Offset 603 | } 604 | } 605 | extension T2.Direct { 606 | public init?(reader: R, myOffset: Offset? = nil) { 607 | guard let reader = reader as? T else { 608 | return nil 609 | } 610 | self._reader = reader 611 | if let myOffset = myOffset { 612 | self._myOffset = myOffset 613 | } else { 614 | if let rootOffset = reader.rootObjectOffset { 615 | self._myOffset = rootOffset 616 | } else { 617 | return nil 618 | } 619 | } 620 | } 621 | public var hashValue: Int { return Int(_myOffset) } 622 | public static func ==(t1 : T2.Direct, t2 : T2.Direct) -> Bool { 623 | return t1._reader.isEqual(other: t2._reader) && t1._myOffset == t2._myOffset 624 | } 625 | public var b: Bool { 626 | 627 | return _reader.get(objectOffset: _myOffset, propertyIndex: 0, defaultValue: false) 628 | } 629 | public var t: T1.Direct? { 630 | guard let offset = _reader.offset(objectOffset: _myOffset, propertyIndex:1) else {return nil} 631 | return T1.Direct(reader: _reader, myOffset: offset) 632 | } 633 | } 634 | extension T2 { 635 | 636 | fileprivate static func from(selfReader: Direct?) -> T2? { 637 | guard let selfReader = selfReader else { 638 | return nil 639 | } 640 | if let o = selfReader._reader.cache?.objectPool[selfReader._myOffset] as? T2 { 641 | return o 642 | } 643 | let o = T2() 644 | selfReader._reader.cache?.objectPool[selfReader._myOffset] = o 645 | o.b = selfReader.b 646 | o.t = T1.from(selfReader:selfReader.t) 647 | 648 | return o 649 | } 650 | } 651 | extension FlatBuffersBuilder { 652 | public func insertT2(b: Bool = false, t: Offset? = nil) throws -> (Offset, [Int?]) { 653 | var valueCursors = [Int?](repeating: nil, count: 2) 654 | try self.startObject(withPropertyCount: 2) 655 | valueCursors[0] = try self.insert(value: b, defaultValue: false, toStartedObjectAt: 0) 656 | if let t = t { 657 | valueCursors[1] = try self.insert(offset: t, toStartedObjectAt: 1) 658 | } 659 | return try (self.endObject(), valueCursors) 660 | } 661 | } 662 | extension T2 { 663 | func insert(_ builder : FlatBuffersBuilder) throws -> Offset { 664 | if builder.options.uniqueTables { 665 | if let myOffset = builder.cache[ObjectIdentifier(self)] { 666 | return myOffset 667 | } 668 | } 669 | if builder.inProgress.contains(ObjectIdentifier(self)){ 670 | return 0 671 | } 672 | builder.inProgress.insert(ObjectIdentifier(self)) 673 | let t = try self.t?.insert(builder) 674 | let (myOffset, valueCursors) = try builder.insertT2( 675 | b: b, 676 | t: t 677 | ) 678 | if t == 0, 679 | let o = self.t, 680 | let cursor = valueCursors[1] { 681 | builder.deferedBindings.append((o, cursor)) 682 | } 683 | if builder.options.uniqueTables { 684 | builder.cache[ObjectIdentifier(self)] = myOffset 685 | } 686 | builder.inProgress.remove(ObjectIdentifier(self)) 687 | return myOffset 688 | } 689 | 690 | } 691 | extension T2 { 692 | public static func from(jsonObject: [String: Any]?) -> T2? { 693 | guard let object = jsonObject else { return nil } 694 | let b = object["b"] as? Bool 695 | let t = T1.from(jsonObject: object["t"] as? [String: Any]) 696 | return T2 ( 697 | b: b, 698 | t: t 699 | ) 700 | } 701 | } 702 | fileprivate func performLateBindings(_ builder : FlatBuffersBuilder) throws { 703 | for binding in builder.deferedBindings { 704 | if let offset = builder.cache[ObjectIdentifier(binding.object)] { 705 | try builder.update(offset: offset, atCursor: binding.cursor) 706 | } else { 707 | throw FlatBuffersBuildError.couldNotPerformLateBinding 708 | } 709 | } 710 | builder.deferedBindings.removeAll() 711 | } 712 | 713 | """ 714 | 715 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 716 | let result = schema?.0.swift() 717 | print("-----------------------") 718 | print(result!) 719 | print("-----------------------") 720 | XCTAssertEqual(expected, result!) 721 | } 722 | 723 | static var allTests = [ 724 | ("testSchema", testSchema), 725 | ("testIdentLookup", testIdentLookup), 726 | ("testHasRecursion1", testHasRecursion1), 727 | ("testHasRecursion2", testHasRecursion2), 728 | ("testHasRecursion3", testHasRecursion3), 729 | ("testHasRecursion4", testHasRecursion4), 730 | ("testHasRecursion5", testHasRecursion5), 731 | ("testHasRecursion6", testHasRecursion6), 732 | ("testGenerate", testGenerate), 733 | ] 734 | } 735 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/StringLiteralTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringLiteralTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class StringLiteralTests: XCTestCase { 14 | 15 | func testReadMultilineString() { 16 | let s: StaticString = """ 17 | "hello there" 18 | """ 19 | let result = StringLiteral.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 20 | XCTAssertNotNil(result) 21 | XCTAssertEqual(result?.0.value, "hello there") 22 | } 23 | 24 | func testReadQuotedString() { 25 | let s: StaticString = "\"hello there\"" 26 | let result = StringLiteral.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 27 | XCTAssertNotNil(result) 28 | XCTAssertEqual(result?.0.value, "hello there") 29 | } 30 | func testNotClosedString() { 31 | let s: StaticString = "\"hello there" 32 | let result = StringLiteral.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 33 | XCTAssertNil(result) 34 | } 35 | 36 | static var allTests = [ 37 | ("testReadMultilineString", testReadMultilineString), 38 | ("testReadQuotedString", testReadQuotedString), 39 | ("testNotClosedString", testNotClosedString), 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/StructGenTest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StructGenTest.swift 3 | // FlatBuffersSwiftCodeGenTests 4 | // 5 | // Created by Maxim Zaks on 05.03.19. 6 | // 7 | 8 | import Foundation 9 | import XCTest 10 | @testable import FlatBuffersSwiftCodeGenCore 11 | 12 | class StructGenTests: XCTestCase { 13 | let s: StaticString = """ 14 | struct S1 { 15 | i: int; 16 | b: bool; 17 | d: double; 18 | i8: byte; 19 | u8: ubyte; 20 | i16: short; 21 | u16: ushort; 22 | u32: uint; 23 | f32: float; 24 | i64: long; 25 | u64: ulong; 26 | } 27 | 28 | struct S2 { 29 | s: S1; 30 | e: E; 31 | } 32 | 33 | enum E: byte {A, B} 34 | """ 35 | 36 | func testStructFromJsonObjectScalarasOnly() { 37 | let expected = """ 38 | extension S1 { 39 | static func from(jsonObject: [String: Any]?) -> S1? { 40 | guard let object = jsonObject else { return nil } 41 | guard let iInt = object["i"] as? Int, let i = Int32(exactly: iInt) else { return nil } 42 | guard let b = object["b"] as? Bool else { return nil } 43 | guard let d = object["d"] as? Double else { return nil } 44 | guard let i8Int = object["i8"] as? Int, let i8 = Int8(exactly: i8Int) else { return nil } 45 | guard let u8Int = object["u8"] as? Int, let u8 = UInt8(exactly: u8Int) else { return nil } 46 | guard let i16Int = object["i16"] as? Int, let i16 = Int16(exactly: i16Int) else { return nil } 47 | guard let u16Int = object["u16"] as? Int, let u16 = UInt16(exactly: u16Int) else { return nil } 48 | guard let u32Int = object["u32"] as? Int, let u32 = UInt32(exactly: u32Int) else { return nil } 49 | guard let f32Double = object["f32"] as? Double, let f32 = Optional.some(Float32(f32Double)) else { return nil } 50 | guard let i64Int = object["i64"] as? Int, let i64 = Int64(exactly: i64Int) else { return nil } 51 | guard let u64Int = object["u64"] as? Int, let u64 = UInt64(exactly: u64Int) else { return nil } 52 | return S1( 53 | i: i, 54 | b: b, 55 | d: d, 56 | i8: i8, 57 | u8: u8, 58 | i16: i16, 59 | u16: u16, 60 | u32: u32, 61 | f32: f32, 62 | i64: i64, 63 | u64: u64 64 | ) 65 | } 66 | } 67 | """ 68 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 69 | let lookup = schema?.identLookup 70 | let s1 = lookup?.structs["S1"] 71 | let result = s1?.genFromJsonObjectExtension(lookup!) 72 | XCTAssertEqual(expected, result!) 73 | } 74 | 75 | func testStructFromJsonObjectWithEmbeddedStruct() { 76 | let expected = """ 77 | extension S2 { 78 | static func from(jsonObject: [String: Any]?) -> S2? { 79 | guard let object = jsonObject else { return nil } 80 | guard let s = S1.from(jsonObject: object["s"] as? [String: Any]) else { return nil } 81 | guard let e = E.from(jsonValue: object["e"]) else { return nil } 82 | return S2( 83 | s: s, 84 | e: e 85 | ) 86 | } 87 | } 88 | """ 89 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 90 | let lookup = schema?.identLookup 91 | let s1 = lookup?.structs["S2"] 92 | let result = s1?.genFromJsonObjectExtension(lookup!) 93 | XCTAssertEqual(expected, result!) 94 | } 95 | 96 | 97 | static var allTests = [ 98 | ("testProtocolReaderExtension", testStructFromJsonObjectScalarasOnly), 99 | ("testStructFromJsonObjectWithEmbeddedStruct", testStructFromJsonObjectWithEmbeddedStruct) 100 | ] 101 | } 102 | 103 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/TableGenTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableGenTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 22.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class TableGenTests: XCTestCase { 14 | let s: StaticString = """ 15 | struct S1 { 16 | a: bool; 17 | } 18 | table T0 { 19 | a: string; 20 | } 21 | enum E: byte {A, B} 22 | union U1 {T0, T1} 23 | table T1 { 24 | i: int; 25 | b: bool; 26 | d: double (deprecated); 27 | bs: [bool]; 28 | name: string; 29 | names: [string]; 30 | _self: T0; 31 | selfs: [T0]; 32 | s: S1; 33 | s_s: [S1]; 34 | e: E; 35 | es: [E]; 36 | u: U1; 37 | } 38 | """ 39 | 40 | func testProtocolReaderExtension() { 41 | let expected = """ 42 | extension T1.Direct { 43 | public init?(reader: R, myOffset: Offset? = nil) { 44 | guard let reader = reader as? T else { 45 | return nil 46 | } 47 | self._reader = reader 48 | if let myOffset = myOffset { 49 | self._myOffset = myOffset 50 | } else { 51 | if let rootOffset = reader.rootObjectOffset { 52 | self._myOffset = rootOffset 53 | } else { 54 | return nil 55 | } 56 | } 57 | } 58 | public var hashValue: Int { return Int(_myOffset) } 59 | public static func ==(t1 : T1.Direct, t2 : T1.Direct) -> Bool { 60 | return t1._reader.isEqual(other: t2._reader) && t1._myOffset == t2._myOffset 61 | } 62 | public var i: Int32 { 63 | 64 | return _reader.get(objectOffset: _myOffset, propertyIndex: 0, defaultValue: 0) 65 | } 66 | public var b: Bool { 67 | 68 | return _reader.get(objectOffset: _myOffset, propertyIndex: 1, defaultValue: false) 69 | } 70 | public var __d: Float64 { 71 | 72 | return _reader.get(objectOffset: _myOffset, propertyIndex: 2, defaultValue: 0) 73 | } 74 | public var bs: FlatBuffersScalarVector { 75 | 76 | return FlatBuffersScalarVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:3)) 77 | } 78 | public var name: UnsafeBufferPointer? { 79 | guard let offset = _reader.offset(objectOffset: _myOffset, propertyIndex:4) else {return nil} 80 | return _reader.stringBuffer(stringOffset: offset) 81 | } 82 | public var names: FlatBuffersStringVector { 83 | 84 | return FlatBuffersStringVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:5)) 85 | } 86 | public var _self: T0.Direct? { 87 | guard let offset = _reader.offset(objectOffset: _myOffset, propertyIndex:6) else {return nil} 88 | return T0.Direct(reader: _reader, myOffset: offset) 89 | } 90 | public var selfs: FlatBuffersTableVector, T> { 91 | 92 | return FlatBuffersTableVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:7)) 93 | } 94 | public var s: S1? { 95 | 96 | return _reader.get(objectOffset: _myOffset, propertyIndex: 8) 97 | } 98 | public var s_s: FlatBuffersScalarVector { 99 | 100 | return FlatBuffersScalarVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:9)) 101 | } 102 | public var e: E? { 103 | 104 | return E(rawValue:_reader.get(objectOffset: _myOffset, propertyIndex: 10, defaultValue: E.A.rawValue)) 105 | } 106 | public var es: FlatBuffersEnumVector { 107 | 108 | return FlatBuffersEnumVector(reader: _reader, myOffset: _reader.offset(objectOffset: _myOffset, propertyIndex:11)) 109 | } 110 | public var u: U1.Direct? { 111 | 112 | return U1.Direct.from(reader: _reader, propertyIndex : 12, objectOffset : _myOffset) 113 | } 114 | } 115 | """ 116 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 117 | let lookup = schema?.identLookup 118 | let table = lookup?.tables["T1"] 119 | let result = table?.readerProtocolExtension(lookup: lookup!) 120 | XCTAssertEqual(expected, result!) 121 | } 122 | 123 | func testProtocolReaderExtensionWithExplicitIndex() { 124 | let s: StaticString = """ 125 | table T1 { 126 | i: int (id: 1); 127 | b: bool (id: 0); 128 | d: double (id: 2, deprecated); 129 | } 130 | """ 131 | let expected = """ 132 | extension T1.Direct { 133 | public init?(reader: R, myOffset: Offset? = nil) { 134 | guard let reader = reader as? T else { 135 | return nil 136 | } 137 | self._reader = reader 138 | if let myOffset = myOffset { 139 | self._myOffset = myOffset 140 | } else { 141 | if let rootOffset = reader.rootObjectOffset { 142 | self._myOffset = rootOffset 143 | } else { 144 | return nil 145 | } 146 | } 147 | } 148 | public var hashValue: Int { return Int(_myOffset) } 149 | public static func ==(t1 : T1.Direct, t2 : T1.Direct) -> Bool { 150 | return t1._reader.isEqual(other: t2._reader) && t1._myOffset == t2._myOffset 151 | } 152 | public var b: Bool { 153 | 154 | return _reader.get(objectOffset: _myOffset, propertyIndex: 0, defaultValue: false) 155 | } 156 | public var i: Int32 { 157 | 158 | return _reader.get(objectOffset: _myOffset, propertyIndex: 1, defaultValue: 0) 159 | } 160 | public var __d: Float64 { 161 | 162 | return _reader.get(objectOffset: _myOffset, propertyIndex: 2, defaultValue: 0) 163 | } 164 | } 165 | """ 166 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 167 | let lookup = schema?.identLookup 168 | let table = lookup?.tables["T1"] 169 | let result = table?.readerProtocolExtension(lookup: lookup!) 170 | print(result!) 171 | XCTAssertEqual(expected, result) 172 | } 173 | 174 | func testSwiftClass() { 175 | let expected = """ 176 | public final class T1 { 177 | public var i: Int32 178 | public var b: Bool 179 | public var __d: Float64 180 | public var bs: [Bool] 181 | public var name: String? 182 | public var names: [String] 183 | public var _self: T0? 184 | public var selfs: [T0] 185 | public var s: S1? 186 | public var s_s: [S1] 187 | public var e: E? 188 | public var es: [E] 189 | public var u: U1? 190 | public init(i: Int32 = 0, b: Bool = false, __d: Float64 = 0, bs: [Bool] = [], name: String? = nil, names: [String] = [], _self: T0? = nil, selfs: [T0] = [], s: S1? = nil, s_s: [S1] = [], e: E? = E.A, es: [E] = [], u: U1? = nil) { 191 | self.i = i 192 | self.b = b 193 | self.__d = __d 194 | self.bs = bs 195 | self.name = name 196 | self.names = names 197 | self._self = _self 198 | self.selfs = selfs 199 | self.s = s 200 | self.s_s = s_s 201 | self.e = e 202 | self.es = es 203 | self.u = u 204 | } 205 | public struct Direct : Hashable, FlatBuffersDirectAccess { 206 | fileprivate let _reader : T 207 | fileprivate let _myOffset : Offset 208 | } 209 | } 210 | """ 211 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 212 | let lookup = schema?.identLookup 213 | let table = lookup?.tables["T1"] 214 | let result = table?.swiftClass(lookup: lookup!) 215 | print(result!) 216 | XCTAssertEqual(expected, result) 217 | } 218 | 219 | func testFromData() { 220 | let expected = """ 221 | extension T1 { 222 | public static func from(data: Data) -> T1? { 223 | let reader = FlatBuffersMemoryReader(data: data, withoutCopy: false) 224 | return T1.from(selfReader: Direct(reader: reader)) 225 | } 226 | fileprivate static func from(selfReader: Direct?) -> T1? { 227 | guard let selfReader = selfReader else { 228 | return nil 229 | } 230 | if let o = selfReader._reader.cache?.objectPool[selfReader._myOffset] as? T1 { 231 | return o 232 | } 233 | let o = T1() 234 | selfReader._reader.cache?.objectPool[selfReader._myOffset] = o 235 | o.i = selfReader.i 236 | o.b = selfReader.b 237 | o.__d = selfReader.__d 238 | o.bs = selfReader.bs.compactMap{$0} 239 | o.name = selfReader.name§ 240 | o.names = selfReader.names.compactMap{ $0§ } 241 | o._self = T0.from(selfReader:selfReader._self) 242 | o.selfs = selfReader.selfs.compactMap{ T0.from(selfReader:$0) } 243 | o.s = selfReader.s 244 | o.s_s = selfReader.s_s.compactMap{$0} 245 | o.e = selfReader.e 246 | o.es = selfReader.es.compactMap{$0} 247 | o.u = U1.from(selfReader: selfReader.u) 248 | 249 | return o 250 | } 251 | } 252 | """ 253 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 254 | let lookup = schema?.identLookup 255 | let table = lookup?.tables["T1"] 256 | let result = table?.fromDataExtenstion(lookup: lookup!, isRoot: true) 257 | print(result!) 258 | XCTAssertEqual(expected, result) 259 | } 260 | 261 | func testInsertExtension() { 262 | let expected = """ 263 | extension FlatBuffersBuilder { 264 | public func insertT1(i: Int32 = 0, b: Bool = false, bs: Offset? = nil, name: Offset? = nil, names: Offset? = nil, _self: Offset? = nil, selfs: Offset? = nil, s: S1? = nil, s_s: Offset? = nil, e: E = E.A, es: Offset? = nil, u_type: Int8 = 0, u: Offset? = nil) throws -> (Offset, [Int?]) { 265 | var valueCursors = [Int?](repeating: nil, count: 14) 266 | try self.startObject(withPropertyCount: 14) 267 | valueCursors[1] = try self.insert(value: b, defaultValue: false, toStartedObjectAt: 1) 268 | if let s = s { 269 | self.insert(value: s) 270 | valueCursors[8] = try self.insertCurrentOffsetAsProperty(toStartedObjectAt: 8) 271 | } 272 | valueCursors[10] = try self.insert(value: e.rawValue, defaultValue: E.A.rawValue, toStartedObjectAt: 10) 273 | valueCursors[12] = try self.insert(value: u_type, defaultValue: 0, toStartedObjectAt: 12) 274 | valueCursors[0] = try self.insert(value: i, defaultValue: 0, toStartedObjectAt: 0) 275 | if let bs = bs { 276 | valueCursors[3] = try self.insert(offset: bs, toStartedObjectAt: 3) 277 | } 278 | if let name = name { 279 | valueCursors[4] = try self.insert(offset: name, toStartedObjectAt: 4) 280 | } 281 | if let names = names { 282 | valueCursors[5] = try self.insert(offset: names, toStartedObjectAt: 5) 283 | } 284 | if let _self = _self { 285 | valueCursors[6] = try self.insert(offset: _self, toStartedObjectAt: 6) 286 | } 287 | if let selfs = selfs { 288 | valueCursors[7] = try self.insert(offset: selfs, toStartedObjectAt: 7) 289 | } 290 | if let s_s = s_s { 291 | valueCursors[9] = try self.insert(offset: s_s, toStartedObjectAt: 9) 292 | } 293 | if let es = es { 294 | valueCursors[11] = try self.insert(offset: es, toStartedObjectAt: 11) 295 | } 296 | if let u = u { 297 | valueCursors[13] = try self.insert(offset: u, toStartedObjectAt: 13) 298 | } 299 | return try (self.endObject(), valueCursors) 300 | } 301 | } 302 | """ 303 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 304 | let lookup = schema?.identLookup 305 | let table = lookup?.tables["T1"] 306 | let result = table?.insertExtenstion(lookup: lookup!) 307 | print(result!) 308 | XCTAssertEqual(expected, result) 309 | } 310 | 311 | func testInsertMethod() { 312 | let expected = """ 313 | extension T1 { 314 | func insert(_ builder : FlatBuffersBuilder) throws -> Offset { 315 | if builder.options.uniqueTables { 316 | if let myOffset = builder.cache[ObjectIdentifier(self)] { 317 | return myOffset 318 | } 319 | } 320 | if builder.inProgress.contains(ObjectIdentifier(self)){ 321 | return 0 322 | } 323 | builder.inProgress.insert(ObjectIdentifier(self)) 324 | let bs: Offset? 325 | if self.bs.isEmpty { 326 | bs = nil 327 | } else { 328 | try builder.startVector(count: self.bs.count, elementSize: MemoryLayout.stride) 329 | for o in self.bs.reversed() { 330 | builder.insert(value: o) 331 | } 332 | bs = builder.endVector() 333 | } 334 | let name = self.name == nil ? nil : try builder.insert(value: self.name) 335 | let names: Offset? 336 | if self.names.isEmpty { 337 | names = nil 338 | } else { 339 | let offsets = try self.names.reversed().map{ try builder.insert(value: $0) } 340 | try builder.startVector(count: self.names.count, elementSize: MemoryLayout.stride) 341 | for (_, o) in offsets.enumerated() { 342 | try builder.insert(offset: o) 343 | } 344 | names = builder.endVector() 345 | } 346 | let _self = try self._self?.insert(builder) 347 | let selfs: Offset? 348 | if self.selfs.isEmpty { 349 | selfs = nil 350 | } else { 351 | let offsets = try self.selfs.reversed().map{ try $0.insert(builder) } 352 | try builder.startVector(count: self.selfs.count, elementSize: MemoryLayout.stride) 353 | for (_, o) in offsets.enumerated() { 354 | try builder.insert(offset: o) 355 | } 356 | selfs = builder.endVector() 357 | } 358 | let s_s: Offset? 359 | if self.s_s.isEmpty { 360 | s_s = nil 361 | } else { 362 | try builder.startVector(count: self.s_s.count, elementSize: MemoryLayout.stride) 363 | for o in self.s_s.reversed() { 364 | builder.insert(value: o) 365 | } 366 | s_s = builder.endVector() 367 | } 368 | let es: Offset? 369 | if self.es.isEmpty { 370 | es = nil 371 | } else { 372 | try builder.startVector(count: self.es.count, elementSize: MemoryLayout.stride) 373 | for o in self.es.reversed() { 374 | builder.insert(value: o.rawValue) 375 | } 376 | es = builder.endVector() 377 | } 378 | let u = try self.u?.insert(builder) 379 | let u_type = self.u?.unionCase ?? 0 380 | let (myOffset, valueCursors) = try builder.insertT1( 381 | i: i, 382 | b: b, 383 | bs: bs, 384 | name: name, 385 | names: names, 386 | _self: _self, 387 | selfs: selfs, 388 | s: s, 389 | s_s: s_s, 390 | e: e ?? E.A, 391 | es: es, 392 | u_type: u_type, 393 | u: u 394 | ) 395 | if u == 0, 396 | let o = self.u, 397 | let cursor = valueCursors[13] { 398 | builder.deferedBindings.append((o.value, cursor)) 399 | } 400 | if builder.options.uniqueTables { 401 | builder.cache[ObjectIdentifier(self)] = myOffset 402 | } 403 | builder.inProgress.remove(ObjectIdentifier(self)) 404 | return myOffset 405 | } 406 | 407 | } 408 | """ 409 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 410 | let lookup = schema?.identLookup 411 | let table = lookup?.tables["T1"] 412 | let result = table?.insertMethod(lookup: lookup!, fileIdentifier: "nil") 413 | XCTAssertEqual(expected, result!) 414 | } 415 | 416 | func testGenFromJsonObjectExtension() { 417 | let expected = """ 418 | extension T1 { 419 | public static func from(jsonObject: [String: Any]?) -> T1? { 420 | guard let object = jsonObject else { return nil } 421 | let i = (object["i"] as? Int).flatMap { Int32(exactly: $0) } ?? 0 422 | let b = object["b"] as? Bool 423 | let __d = object["__d"] as? Double 424 | let bs = object["bs"] as? [Bool] ?? [] 425 | let name = object["name"] as? String 426 | let names = object["names"] as? [String] ?? [] 427 | let _self = T0.from(jsonObject: object["_self"] as? [String: Any]) 428 | let selfs = ((object["selfs"] as? [[String: Any]]) ?? []).compactMap { T0.from(jsonObject: $0)} 429 | let s = S1.from(jsonObject: object["s"] as? [String: Any]) 430 | let s_s = ((object["s_s"] as? [[String: Any]]) ?? []).compactMap { S1.from(jsonObject: $0)} 431 | let e = E.from(jsonValue: object["e"]) 432 | let es = ((object["es"] as? [Any]) ?? []).compactMap { E.from(jsonValue: $0)} 433 | let u = U1.from(type:object["u_type"] as? String, jsonObject: object["u"] as? [String: Any]) 434 | return T1 ( 435 | i: i, 436 | b: b, 437 | __d: __d, 438 | bs: bs, 439 | name: name, 440 | names: names, 441 | _self: _self, 442 | selfs: selfs, 443 | s: s, 444 | s_s: s_s, 445 | e: e, 446 | es: es, 447 | u: u 448 | ) 449 | } 450 | } 451 | """ 452 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 453 | let lookup = schema?.identLookup 454 | let table = lookup?.tables["T1"] 455 | let result = table?.genFromJsonObjectExtension(lookup!) 456 | XCTAssertEqual(expected, result!) 457 | } 458 | 459 | func testGenAll() { 460 | let schema = Schema.with(pointer:s.utf8Start, length: s.utf8CodeUnitCount)?.0 461 | let lookup = schema!.identLookup 462 | print(lookup.enums["E"]!.swift) 463 | print(lookup.structs["S1"]!.swift) 464 | print(lookup.unions["U1"]!.swift) 465 | let t0 = lookup.tables["T0"]! 466 | print(t0.readerProtocolExtension(lookup: lookup)) 467 | print(t0.swiftClass(lookup: lookup)) 468 | print(t0.fromDataExtenstion(lookup: lookup)) 469 | let t1 = lookup.tables["T1"]! 470 | print(t1.readerProtocolExtension(lookup: lookup)) 471 | print(t1.swiftClass(lookup: lookup)) 472 | print(t1.fromDataExtenstion(lookup: lookup)) 473 | } 474 | 475 | static var allTests = [ 476 | ("testProtocolReaderExtension", testProtocolReaderExtension), 477 | ("testProtocolReaderExtensionWithExplicitIndex", testProtocolReaderExtensionWithExplicitIndex), 478 | ("testSwiftClass", testSwiftClass), 479 | ("testFromData", testFromData), 480 | ("testInsertExtension", testInsertExtension), 481 | ("testInsertMethod", testInsertMethod), 482 | ("testGenAll", testGenAll), 483 | ("testGenFromJsonObjectExtension", testGenFromJsonObjectExtension) 484 | ] 485 | } 486 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/TableTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class TableTests: XCTestCase { 14 | 15 | func testTable() { 16 | let s: StaticString = """ 17 | table Foo { 18 | i: int; 19 | b: bool; 20 | } 21 | """ 22 | let result = Table.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 23 | XCTAssertNotNil(result) 24 | XCTAssertEqual(result?.0.name.value, "Foo") 25 | XCTAssertEqual(result?.0.fields.count, 2) 26 | XCTAssertEqual(result?.0.fields[0].name.value, "i") 27 | XCTAssertEqual(result?.0.fields[0].type.scalar, .i32) 28 | XCTAssertEqual(result?.0.fields[1].name.value, "b") 29 | XCTAssertEqual(result?.0.fields[1].type.scalar, .bool) 30 | } 31 | 32 | func testWithCommentsTable() { 33 | let s: StaticString = """ 34 | // hello 35 | /// bla 36 | table Foo { 37 | i: int; 38 | b: bool; 39 | } 40 | """ 41 | let result = Table.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 42 | XCTAssertNotNil(result) 43 | XCTAssertEqual(result?.0.name.value, "Foo") 44 | XCTAssertEqual(result?.0.fields.count, 2) 45 | XCTAssertEqual(result?.0.fields[0].name.value, "i") 46 | XCTAssertEqual(result?.0.fields[0].type.scalar, .i32) 47 | XCTAssertEqual(result?.0.fields[1].name.value, "b") 48 | XCTAssertEqual(result?.0.fields[1].type.scalar, .bool) 49 | XCTAssertEqual(result?.0.comments.count, 2) 50 | XCTAssertEqual(result?.0.comments[0].value, " hello") 51 | XCTAssertEqual(result?.0.comments[1].value, "/ bla") 52 | } 53 | 54 | func testTableWithMeta() { 55 | let s: StaticString = """ 56 | table Foo (exclude) { 57 | i: int; 58 | b: bool; 59 | } 60 | """ 61 | let result = Table.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 62 | XCTAssertNotNil(result) 63 | XCTAssertEqual(result?.0.name.value, "Foo") 64 | XCTAssertEqual(result?.0.metaData?.values[0].0.value, "exclude") 65 | XCTAssertEqual(result?.0.fields.count, 2) 66 | XCTAssertEqual(result?.0.fields[0].name.value, "i") 67 | XCTAssertEqual(result?.0.fields[0].type.scalar, .i32) 68 | XCTAssertEqual(result?.0.fields[1].name.value, "b") 69 | XCTAssertEqual(result?.0.fields[1].type.scalar, .bool) 70 | } 71 | 72 | func testStructIsNotTable() { 73 | let s: StaticString = """ 74 | // foo 75 | struct Foo (exclude) { 76 | i: int; 77 | b: bool; 78 | } 79 | """ 80 | let result = Table.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 81 | XCTAssertNil(result) 82 | } 83 | 84 | func testSwiftStruct(){ 85 | let s: StaticString = """ 86 | struct Foo (exclude) { 87 | i: int; 88 | b: bool; 89 | } 90 | """ 91 | let result = Struct.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)?.0.swift 92 | let expected = """ 93 | public struct Foo: Scalar { 94 | public let i: Int32 95 | public let b: Bool 96 | public static func ==(v1:Foo, v2:Foo) -> Bool { 97 | return v1.i==v2.i && v1.b==v2.b 98 | } 99 | } 100 | """ 101 | print(result!) 102 | print(expected) 103 | XCTAssertEqual(expected.count, result?.count) 104 | XCTAssertEqual(expected, result) 105 | } 106 | 107 | func testTableIsNotStruct() { 108 | let s: StaticString = """ 109 | table Foo (exclude) { 110 | i: int; 111 | b: bool; 112 | } 113 | """ 114 | let result = Struct.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 115 | XCTAssertNil(result) 116 | } 117 | 118 | func testStructWithMeta() { 119 | let s: StaticString = """ 120 | struct Foo (exclude) { 121 | i: int; 122 | b: bool; 123 | } 124 | """ 125 | let result = Struct.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 126 | XCTAssertNotNil(result) 127 | XCTAssertEqual(result?.0.name.value, "Foo") 128 | XCTAssertEqual(result?.0.metaData?.values[0].0.value, "exclude") 129 | XCTAssertEqual(result?.0.fields.count, 2) 130 | XCTAssertEqual(result?.0.fields[0].name.value, "i") 131 | XCTAssertEqual(result?.0.fields[0].type.scalar, .i32) 132 | XCTAssertEqual(result?.0.fields[1].name.value, "b") 133 | XCTAssertEqual(result?.0.fields[1].type.scalar, .bool) 134 | } 135 | 136 | func testSimpleFieldsList() { 137 | let s: StaticString = """ 138 | table Foo { 139 | i: int; 140 | b: bool; 141 | } 142 | """ 143 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 144 | let lookup = schema.identLookup 145 | let table = lookup.tables["Foo"]! 146 | let names = table.computeFieldNamesWithVTableIndex(lookup: lookup) 147 | XCTAssertEqual(names.count, 2) 148 | XCTAssertEqual(names[0].0, "i") 149 | XCTAssertEqual(names[0].1, 0) 150 | XCTAssertEqual(names[1].0, "b") 151 | XCTAssertEqual(names[1].1, 1) 152 | } 153 | 154 | func testSimpleFieldsListWithId() { 155 | let s: StaticString = """ 156 | table Foo { 157 | i: int (id:1); 158 | b: bool(id:0); 159 | } 160 | """ 161 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 162 | let lookup = schema.identLookup 163 | let table = lookup.tables["Foo"]! 164 | let names = table.computeFieldNamesWithVTableIndex(lookup: lookup) 165 | XCTAssertEqual(names.count, 2) 166 | XCTAssertEqual(names[0].0, "b") 167 | XCTAssertEqual(names[0].1, 0) 168 | XCTAssertEqual(names[1].0, "i") 169 | XCTAssertEqual(names[1].1, 1) 170 | } 171 | 172 | func testFieldsListWithUnion() { 173 | let s: StaticString = """ 174 | union U1 {A, B} 175 | union U2 {C, D} 176 | table Foo { 177 | i: int; 178 | u1: U1; 179 | b: bool; 180 | u2: U2; 181 | } 182 | """ 183 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 184 | let lookup = schema.identLookup 185 | let table = lookup.tables["Foo"]! 186 | let names = table.computeFieldNamesWithVTableIndex(lookup: lookup) 187 | XCTAssertEqual(names.count, 6) 188 | XCTAssertEqual(names[0].name, "i") 189 | XCTAssertEqual(names[0].index, 0) 190 | XCTAssertEqual(names[1].0, "u1_type") 191 | XCTAssertEqual(names[1].1, 1) 192 | XCTAssertEqual(names[2].0, "u1") 193 | XCTAssertEqual(names[2].1, 2) 194 | XCTAssertEqual(names[3].0, "b") 195 | XCTAssertEqual(names[3].1, 3) 196 | XCTAssertEqual(names[4].0, "u2_type") 197 | XCTAssertEqual(names[4].1, 4) 198 | XCTAssertEqual(names[5].0, "u2") 199 | XCTAssertEqual(names[5].1, 5) 200 | } 201 | 202 | func testFieldsListWithUnionAndId() { 203 | let s: StaticString = """ 204 | union U1 {A, B} 205 | union U2 {C, D} 206 | table Foo { 207 | i: int(id: 3); 208 | u1: U1(id: 1); 209 | b: bool(id:0); 210 | u2: U2 (id:2); 211 | } 212 | """ 213 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 214 | let lookup = schema.identLookup 215 | let table = lookup.tables["Foo"]! 216 | let names = table.computeFieldNamesWithVTableIndex(lookup: lookup) 217 | XCTAssertEqual(names.count, 6) 218 | XCTAssertEqual(names[0].name, "b") 219 | XCTAssertEqual(names[0].index, 0) 220 | XCTAssertEqual(names[1].0, "u1_type") 221 | XCTAssertEqual(names[1].1, 1) 222 | XCTAssertEqual(names[2].0, "u1") 223 | XCTAssertEqual(names[2].1, 2) 224 | XCTAssertEqual(names[3].0, "u2_type") 225 | XCTAssertEqual(names[3].1, 3) 226 | XCTAssertEqual(names[4].0, "u2") 227 | XCTAssertEqual(names[4].1, 4) 228 | XCTAssertEqual(names[5].0, "i") 229 | XCTAssertEqual(names[5].1, 5) 230 | } 231 | 232 | func testFieldsListWithUnionAndIdWithoutUnionType() { 233 | let s: StaticString = """ 234 | union U1 {A, B} 235 | union U2 {C, D} 236 | table Foo { 237 | i: int(id: 3); 238 | u1: U1(id: 1); 239 | b: bool(id:0); 240 | u2: U2 (id:2); 241 | } 242 | """ 243 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 244 | let lookup = schema.identLookup 245 | let table = lookup.tables["Foo"]! 246 | let names = table.computeFieldNamesWithVTableIndex(lookup: lookup, withUniontypes: false) 247 | XCTAssertEqual(names.count, 4) 248 | XCTAssertEqual(names[0].name, "b") 249 | XCTAssertEqual(names[0].index, 0) 250 | XCTAssertEqual(names[1].0, "u1") 251 | XCTAssertEqual(names[1].1, 1) 252 | XCTAssertEqual(names[2].0, "u2") 253 | XCTAssertEqual(names[2].1, 3) 254 | XCTAssertEqual(names[3].0, "i") 255 | XCTAssertEqual(names[3].1, 5) 256 | } 257 | 258 | func testFieldsListWithUnionAndIdSortedBySize() { 259 | let s: StaticString = """ 260 | union U1 {A, B} 261 | union U2 {C, D} 262 | table Foo { 263 | i: int(id: 3); 264 | u1: U1(id: 1); 265 | b: bool(id:0); 266 | u2: U2 (id:2); 267 | } 268 | """ 269 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 270 | let lookup = schema.identLookup 271 | let table = lookup.tables["Foo"]! 272 | let names = table.computeFieldNamesWithVTableIndexSortedBySize(lookup: lookup) 273 | XCTAssertEqual(names.count, 6) 274 | XCTAssertEqual(names[0].name, "b") 275 | XCTAssertEqual(names[0].index, 0) 276 | XCTAssertEqual(names[1].0, "u1_type") 277 | XCTAssertEqual(names[1].1, 1) 278 | XCTAssertEqual(names[2].0, "u2_type") 279 | XCTAssertEqual(names[2].1, 3) 280 | XCTAssertEqual(names[3].0, "u1") 281 | XCTAssertEqual(names[3].1, 2) 282 | XCTAssertEqual(names[4].0, "u2") 283 | XCTAssertEqual(names[4].1, 4) 284 | XCTAssertEqual(names[5].0, "i") 285 | XCTAssertEqual(names[5].1, 5) 286 | } 287 | func testFieldsListWithUnionAndStructAndIdSortedBySize() { 288 | let s: StaticString = """ 289 | union U1 {A, B} 290 | union U2 {C, D} 291 | enum E1: byte {a, b} 292 | struct A { 293 | a: bool; 294 | e: E1; 295 | } 296 | struct B { 297 | a1: A; 298 | a: bool; 299 | } 300 | table Foo { 301 | i: int(id: 3); 302 | u1: U1(id: 1); 303 | b: bool(id:0); 304 | u2: U2 (id:2); 305 | b: B (id: 4); 306 | a: A (id: 5); 307 | } 308 | """ 309 | let schema = Schema.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)!.0 310 | let lookup = schema.identLookup 311 | let table = lookup.tables["Foo"]! 312 | let names = table.computeFieldNamesWithVTableIndexSortedBySize(lookup: lookup) 313 | XCTAssertEqual(names.count, 8) 314 | XCTAssertEqual(names[0].name, "b") 315 | XCTAssertEqual(names[0].index, 0) 316 | XCTAssertEqual(names[1].0, "u1_type") 317 | XCTAssertEqual(names[1].1, 1) 318 | XCTAssertEqual(names[2].0, "u2_type") 319 | XCTAssertEqual(names[2].1, 3) 320 | XCTAssertEqual(names[3].0, "a") 321 | XCTAssertEqual(names[3].1, 7) 322 | XCTAssertEqual(names[4].0, "b") 323 | XCTAssertEqual(names[4].1, 6) 324 | XCTAssertEqual(names[5].0, "u1") 325 | XCTAssertEqual(names[5].1, 2) 326 | XCTAssertEqual(names[6].0, "u2") 327 | XCTAssertEqual(names[6].1, 4) 328 | XCTAssertEqual(names[7].0, "i") 329 | XCTAssertEqual(names[7].1, 5) 330 | } 331 | 332 | static var allTests = [ 333 | ("testTable", testTable), 334 | ("testWithCommentsTable", testWithCommentsTable), 335 | ("testTableWithMeta", testTableWithMeta), 336 | ("testStructIsNotTable", testStructIsNotTable), 337 | ("testSwiftStruct", testSwiftStruct), 338 | ("testTableIsNotStruct", testTableIsNotStruct), 339 | ("testStructWithMeta", testStructWithMeta), 340 | ("testSimpleFieldsList", testSimpleFieldsList), 341 | ("testSimpleFieldsListWithId", testSimpleFieldsListWithId), 342 | ("testFieldsListWithUnion", testFieldsListWithUnion), 343 | ("testFieldsListWithUnionAndId", testFieldsListWithUnionAndId), 344 | ("testFieldsListWithUnionAndIdWithoutUnionType", testFieldsListWithUnionAndIdWithoutUnionType), 345 | ("testFieldsListWithUnionAndIdSortedBySize", testFieldsListWithUnionAndIdSortedBySize), 346 | ("testFieldsListWithUnionAndStructAndIdSortedBySize", testFieldsListWithUnionAndStructAndIdSortedBySize), 347 | ] 348 | } 349 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/TypeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TypeTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class TypeTests: XCTestCase { 14 | 15 | func testMultipleTypes() { 16 | let s: StaticString = """ 17 | 18 | bool byte ubyte short ushort int uint long ulong float double string Foo [bool] [Bar] [string] 19 | int8 int16 int32 int64 uint8 uint16 uint32 uint64 float32 float64 20 | [int8] [float64] 21 | """ 22 | var result = Type.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 23 | XCTAssertNotNil(result) 24 | XCTAssertEqual(result?.0.scalar, .bool) 25 | XCTAssertNil(result!.0.ref) 26 | XCTAssertFalse(result!.0.string) 27 | XCTAssertFalse(result!.0.vector) 28 | 29 | var length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 30 | result = Type.with(pointer: result!.1, length: length) 31 | XCTAssertNotNil(result) 32 | XCTAssertEqual(result?.0.scalar, .i8) 33 | XCTAssertNil(result!.0.ref) 34 | XCTAssertFalse(result!.0.string) 35 | XCTAssertFalse(result!.0.vector) 36 | 37 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 38 | result = Type.with(pointer: result!.1, length: length) 39 | XCTAssertNotNil(result) 40 | XCTAssertEqual(result?.0.scalar, .u8) 41 | XCTAssertNil(result!.0.ref) 42 | XCTAssertFalse(result!.0.string) 43 | XCTAssertFalse(result!.0.vector) 44 | 45 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 46 | result = Type.with(pointer: result!.1, length: length) 47 | XCTAssertNotNil(result) 48 | XCTAssertEqual(result?.0.scalar, .i16) 49 | XCTAssertNil(result!.0.ref) 50 | XCTAssertFalse(result!.0.string) 51 | XCTAssertFalse(result!.0.vector) 52 | 53 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 54 | result = Type.with(pointer: result!.1, length: length) 55 | XCTAssertNotNil(result) 56 | XCTAssertEqual(result?.0.scalar, .u16) 57 | XCTAssertNil(result!.0.ref) 58 | XCTAssertFalse(result!.0.string) 59 | XCTAssertFalse(result!.0.vector) 60 | 61 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 62 | result = Type.with(pointer: result!.1, length: length) 63 | XCTAssertNotNil(result) 64 | XCTAssertEqual(result?.0.scalar, .i32) 65 | XCTAssertNil(result!.0.ref) 66 | XCTAssertFalse(result!.0.string) 67 | XCTAssertFalse(result!.0.vector) 68 | 69 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 70 | result = Type.with(pointer: result!.1, length: length) 71 | XCTAssertNotNil(result) 72 | XCTAssertEqual(result?.0.scalar, .u32) 73 | XCTAssertNil(result!.0.ref) 74 | XCTAssertFalse(result!.0.string) 75 | XCTAssertFalse(result!.0.vector) 76 | 77 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 78 | result = Type.with(pointer: result!.1, length: length) 79 | XCTAssertNotNil(result) 80 | XCTAssertEqual(result?.0.scalar, .i64) 81 | XCTAssertNil(result!.0.ref) 82 | XCTAssertFalse(result!.0.string) 83 | XCTAssertFalse(result!.0.vector) 84 | 85 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 86 | result = Type.with(pointer: result!.1, length: length) 87 | XCTAssertNotNil(result) 88 | XCTAssertEqual(result?.0.scalar, .u64) 89 | XCTAssertNil(result!.0.ref) 90 | XCTAssertFalse(result!.0.string) 91 | XCTAssertFalse(result!.0.vector) 92 | 93 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 94 | result = Type.with(pointer: result!.1, length: length) 95 | XCTAssertNotNil(result) 96 | XCTAssertEqual(result?.0.scalar, .f32) 97 | XCTAssertNil(result!.0.ref) 98 | XCTAssertFalse(result!.0.string) 99 | XCTAssertFalse(result!.0.vector) 100 | 101 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 102 | result = Type.with(pointer: result!.1, length: length) 103 | XCTAssertNotNil(result) 104 | XCTAssertEqual(result!.0.scalar, .f64) 105 | XCTAssertNil(result!.0.ref) 106 | XCTAssertFalse(result!.0.string) 107 | XCTAssertFalse(result!.0.vector) 108 | 109 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 110 | result = Type.with(pointer: result!.1, length: length) 111 | XCTAssertNotNil(result) 112 | XCTAssertNil(result!.0.scalar) 113 | XCTAssertNil(result!.0.ref) 114 | XCTAssertTrue(result!.0.string) 115 | XCTAssertFalse(result!.0.vector) 116 | 117 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 118 | result = Type.with(pointer: result!.1, length: length) 119 | XCTAssertNotNil(result) 120 | XCTAssertNil(result!.0.scalar) 121 | XCTAssertEqual(result!.0.ref?.value, "Foo") 122 | XCTAssertFalse(result!.0.string) 123 | XCTAssertFalse(result!.0.vector) 124 | 125 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 126 | result = Type.with(pointer: result!.1, length: length) 127 | XCTAssertNotNil(result) 128 | XCTAssertEqual(result!.0.scalar, .bool) 129 | XCTAssertNil(result!.0.ref?.value) 130 | XCTAssertFalse(result!.0.string) 131 | XCTAssertTrue(result!.0.vector) 132 | 133 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 134 | result = Type.with(pointer: result!.1, length: length) 135 | XCTAssertNotNil(result) 136 | XCTAssertNil(result!.0.scalar) 137 | XCTAssertEqual(result!.0.ref?.value, "Bar") 138 | XCTAssertFalse(result!.0.string) 139 | XCTAssertTrue(result!.0.vector) 140 | 141 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 142 | result = Type.with(pointer: result!.1, length: length) 143 | XCTAssertNotNil(result) 144 | XCTAssertNil(result!.0.scalar) 145 | XCTAssertNil(result!.0.ref) 146 | XCTAssertTrue(result!.0.string) 147 | XCTAssertTrue(result!.0.vector) 148 | 149 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 150 | result = Type.with(pointer: result!.1, length: length) 151 | XCTAssertNotNil(result) 152 | XCTAssertEqual(result!.0.scalar, .i8) 153 | XCTAssertNil(result!.0.ref) 154 | XCTAssertFalse(result!.0.string) 155 | XCTAssertFalse(result!.0.vector) 156 | 157 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 158 | result = Type.with(pointer: result!.1, length: length) 159 | XCTAssertNotNil(result) 160 | XCTAssertEqual(result!.0.scalar, .i16) 161 | XCTAssertNil(result!.0.ref) 162 | XCTAssertFalse(result!.0.string) 163 | XCTAssertFalse(result!.0.vector) 164 | 165 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 166 | result = Type.with(pointer: result!.1, length: length) 167 | XCTAssertNotNil(result) 168 | XCTAssertEqual(result!.0.scalar, .i32) 169 | XCTAssertNil(result!.0.ref) 170 | XCTAssertFalse(result!.0.string) 171 | XCTAssertFalse(result!.0.vector) 172 | 173 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 174 | result = Type.with(pointer: result!.1, length: length) 175 | XCTAssertNotNil(result) 176 | XCTAssertEqual(result!.0.scalar, .i64) 177 | XCTAssertNil(result!.0.ref) 178 | XCTAssertFalse(result!.0.string) 179 | XCTAssertFalse(result!.0.vector) 180 | 181 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 182 | result = Type.with(pointer: result!.1, length: length) 183 | XCTAssertNotNil(result) 184 | XCTAssertEqual(result!.0.scalar, .u8) 185 | XCTAssertNil(result!.0.ref) 186 | XCTAssertFalse(result!.0.string) 187 | XCTAssertFalse(result!.0.vector) 188 | 189 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 190 | result = Type.with(pointer: result!.1, length: length) 191 | XCTAssertNotNil(result) 192 | XCTAssertEqual(result!.0.scalar, .u16) 193 | XCTAssertNil(result!.0.ref) 194 | XCTAssertFalse(result!.0.string) 195 | XCTAssertFalse(result!.0.vector) 196 | 197 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 198 | result = Type.with(pointer: result!.1, length: length) 199 | XCTAssertNotNil(result) 200 | XCTAssertEqual(result!.0.scalar, .u32) 201 | XCTAssertNil(result!.0.ref) 202 | XCTAssertFalse(result!.0.string) 203 | XCTAssertFalse(result!.0.vector) 204 | 205 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 206 | result = Type.with(pointer: result!.1, length: length) 207 | XCTAssertNotNil(result) 208 | XCTAssertEqual(result!.0.scalar, .u64) 209 | XCTAssertNil(result!.0.ref) 210 | XCTAssertFalse(result!.0.string) 211 | XCTAssertFalse(result!.0.vector) 212 | 213 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 214 | result = Type.with(pointer: result!.1, length: length) 215 | XCTAssertNotNil(result) 216 | XCTAssertEqual(result!.0.scalar, .f32) 217 | XCTAssertNil(result!.0.ref) 218 | XCTAssertFalse(result!.0.string) 219 | XCTAssertFalse(result!.0.vector) 220 | 221 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 222 | result = Type.with(pointer: result!.1, length: length) 223 | XCTAssertNotNil(result) 224 | XCTAssertEqual(result!.0.scalar, .f64) 225 | XCTAssertNil(result!.0.ref) 226 | XCTAssertFalse(result!.0.string) 227 | XCTAssertFalse(result!.0.vector) 228 | 229 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 230 | result = Type.with(pointer: result!.1, length: length) 231 | XCTAssertNotNil(result) 232 | XCTAssertEqual(result!.0.scalar, .i8) 233 | XCTAssertNil(result!.0.ref) 234 | XCTAssertFalse(result!.0.string) 235 | XCTAssertTrue(result!.0.vector) 236 | 237 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 238 | result = Type.with(pointer: result!.1, length: length) 239 | XCTAssertNotNil(result) 240 | XCTAssertEqual(result!.0.scalar, .f64) 241 | XCTAssertNil(result!.0.ref) 242 | XCTAssertFalse(result!.0.string) 243 | XCTAssertTrue(result!.0.vector) 244 | 245 | // Done 246 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 247 | result = Type.with(pointer: result!.1, length: length) 248 | XCTAssertNil(result) 249 | } 250 | 251 | func testBrokenDef() { 252 | let s: StaticString = "[string" 253 | let result = Type.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 254 | XCTAssertNil(result) 255 | } 256 | 257 | func testStrangeVector() { 258 | let s: StaticString = " [ string \n ] " 259 | let result = Type.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 260 | XCTAssertNotNil(result) 261 | XCTAssertNil(result!.0.scalar) 262 | XCTAssertNil(result!.0.ref) 263 | XCTAssertTrue(result!.0.string) 264 | XCTAssertTrue(result!.0.vector) 265 | } 266 | 267 | func testMultipleTypesToSwift() { 268 | let s: StaticString = """ 269 | 270 | bool byte ubyte short ushort int uint long ulong float double string Foo [bool] [Bar] [string] 271 | """ 272 | 273 | var types: [Type] = [] 274 | var p = s.utf8Start 275 | var length = s.utf8CodeUnitCount 276 | while let r = Type.with(pointer: p, length: length) { 277 | types.append(r.0) 278 | length -= p.distance(to: r.1) 279 | p = r.1 280 | } 281 | 282 | XCTAssertEqual(types.count, 16) 283 | let swiftTypes = "Bool Int8 UInt8 Int16 UInt16 Int32 UInt32 Int64 UInt64 Float32 Float64 String Foo [Bool] [Bar] [String]" 284 | let result = types.map { $0.swift }.joined(separator: " ") 285 | XCTAssertEqual(result, swiftTypes) 286 | } 287 | 288 | static var allTests = [ 289 | ("testMultipleTypes", testMultipleTypes), 290 | ("testBrokenDef", testBrokenDef), 291 | ("testStrangeVector", testStrangeVector), 292 | ("testMultipleTypesToSwift", testMultipleTypesToSwift), 293 | ] 294 | } 295 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/UnionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UnionTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 19.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class UnionTests: XCTestCase { 14 | 15 | func testUnion() { 16 | let s: StaticString = """ 17 | /// bla blup 18 | union Foo2 (something) {Bar, Baz} 19 | """ 20 | let result = Union.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 21 | XCTAssertNotNil(result) 22 | XCTAssertEqual(result?.0.name.value, "Foo2") 23 | XCTAssertEqual(result?.0.metaData?.values[0].0.value, "something") 24 | XCTAssertEqual(result?.0.cases.count, 2) 25 | XCTAssertEqual(result?.0.cases[0].value, "Bar") 26 | XCTAssertEqual(result?.0.cases[1].value, "Baz") 27 | XCTAssertEqual(result?.0.comments.count, 1) 28 | XCTAssertEqual(result?.0.comments[0].value, "/ bla blup") 29 | } 30 | 31 | func testGen(){ 32 | let s: StaticString = """ 33 | union Foo2 (something) {A, B} 34 | """ 35 | let expected = """ 36 | public enum Foo2 { 37 | case withA(A), withB(B) 38 | fileprivate static func from(selfReader: Foo2.Direct?) -> Foo2? { 39 | guard let selfReader = selfReader else { 40 | return nil 41 | } 42 | switch selfReader { 43 | case .withA(let o): 44 | guard let o1 = A.from(selfReader: o) else { 45 | return nil 46 | } 47 | return .withA(o1) 48 | case .withB(let o): 49 | guard let o1 = B.from(selfReader: o) else { 50 | return nil 51 | } 52 | return .withB(o1) 53 | } 54 | } 55 | public enum Direct { 56 | case withA(A.Direct), withB(B.Direct) 57 | fileprivate static func from(reader: R, propertyIndex : Int, objectOffset : Offset?) -> Foo2.Direct? { 58 | guard let objectOffset = objectOffset else { 59 | return nil 60 | } 61 | let unionCase : Int8 = reader.get(objectOffset: objectOffset, propertyIndex: propertyIndex, defaultValue: 0) 62 | guard let caseObjectOffset : Offset = reader.offset(objectOffset: objectOffset, propertyIndex:propertyIndex + 1) else { 63 | return nil 64 | } 65 | switch unionCase { 66 | case 1: 67 | guard let o = A.Direct(reader: reader, myOffset: caseObjectOffset) else { 68 | return nil 69 | } 70 | return Foo2.Direct.withA(o) 71 | case 2: 72 | guard let o = B.Direct(reader: reader, myOffset: caseObjectOffset) else { 73 | return nil 74 | } 75 | return Foo2.Direct.withB(o) 76 | default: 77 | break 78 | } 79 | return nil 80 | } 81 | public var asA: A.Direct? { 82 | switch self { 83 | case .withA(let v): 84 | return v 85 | default: 86 | return nil 87 | } 88 | } 89 | public var asB: B.Direct? { 90 | switch self { 91 | case .withB(let v): 92 | return v 93 | default: 94 | return nil 95 | } 96 | } 97 | } 98 | var unionCase: Int8 { 99 | switch self { 100 | case .withA(_): return 1 101 | case .withB(_): return 2 102 | } 103 | } 104 | func insert(_ builder: FlatBuffersBuilder) throws -> Offset { 105 | switch self { 106 | case .withA(let o): return try o.insert(builder) 107 | case .withB(let o): return try o.insert(builder) 108 | } 109 | } 110 | public var asA: A? { 111 | switch self { 112 | case .withA(let v): 113 | return v 114 | default: 115 | return nil 116 | } 117 | } 118 | public var asB: B? { 119 | switch self { 120 | case .withB(let v): 121 | return v 122 | default: 123 | return nil 124 | } 125 | } 126 | public var value: AnyObject { 127 | switch self { 128 | case .withA(let v): return v 129 | case .withB(let v): return v 130 | } 131 | } 132 | } 133 | """ 134 | let result = Union.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)?.0.swift 135 | print(result!) 136 | XCTAssertEqual(result, expected) 137 | } 138 | 139 | func testGenFromJson() { 140 | let s: StaticString = """ 141 | union Foo2 (something) {A, B} 142 | """ 143 | let expected = """ 144 | extension Foo2 { 145 | static func from(type: String?, jsonObject: [String: Any]?) -> Foo2? { 146 | guard let type = type, let object = jsonObject else { return nil } 147 | switch type { 148 | case "A": 149 | guard let o = A.from(jsonObject: object) else { return nil } 150 | return Foo2.withA(o) 151 | case "B": 152 | guard let o = B.from(jsonObject: object) else { return nil } 153 | return Foo2.withB(o) 154 | default: 155 | return nil 156 | } 157 | } 158 | } 159 | """ 160 | let result = Union.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount)?.0.genFromJsonExtension() 161 | print(result!) 162 | XCTAssertEqual(result!, expected) 163 | } 164 | 165 | static var allTests = [ 166 | ("testUnion", testUnion), 167 | ("testGen", testGen), 168 | ("testGenFromJson", testGenFromJson) 169 | ] 170 | } 171 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/ValueLiteralTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ValueLiteralTests.swift 3 | // CodeGenTests 4 | // 5 | // Created by Maxim Zaks on 10.07.17. 6 | // Copyright © 2017 maxim.zaks. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | @testable import FlatBuffersSwiftCodeGenCore 12 | 13 | class ValueLiteralTests: XCTestCase { 14 | 15 | func testValues() { 16 | let s: StaticString = """ 17 | "hello there" 12 -12 0.1 -0.1 true false 1.2e10 18 | """ 19 | var result = ValueLiteral.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 20 | XCTAssertNotNil(result) 21 | XCTAssertEqual(result?.0.value, "\"hello there\"") 22 | 23 | var length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 24 | result = ValueLiteral.with(pointer: result!.1, length: length) 25 | XCTAssertNotNil(result) 26 | XCTAssertEqual(result?.0.value, "12") 27 | 28 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 29 | result = ValueLiteral.with(pointer: result!.1, length: length) 30 | XCTAssertNotNil(result) 31 | XCTAssertEqual(result?.0.value, "-12") 32 | 33 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 34 | result = ValueLiteral.with(pointer: result!.1, length: length) 35 | XCTAssertNotNil(result) 36 | XCTAssertEqual(result?.0.value, "0.1") 37 | 38 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 39 | result = ValueLiteral.with(pointer: result!.1, length: length) 40 | XCTAssertNotNil(result) 41 | XCTAssertEqual(result?.0.value, "-0.1") 42 | 43 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 44 | result = ValueLiteral.with(pointer: result!.1, length: length) 45 | XCTAssertNotNil(result) 46 | XCTAssertEqual(result?.0.value, "true") 47 | 48 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 49 | result = ValueLiteral.with(pointer: result!.1, length: length) 50 | XCTAssertNotNil(result) 51 | XCTAssertEqual(result?.0.value, "false") 52 | 53 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 54 | result = ValueLiteral.with(pointer: result!.1, length: length) 55 | XCTAssertNotNil(result) 56 | XCTAssertEqual(result?.0.value, "1.2e10") 57 | 58 | length = s.utf8CodeUnitCount - s.utf8Start.distance(to: result!.1) 59 | result = ValueLiteral.with(pointer: result!.1, length: length) 60 | XCTAssertNil(result) 61 | } 62 | 63 | func testNotValue() { 64 | let s: StaticString = """ 65 | 66 | hello 67 | """ 68 | let result = ValueLiteral.with(pointer: s.utf8Start, length: s.utf8CodeUnitCount) 69 | XCTAssertNil(result) 70 | } 71 | 72 | static var allTests = [ 73 | ("testValues", testValues), 74 | ("testNotValue", testNotValue), 75 | ] 76 | } 77 | -------------------------------------------------------------------------------- /Tests/FlatBuffersSwiftCodeGenTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !os(macOS) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(ASTNodeTests.allTests), 7 | testCase(CommentTests.allTests), 8 | testCase(EnumTests.allTests), 9 | testCase(FieldTests.allTests), 10 | testCase(IdentTests.allTests), 11 | testCase(MetaDataTests.allTests), 12 | testCase(SchemaTests.allTests), 13 | testCase(StringLiteralTests.allTests), 14 | testCase(TableGenTests.allTests), 15 | testCase(TableTests.allTests), 16 | testCase(TypeTests.allTests), 17 | testCase(UnionTests.allTests), 18 | testCase(ValueLiteralTests.allTests), 19 | ] 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import FlatBuffersSwiftCodeGenTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += FlatBuffersSwiftCodeGenTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'macOS-10.13' 11 | 12 | steps: 13 | - script: swift test 14 | displayName: 'Run Swift test' 15 | -------------------------------------------------------------------------------- /fbsCG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzaks/FlatBuffersSwiftCodeGen/c3ed95bf5e2088d4285a784a1dc50470fae93a1e/fbsCG -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | echo "Build release version" 2 | swift build -c release --static-swift-stdlib 3 | echo "Copy binary to ./fbsCG" 4 | cp .build/release/FlatBuffersSwiftCodeGen ./fbsCG 5 | echo "Done 👌" 6 | --------------------------------------------------------------------------------