THRIFT-4547: Swift crosstests (#2670)

Co-authored-by: Jiayu Liu <Jimexist@users.noreply.github.com>
diff --git a/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java b/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java
index 8d0c7aa..6657df6 100644
--- a/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java
+++ b/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java
@@ -246,7 +246,7 @@
       first_map.put(Numberz.TWO, argument);
       first_map.put(Numberz.THREE, argument);
 
-      Insanity looney = new Insanity();
+      Insanity looney = new Insanity(new HashMap<>(), Arrays.asList());
       second_map.put(Numberz.SIX, looney);
 
       Map<Long, Map<Numberz, Insanity>> insane = new HashMap<>();
diff --git a/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt b/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt
index ab415b0..b7f38d7 100644
--- a/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt
+++ b/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt
@@ -183,7 +183,11 @@
         val secondMap = mutableMapOf<Numberz, Insanity>()
         firstMap[Numberz.TWO] = argument
         firstMap[Numberz.THREE] = argument
-        val looney = Insanity()
+        val looney =
+            Insanity().apply {
+                userMap = HashMap()
+                xtructs = listOf()
+            }
         secondMap[Numberz.SIX] = looney
         val insane: MutableMap<Long, Map<Numberz, Insanity>> = HashMap()
         insane[1L] = firstMap
@@ -241,11 +245,20 @@
         } else if (arg0 == "Xception2") {
             val x = Xception2()
             x.errorCode = 2002
-            x.struct_thing = Xtruct().apply { string_thing = "This is an Xception2" }
+            x.struct_thing =
+                Xtruct().apply {
+                    string_thing = "This is an Xception2"
+                    byte_thing = 0
+                    i32_thing = 0
+                    i64_thing = 0
+                }
             throw x
         }
         val result = Xtruct()
         result.string_thing = arg1
+        result.byte_thing = 0
+        result.i32_thing = 0
+        result.i64_thing = 0
         return result
     }
 
diff --git a/lib/swift/Makefile.am b/lib/swift/Makefile.am
index 6b88b06..6a6644a 100644
--- a/lib/swift/Makefile.am
+++ b/lib/swift/Makefile.am
@@ -30,7 +30,7 @@
 	rm -rf .build
 
 precross:
-	swift
+	swift build
 
 check-local:
 	swift test
diff --git a/lib/swift/Sources/LinuxHelper.swift b/lib/swift/Sources/LinuxHelper.swift
index 66d92bb..83603f8 100644
--- a/lib/swift/Sources/LinuxHelper.swift
+++ b/lib/swift/Sources/LinuxHelper.swift
@@ -24,10 +24,6 @@
 #if os(Linux)
 /// Extensions for Linux for incomplete Foundation API's.
 /// swift-corelibs-foundation is not yet 1:1 with OSX/iOS Foundation
-
-extension CFSocketError {
-  public static let success = kCFSocketSuccess
-}
   
 extension UInt {
   public static func &(lhs: UInt, rhs: Int) -> UInt {
diff --git a/lib/swift/Sources/TBinaryProtocol.swift b/lib/swift/Sources/TBinaryProtocol.swift
index 85acce0..766027e 100644
--- a/lib/swift/Sources/TBinaryProtocol.swift
+++ b/lib/swift/Sources/TBinaryProtocol.swift
@@ -191,6 +191,16 @@
     return buff[0]
   }
   
+  public func read() throws -> Int8 {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 1)
+    }
+    return buff.withUnsafeBytes { pntr in
+      return pntr.load(as: Int8.self)
+    }
+  }
+  
   public func read() throws -> Int16 {
     var buff = Data()
     try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
@@ -246,6 +256,20 @@
     return data
   }
   
+  public func read() throws -> UUID {
+    let data = try self.transport.readAll(size: 16)
+    let lsb = data[0..<8]
+    let msb = data[8..<16]
+    
+    var id = UUID().uuid
+    withUnsafeMutableBytes(of: &id) { pntr in
+      var copyData = msb
+      copyData.append(lsb)
+      copyData.copyBytes(to: pntr)
+    }
+    return UUID(uuid: id)
+  }
+  
   // Write methods
   
   public func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws {
@@ -332,6 +356,14 @@
     }
   }
   
+  public func write(_ value: Int8) throws {
+    var value = value
+    let buff = Data(bytes: &value, count: MemoryLayout<Int8>.size(ofValue: value))
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: buff)
+    }
+  }
+  
   public func write(_ value: Int16) throws {
     var buff = Data()
     buff.append(Data([UInt8(0xff & (value >> 8))]))
@@ -381,4 +413,18 @@
       try self.transport.write(data: data)
     }
   }
+  
+  public func write(_ value: UUID) throws {
+    let data = withUnsafePointer(to: value.uuid) {
+      Data(bytes: $0, count: MemoryLayout.size(ofValue: value.uuid))
+    }
+    let msb = data[0..<8]
+    let lsb = data[8..<16]
+    
+    var buff = Data()
+    buff.append(lsb)
+    buff.append(msb)
+    
+    try self.transport.write(data: buff)
+  }
 }
diff --git a/lib/swift/Sources/TCompactProtocol.swift b/lib/swift/Sources/TCompactProtocol.swift
index 81a51f5..482178e 100644
--- a/lib/swift/Sources/TCompactProtocol.swift
+++ b/lib/swift/Sources/TCompactProtocol.swift
@@ -34,6 +34,7 @@
   case set           = 0x0A
   case map           = 0x0B
   case `struct`      = 0x0C
+  case uuid          = 0x0D
   
   public static let typeMask: UInt8 = 0xE0 // 1110 0000
   public static let typeBits: UInt8 = 0x07 // 0000 0111
@@ -188,6 +189,7 @@
     case .set: return .set;
     case .map: return .map;
     case .struct: return .struct;
+    case .uuid: return .uuid;
     }
   }
   
@@ -207,7 +209,8 @@
     case .set:    return .set
     case .list:   return .list
     case .utf8:   return .binary
-    case .utf16:  return .binary
+      //case .utf16:  return .binary
+    case .uuid:   return .uuid
     }
   }
   
@@ -261,7 +264,8 @@
     guard let mtype = TMessageType(rawValue: Int32(type)) else {
       throw TProtocolError(message: "Unknown TMessageType value: \(type)")
     }
-    let sequenceId = try readVarint32()
+    let varint = zigZagToi32(try readVarint32())
+    let sequenceId = Int32(varint)
     let name: String = try read()
     
     return (name, mtype, Int32(sequenceId))
@@ -351,6 +355,16 @@
     return buff
   }
   
+  public func read() throws -> Int8 {
+    var buff = Data()
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport Read Failed")) {
+      buff = try self.transport.readAll(size: 1)
+    }
+    return buff.withUnsafeBytes { pntr in
+      return pntr.load(as: Int8.self)
+    }
+  }
+  
   public func read() throws -> Int16 {
     let v = try readVarint32()
     return Int16(zigZagToi32(v))
@@ -381,6 +395,20 @@
     return try readBinary(Int(length))
   }
   
+  public func read() throws -> UUID {
+    let data = try self.transport.readAll(size: 16)
+    let lsb = data[0..<data.count/2]
+    let msb = data[(data.count/2)..<data.count]
+    
+    var id = UUID().uuid
+    withUnsafeMutableBytes(of: &id) { pntr in
+      var copyData = msb
+      copyData.append(lsb)
+      copyData.copyBytes(to: pntr)
+    }
+    return UUID(uuid: id)
+  }
+  
   public func readMapBegin() throws -> (TType, TType, Int32) {
     var keyAndValueType: UInt8 = 8
     let size = try readVarint32()
@@ -423,7 +451,7 @@
                           (UInt8((UInt32(messageType.rawValue) << UInt32(TCType.typeShiftAmount))) &
                           TCType.typeMask)
     try writebyteDirect(nextByte)
-    try writeVarint32(UInt32(sequenceID))
+    try writeVarint32(i32ToZigZag(sequenceID))
     try write(name)
     
     currentMessageName = name
@@ -536,7 +564,15 @@
   public func write(_ value: UInt8) throws {
     try writebyteDirect(value)
   }
-
+  
+  public func write(_ value: Int8) throws {
+    var value = value
+    let buff = Data(bytes: &value, count: MemoryLayout<Int8>.size(ofValue: value))
+    try ProtocolTransportTry(error: TProtocolError(message: "Transport write failed")) {
+      try self.transport.write(data: buff)
+    }
+  }
+  
   public func write(_ value: Int16) throws {
     try writeVarint32(i32ToZigZag(Int32(value)))
   }
@@ -565,4 +601,18 @@
       try self.transport.write(data: data)
     }
   }
+  
+  public func write(_ value: UUID) throws {
+    let data = withUnsafePointer(to: value.uuid) {
+      Data(bytes: $0, count: MemoryLayout.size(ofValue: value.uuid))
+    }
+    let msb = data[0..<data.count/2]
+    let lsb = data[(data.count/2)..<data.count]
+    
+    var buff = Data()
+    buff.append(lsb)
+    buff.append(msb)
+    
+    try self.transport.write(data: buff)
+  }
 }
diff --git a/lib/swift/Sources/TMap.swift b/lib/swift/Sources/TMap.swift
index 8f52067..7a93630 100644
--- a/lib/swift/Sources/TMap.swift
+++ b/lib/swift/Sources/TMap.swift
@@ -180,5 +180,5 @@
   if lhs.count != rhs.count {
     return false
   }
-  return lhs.storage.elementsEqual(rhs.storage) { $0.key == $1.key && $0.value == $1.value }
+  return lhs.storage == rhs.storage
 }
diff --git a/lib/swift/Sources/TProtocol.swift b/lib/swift/Sources/TProtocol.swift
index b4e5dbe..87e3bc5 100644
--- a/lib/swift/Sources/TProtocol.swift
+++ b/lib/swift/Sources/TProtocol.swift
@@ -41,7 +41,8 @@
   case set      = 14
   case list     = 15
   case utf8     = 16
-  case utf16    = 17
+  //case utf16    = 17
+  case uuid     = 17
 }
 
 public protocol TProtocol {
@@ -65,12 +66,14 @@
   func read() throws -> String
   func read() throws -> Bool
   func read() throws -> UInt8
+  func read() throws -> Int8
   func read() throws -> Int16
   func read() throws -> Int32
   func read() throws -> Int64
   func read() throws -> Double
   func read() throws -> Data
-  
+  func read() throws -> UUID
+    
   // Writing methods
   
   func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws
@@ -90,11 +93,13 @@
   func write(_ value: String) throws
   func write(_ value: Bool) throws
   func write(_ value: UInt8) throws
+  func write(_ value: Int8) throws
   func write(_ value: Int16) throws
   func write(_ value: Int32) throws
   func write(_ value: Int64) throws
   func write(_ value: Double) throws
   func write(_ value: Data) throws
+  func write(_ value: UUID) throws
 }
 
 public extension TProtocol {
@@ -132,12 +137,13 @@
   func skip(type: TType) throws {
     switch type {
     case .bool:   _ = try read() as Bool
-    case .i8:   _ = try read() as UInt8
+    case .i8:   _ = try read() as Int8
     case .i16:    _ = try read() as Int16
     case .i32:    _ = try read() as Int32
     case .i64:    _ = try read() as Int64
     case .double: _ = try read() as Double
     case .string: _ = try read() as String
+    case .uuid: _ = try read() as UUID
       
     case .struct:
       _ = try readStructBegin()
diff --git a/lib/swift/Sources/TProtocolDecorator.swift b/lib/swift/Sources/TProtocolDecorator.swift
index b1b1480..e831f27 100644
--- a/lib/swift/Sources/TProtocolDecorator.swift
+++ b/lib/swift/Sources/TProtocolDecorator.swift
@@ -92,6 +92,10 @@
   func read() throws -> UInt8 {
     return try proto.read()
   }
+    
+  func read() throws -> Int8 {
+    return try proto.read()
+  }
 
   func read() throws -> Int16 {
     return try proto.read()
@@ -112,6 +116,10 @@
   func read() throws -> Data {
     return try proto.read()
   }
+    
+  func read() throws -> UUID {
+    return try proto.read()
+  }
 
   func writeMessageBegin(name: String, type messageType: TMessageType, sequenceID: Int32) throws {
     try proto.writeMessageBegin(name: name, type: messageType, sequenceID: sequenceID)
@@ -176,6 +184,10 @@
   func write(_ value: UInt8) throws {
     try proto.write(value)
   }
+    
+  func write(_ value: Int8) throws {
+    try proto.write(value)
+  }
 
   func write(_ value: Int16) throws {
     try proto.write(value)
@@ -196,4 +208,8 @@
   func write(_ value: Data) throws {
     try proto.write(value)
   }
+    
+  func write(_ value: UUID) throws {
+    try proto.write(value)
+  }
 }
diff --git a/lib/swift/Sources/TSerializable.swift b/lib/swift/Sources/TSerializable.swift
index 1374700..ff976eb 100644
--- a/lib/swift/Sources/TSerializable.swift
+++ b/lib/swift/Sources/TSerializable.swift
@@ -61,11 +61,11 @@
   public static var thriftType: TType { return .i8 }
 
   public static func read(from proto: TProtocol) throws -> Int8 {
-    return Int8(try proto.read() as UInt8)
+    return try proto.read() as Int8
   }
 
   public func write(to proto: TProtocol) throws {
-    try proto.write(UInt8(self))
+    try proto.write(Int8(self))
   }
 }
 
@@ -129,3 +129,15 @@
     try proto.write(self)
   }
 }
+
+extension UUID : TSerializable {
+  public static var thriftType: TType { .uuid }
+  
+  public static func read(from proto: TProtocol) throws -> UUID {
+    return try proto.read()
+  }
+  
+  public func write(to proto: TProtocol) throws {
+    try proto.write(self)
+  }
+}
diff --git a/lib/swift/Sources/TSocketServer.swift b/lib/swift/Sources/TSocketServer.swift
index 7debe9f..6cd9adf 100644
--- a/lib/swift/Sources/TSocketServer.swift
+++ b/lib/swift/Sources/TSocketServer.swift
@@ -96,26 +96,21 @@
 
     // throw away our socket
     CFSocketInvalidate(sock)
-
-    // register for notifications of accepted incoming connections
-    _ = NotificationCenter.default.addObserver(forName: .NSFileHandleConnectionAccepted,
-                                               object: nil, queue: nil) {
-                                                [weak self] notification in
-                                                guard let strongSelf = self else { return }
-                                                guard let clientSocket = notification.userInfo?[NSFileHandleNotificationFileHandleItem] as? FileHandle else { return }
-                                                strongSelf.connectionAccepted(clientSocket)
-    }
-
-    // tell socket to listen
-    socketFileHandle.acceptConnectionInBackgroundAndNotify()
-
+    
     print("TSocketServer: Listening on TCP port \(port)")
+    
+    // tell socket to listen
+    acceptConnectionInBackgroundAndNotify(handle: socketFileHandle)
   }
-
-  deinit {
-    NotificationCenter.default.removeObserver(self)
+  
+  private func acceptConnectionInBackgroundAndNotify(handle: FileHandle) {
+    DispatchQueue(label: "TSocketServer.connectionAccept").async {
+      let acceptedFD = accept(handle.fileDescriptor, nil, nil)
+      DispatchQueue.main.async {
+        self.connectionAccepted(FileHandle(fileDescriptor: acceptedFD))
+      }
+    }
   }
-
   func connectionAccepted(_ clientSocket: FileHandle) {
     // Now that we have a client connected, handle the request on queue
     processingQueue.async {
@@ -123,7 +118,7 @@
     }
 
     // continue accepting connections
-    socketFileHandle.acceptConnectionInBackgroundAndNotify()
+    acceptConnectionInBackgroundAndNotify(handle: socketFileHandle)
   }
 
   open func createTransport(fileHandle: FileHandle) -> TTransport {
@@ -145,7 +140,7 @@
     DispatchQueue.main.async {
       NotificationCenter.default
         .post(name: Notification.Name(rawValue: TSocketServerClientConnectionFinished),
-              object: self,
+              object: nil,
               userInfo: [TSocketServerProcessorKey: self.processor,
                          TSocketServerTransportKey: transport])
     }
diff --git a/lib/swift/Sources/TWrappedProtocol.swift b/lib/swift/Sources/TWrappedProtocol.swift
index 8e8577b..8e47bd5 100644
--- a/lib/swift/Sources/TWrappedProtocol.swift
+++ b/lib/swift/Sources/TWrappedProtocol.swift
@@ -101,6 +101,10 @@
     return try concreteProtocol.read()
   }
   
+  public func read() throws -> Int8 {
+    return try concreteProtocol.read()
+  }
+    
   public func read() throws -> Int16 {
     return try concreteProtocol.read()
   }
@@ -120,6 +124,10 @@
   public func read() throws -> Data {
     return try concreteProtocol.read()
   }
+    
+  public func read() throws -> UUID {
+    return try concreteProtocol.read()
+  }
   
   // Write methods
   
@@ -185,6 +193,10 @@
   public func write(_ value: UInt8) throws {
     try concreteProtocol.write(value)
   }
+  
+  public func write(_ value: Int8) throws {
+    try concreteProtocol.write(value)
+  }
 
   public func write(_ value: Int16) throws {
     try concreteProtocol.write(value)
@@ -205,4 +217,8 @@
   public func write(_ data: Data) throws {
     try concreteProtocol.write(data)
   }
+    
+  public func write(_ value: UUID) throws {
+    try concreteProtocol.write(value)
+  }
 }