THRIFT-5621: Add Swift tutorial

Client: swift
diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
index aa5712b..24969d1 100644
--- a/tutorial/Makefile.am
+++ b/tutorial/Makefile.am
@@ -86,6 +86,10 @@
 SUBDIRS += php
 endif
 
+if WITH_SWIFT
+SUBDIRS += swift
+endif
+
 #
 # generate html for tutorial.thrift
 #
diff --git a/tutorial/swift/Makefile.am b/tutorial/swift/Makefile.am
new file mode 100644
index 0000000..f484560
--- /dev/null
+++ b/tutorial/swift/Makefile.am
@@ -0,0 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#
+# Common thrift code generation rules
+#
+gen_swift:
+	$(THRIFT) --gen swift -r -o Sources/Common $(top_srcdir)/tutorial/tutorial.thrift
+
+tutorial: gen_swift
+	swift run TutorialRunner
+
+tutorialserver: gen_swift
+	swift run TutorialServer
+
+tutorialclient: gen_swift
+	swift run TutorialClient
diff --git a/tutorial/swift/Package.swift b/tutorial/swift/Package.swift
new file mode 100644
index 0000000..ae3f530
--- /dev/null
+++ b/tutorial/swift/Package.swift
@@ -0,0 +1,53 @@
+// swift-tools-version:5.1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import PackageDescription
+
+let thriftDependency: Target.Dependency = .product(name: "Thrift", package: "swift-dep")
+let package = Package(
+    name: "swift-tutorial",
+    platforms: [
+        .macOS(.v10_13)
+    ],
+    products: [
+        // Products define the executables and libraries a package produces, and make them visible to other packages.
+        .executable(name: "TutorialServer", targets: ["TutorialServer"]),
+        .executable(name: "TutorialClient", targets: ["TutorialClient"]),
+        .executable(name: "TutorialRunner", targets: ["TutorialRunner"])
+    ],
+    dependencies: [
+        // Dependencies declare other packages that this package depends on.
+        .package(path: "./swift-dep"),
+    ],
+    targets: [
+        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+        // Targets can depend on other targets in this package, and on products in packages this package depends on.
+        .target(
+            name: "Common",
+            dependencies: [thriftDependency]),
+        .target(
+            name: "TutorialServer",
+            dependencies: [thriftDependency, "Common"]),
+        .target(
+            name: "TutorialClient",
+            dependencies: [thriftDependency, "Common"]),
+        .target(name: "TutorialRunner")
+    ]
+)
diff --git a/tutorial/swift/README.md b/tutorial/swift/README.md
new file mode 100644
index 0000000..18a1e7b
--- /dev/null
+++ b/tutorial/swift/README.md
@@ -0,0 +1,11 @@
+# Thrift Swift Tutorial
+==================================================
+
+## Run the tutorial code (client + server):
+`make tutorial`
+
+## Run the server only
+`make tutorialserver`
+
+## Run the client only
+`make tutorialclient`
diff --git a/tutorial/swift/Sources/TutorialClient/main.swift b/tutorial/swift/Sources/TutorialClient/main.swift
new file mode 100644
index 0000000..ea8720f
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialClient/main.swift
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Foundation
+import Thrift
+import Common
+
+let transport = try TSocketTransport(hostname: "localhost", port: 9090)
+let inOutProto = TBinaryProtocol(on: transport)
+let client = CalculatorClient(inoutProtocol: inOutProto)
+
+try client.ping()
+print("1+1= \(try client.add(num1: 1, num2: 1))")
+
+let work = Work(num1: 1, num2: 0, op: .divide)
+do {
+    _ = try client.calculate(logid: 1, w: work)
+    assertionFailure("Hm... shouldn't be able to divide by zero")
+} catch let error as InvalidOperation {
+    print("Invalid operation: \(error.why)")
+}
+
+work.op = .subtract
+work.num1 = 15
+work.num2 = 10
+
+print("15-10= \(try client.calculate(logid: 1, w: work))")
+
+print("Done!")
diff --git a/tutorial/swift/Sources/TutorialRunner/main.swift b/tutorial/swift/Sources/TutorialRunner/main.swift
new file mode 100644
index 0000000..7d24391
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialRunner/main.swift
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Foundation
+
+let swiftUrl = URL(fileURLWithPath: "/usr/bin/swift")
+let server = Process()
+server.executableURL = swiftUrl
+server.arguments = ["run", "TutorialServer"]
+try server.run()
+
+Thread.sleep(forTimeInterval: 2)
+
+let client = Process()
+client.executableURL = swiftUrl
+client.arguments = ["run", "TutorialClient"]
+try client.run()
+client.waitUntilExit()
+
+server.terminate()
diff --git a/tutorial/swift/Sources/TutorialServer/CalculatorService.swift b/tutorial/swift/Sources/TutorialServer/CalculatorService.swift
new file mode 100644
index 0000000..2021cfc
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialServer/CalculatorService.swift
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Foundation
+import Common
+
+struct CalculatorError: Error {
+    
+}
+class CalculatorService: Calculator {
+    var resultMap = [Int32:SharedStruct]()
+    
+    func ping() throws {
+        print("ping()")
+    }
+    
+    func add(num1: Int32, num2: Int32) throws -> Int32 {
+        print("add(\(num1), \(num2))")
+        return num1 + num2
+    }
+    
+    func calculate(logid: Int32, w: Work) throws -> Int32 {
+        print("calculate(\(logid), \(w))")
+        let result: Int32 = try {
+        switch w.op {
+        case .add:
+            return w.num1 + w.num2
+        case .subtract:
+            return w.num1 - w.num2
+        case .multiply:
+            return w.num1 * w.num2
+        case .divide:
+            guard w.num2 != 0 else {
+                throw InvalidOperation(whatOp: w.op.rawValue, why: "Cannot divide by 0")
+            }
+            return w.num1 / w.num2
+        }
+        }()
+        
+        let resultEntry = SharedStruct(key: logid, value: "\(result)")
+        resultMap[logid] = resultEntry
+        
+        return result
+    }
+    
+    func zip() throws {
+        print("zip()")
+    }
+    
+    func getStruct(key: Int32) throws -> SharedStruct {
+        print("getStruct(\(key))")
+        guard let entry = resultMap[key] else {
+            throw CalculatorError()
+        }
+        return entry
+    }
+}
diff --git a/tutorial/swift/Sources/TutorialServer/main.swift b/tutorial/swift/Sources/TutorialServer/main.swift
new file mode 100644
index 0000000..517a8b1
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialServer/main.swift
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Foundation
+import Common
+import Thrift
+
+let service = CalculatorService()
+let processor = CalculatorProcessor(service: service)
+let server = try TSocketServer(port: 9090, inProtocol: TBinaryProtocol.self, outProtocol: TBinaryProtocol.self, processor: processor)
+
+RunLoop.main.run()
diff --git a/tutorial/swift/swift-dep b/tutorial/swift/swift-dep
new file mode 120000
index 0000000..c757a77
--- /dev/null
+++ b/tutorial/swift/swift-dep
@@ -0,0 +1 @@
+../../lib/swift
\ No newline at end of file