From 45bc029df6c548d445c67c452f7928ca7f4bc9f5 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Thu, 17 Aug 2023 09:29:58 -0700 Subject: [PATCH 01/18] Add `Sendable` conformance to generated clients --- .../GeneratedSources/eliza.connect.swift | 2 +- .../ConnectSwiftPlugin/ConnectClientGenerator.swift | 4 +++- .../Generated/grpc/testing/test.connect.swift | 12 ++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift b/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift index 46a1893b..ef8cf5e9 100644 --- a/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift +++ b/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift @@ -32,7 +32,7 @@ internal protocol Buf_Connect_Demo_Eliza_V1_ElizaServiceClientInterface { } /// Concrete implementation of `Buf_Connect_Demo_Eliza_V1_ElizaServiceClientInterface`. -internal final class Buf_Connect_Demo_Eliza_V1_ElizaServiceClient: Buf_Connect_Demo_Eliza_V1_ElizaServiceClientInterface { +internal final class Buf_Connect_Demo_Eliza_V1_ElizaServiceClient: Buf_Connect_Demo_Eliza_V1_ElizaServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { diff --git a/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift b/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift index d42920e5..e2b8d9f8 100644 --- a/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift +++ b/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift @@ -64,7 +64,9 @@ final class ConnectClientGenerator: Generator { let className = service.implementationName(using: self.namer) self.printLine("/// Concrete implementation of `\(protocolName)`.") - self.printLine("\(self.visibility) final class \(className): \(protocolName) {") + self.printLine( + "\(self.visibility) final class \(className): \(protocolName), Sendable {" + ) self.indent { self.printLine("private let client: Connect.ProtocolClientInterface") self.printLine() diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift index 18a6df6a..137c58b7 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift @@ -117,7 +117,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { } /// Concrete implementation of `Grpc_Testing_TestServiceClientInterface`. -internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceClientInterface { +internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { @@ -266,7 +266,7 @@ internal protocol Grpc_Testing_UnimplementedServiceClientInterface { } /// Concrete implementation of `Grpc_Testing_UnimplementedServiceClientInterface`. -internal final class Grpc_Testing_UnimplementedServiceClient: Grpc_Testing_UnimplementedServiceClientInterface { +internal final class Grpc_Testing_UnimplementedServiceClient: Grpc_Testing_UnimplementedServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { @@ -317,7 +317,7 @@ internal protocol Grpc_Testing_ReconnectServiceClientInterface { } /// Concrete implementation of `Grpc_Testing_ReconnectServiceClientInterface`. -internal final class Grpc_Testing_ReconnectServiceClient: Grpc_Testing_ReconnectServiceClientInterface { +internal final class Grpc_Testing_ReconnectServiceClient: Grpc_Testing_ReconnectServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { @@ -373,7 +373,7 @@ internal protocol Grpc_Testing_LoadBalancerStatsServiceClientInterface { } /// Concrete implementation of `Grpc_Testing_LoadBalancerStatsServiceClientInterface`. -internal final class Grpc_Testing_LoadBalancerStatsServiceClient: Grpc_Testing_LoadBalancerStatsServiceClientInterface { +internal final class Grpc_Testing_LoadBalancerStatsServiceClient: Grpc_Testing_LoadBalancerStatsServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { @@ -425,7 +425,7 @@ internal protocol Grpc_Testing_XdsUpdateHealthServiceClientInterface { } /// Concrete implementation of `Grpc_Testing_XdsUpdateHealthServiceClientInterface`. -internal final class Grpc_Testing_XdsUpdateHealthServiceClient: Grpc_Testing_XdsUpdateHealthServiceClientInterface { +internal final class Grpc_Testing_XdsUpdateHealthServiceClient: Grpc_Testing_XdsUpdateHealthServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { @@ -473,7 +473,7 @@ internal protocol Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface { } /// Concrete implementation of `Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface`. -internal final class Grpc_Testing_XdsUpdateClientConfigureServiceClient: Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface { +internal final class Grpc_Testing_XdsUpdateClientConfigureServiceClient: Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface, Sendable { private let client: Connect.ProtocolClientInterface internal init(client: Connect.ProtocolClientInterface) { From a4710ccdc8c26bcd6cfca6285c912ff1f243882c Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 22 Aug 2023 13:27:29 -0700 Subject: [PATCH 02/18] wip --- .swiftlint.yml | 3 + .../Implementation/Codecs/JSONCodec.swift | 9 +- .../Implementation/Codecs/ProtoCodec.swift | 4 +- .../Generated/grpc/status/v1/status.pb.swift | 4 +- .../Interceptors/ConnectInterceptor.swift | 8 +- .../Interceptors/GRPCWebInterceptor.swift | 6 +- .../Interceptors/InterceptorChain.swift | 2 +- Libraries/Connect/Implementation/Lock.swift | 2 +- Libraries/Connect/Implementation/Locked.swift | 35 +++++++ .../Implementation/ProtocolClient.swift | 58 ++++++------ .../Implementation/ProtocolClientConfig.swift | 12 +-- .../Streaming/BidirectionalAsyncStream.swift | 4 +- .../Streaming/BidirectionalStream.swift | 2 +- .../Streaming/ServerOnlyAsyncStream.swift | 2 +- .../Streaming/ServerOnlyStream.swift | 2 +- .../Streaming/URLSessionStream.swift | 13 +-- .../Implementation/URLSessionHTTPClient.swift | 6 +- .../Implementation/UnaryAsyncWrapper.swift | 6 +- Libraries/Connect/Interfaces/Cancelable.swift | 6 +- Libraries/Connect/Interfaces/Codec.swift | 6 +- .../Connect/Interfaces/CompressionPool.swift | 2 +- .../Connect/Interfaces/ConnectError.swift | 2 +- Libraries/Connect/Interfaces/File.swift | 17 ++++ .../Interfaces/HTTPClientInterface.swift | 4 +- .../Connect/Interfaces/Interceptor.swift | 30 +++--- .../Connect/Interfaces/NetworkProtocol.swift | 4 +- .../Interfaces/ProtocolClientInterface.swift | 24 ++--- .../Connect/Interfaces/ResponseMessage.swift | 2 +- .../BidirectionalAsyncStreamInterface.swift | 4 +- .../BidirectionalStreamInterface.swift | 2 +- .../ClientOnlyAsyncStreamInterface.swift | 4 +- .../Streams/ClientOnlyStreamInterface.swift | 2 +- .../Interfaces/Streams/RequestCallbacks.swift | 10 +- .../Streams/ResponseCallbacks.swift | 14 +-- .../ServerOnlyAsyncStreamInterface.swift | 4 +- .../Streams/ServerOnlyStreamInterface.swift | 2 +- .../MockBidirectionalAsyncStream.swift | 4 +- .../MockBidirectionalStream.swift | 4 +- .../MockClientOnlyAsyncStream.swift | 4 +- .../ConnectMocks/MockClientOnlyStream.swift | 4 +- .../MockServerOnlyAsyncStream.swift | 4 +- .../ConnectMocks/MockServerOnlyStream.swift | 4 +- Package.swift | 3 +- .../ConnectTests/ConnectErrorTests.swift | 2 +- .../Generated/grpc/testing/empty.pb.swift | 4 +- .../Generated/grpc/testing/messages.pb.swift | 92 +++++++++---------- .../Generated/server/v1/server.pb.swift | 12 +-- 47 files changed, 260 insertions(+), 194 deletions(-) create mode 100644 Libraries/Connect/Implementation/Locked.swift create mode 100644 Libraries/Connect/Interfaces/File.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 127ed03d..8fe33263 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -114,6 +114,9 @@ custom_rules: newline_before_brace: name: "Closing braces shouldn't have empty lines before them" regex: '\n\n\}' + sendable_order: + name: "Use @escaping before @Sendable" + regex: '@Sendable\s+@escaping' space_before_comma: name: "Commas should never have a space before them" regex: '\s+,' diff --git a/Libraries/Connect/Implementation/Codecs/JSONCodec.swift b/Libraries/Connect/Implementation/Codecs/JSONCodec.swift index a42bde37..fd30a205 100644 --- a/Libraries/Connect/Implementation/Codecs/JSONCodec.swift +++ b/Libraries/Connect/Implementation/Codecs/JSONCodec.swift @@ -13,10 +13,11 @@ // limitations under the License. import Foundation -import SwiftProtobuf +// TODO: Remove @preconcurrency once JSON(Encoding|Decoding)Options are Sendable +@preconcurrency import SwiftProtobuf /// Codec providing functionality for serializing to/from JSON. -public struct JSONCodec { +public struct JSONCodec: Sendable { private let encodingOptions: JSONEncodingOptions private let decodingOptions: JSONDecodingOptions = { var options = JSONDecodingOptions() @@ -43,11 +44,11 @@ extension JSONCodec: Codec { return "json" } - public func serialize(message: Input) throws -> Data { + public func serialize(message: Input) throws -> Data { return try message.jsonUTF8Data(options: self.encodingOptions) } - public func deserialize(source: Data) throws -> Output { + public func deserialize(source: Data) throws -> Output { return try Output(jsonUTF8Data: source, options: self.decodingOptions) } } diff --git a/Libraries/Connect/Implementation/Codecs/ProtoCodec.swift b/Libraries/Connect/Implementation/Codecs/ProtoCodec.swift index 38d86987..068db0ec 100644 --- a/Libraries/Connect/Implementation/Codecs/ProtoCodec.swift +++ b/Libraries/Connect/Implementation/Codecs/ProtoCodec.swift @@ -25,11 +25,11 @@ extension ProtoCodec: Codec { return "proto" } - public func serialize(message: Input) throws -> Data { + public func serialize(message: Input) throws -> Data { return try message.serializedData() } - public func deserialize(source: Data) throws -> Output { + public func deserialize(source: Data) throws -> Output { return try Output(serializedData: source) } } diff --git a/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift b/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift index f037f755..ae0915e8 100644 --- a/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift +++ b/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift @@ -39,7 +39,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This struct must remain binary-compatible with /// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto. struct Grpc_Status_V1_Status { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -64,7 +64,7 @@ extension Grpc_Status_V1_Status: @unchecked Sendable {} fileprivate let _protobuf_package = "grpc.status.v1" -extension Grpc_Status_V1_Status: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Status_V1_Status: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".Status" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "code"), diff --git a/Libraries/Connect/Implementation/Interceptors/ConnectInterceptor.swift b/Libraries/Connect/Implementation/Interceptors/ConnectInterceptor.swift index 062c948f..f2507b0c 100644 --- a/Libraries/Connect/Implementation/Interceptors/ConnectInterceptor.swift +++ b/Libraries/Connect/Implementation/Interceptors/ConnectInterceptor.swift @@ -101,7 +101,7 @@ extension ConnectInterceptor: Interceptor { } func streamFunction() -> StreamFunction { - var responseHeaders: Headers? + let responseHeaders = Locked(nil) return StreamFunction( requestFunction: { request in var headers = request.headers @@ -124,12 +124,12 @@ extension ConnectInterceptor: Interceptor { streamResultFunction: { result in switch result { case .headers(let headers): - responseHeaders = headers + responseHeaders.value = headers return result case .message(let data): do { - let responseCompressionPool = responseHeaders?[ + let responseCompressionPool = responseHeaders.value?[ HeaderConstants.connectStreamingContentEncoding ]?.first.flatMap { self.config.responseCompressionPool(forName: $0) } let (headerByte, message) = try Envelope.unpackMessage( @@ -161,7 +161,7 @@ extension ConnectInterceptor: Interceptor { code: code, error: ConnectError.from( code: code, - headers: responseHeaders ?? [:], + headers: responseHeaders.value ?? [:], source: nil ), trailers: trailers diff --git a/Libraries/Connect/Implementation/Interceptors/GRPCWebInterceptor.swift b/Libraries/Connect/Implementation/Interceptors/GRPCWebInterceptor.swift index 3d54ab09..511e84ce 100644 --- a/Libraries/Connect/Implementation/Interceptors/GRPCWebInterceptor.swift +++ b/Libraries/Connect/Implementation/Interceptors/GRPCWebInterceptor.swift @@ -111,7 +111,7 @@ extension GRPCWebInterceptor: Interceptor { } func streamFunction() -> StreamFunction { - var responseHeaders: Headers? + let responseHeaders = Locked(nil) return StreamFunction( requestFunction: { request in return HTTPRequest( @@ -137,13 +137,13 @@ extension GRPCWebInterceptor: Interceptor { trailers: headers ) } else { - responseHeaders = headers + responseHeaders.value = headers return result } case .message(let data): do { - let responseCompressionPool = responseHeaders?[ + let responseCompressionPool = responseHeaders.value?[ HeaderConstants.grpcContentEncoding ]?.first.flatMap { self.config.responseCompressionPool(forName: $0) } let (headerByte, unpackedData) = try Envelope.unpackMessage( diff --git a/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift b/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift index e92866ad..74963506 100644 --- a/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift +++ b/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift @@ -14,7 +14,7 @@ /// Represents a chain of interceptors that is used for a single request/stream, /// and orchestrates invoking each of them in the proper order. -struct InterceptorChain { +struct InterceptorChain: Sendable { private let interceptors: [Interceptor] /// Initialize the interceptor chain. diff --git a/Libraries/Connect/Implementation/Lock.swift b/Libraries/Connect/Implementation/Lock.swift index 74fa3995..dc9343c8 100644 --- a/Libraries/Connect/Implementation/Lock.swift +++ b/Libraries/Connect/Implementation/Lock.swift @@ -15,7 +15,7 @@ import Foundation /// Internal implementation of a lock. Wraps usage of `os_unfair_lock`. -final class Lock { +final class Lock: Sendable { private let underlyingLock: UnsafeMutablePointer init() { diff --git a/Libraries/Connect/Implementation/Locked.swift b/Libraries/Connect/Implementation/Locked.swift new file mode 100644 index 00000000..8f80f523 --- /dev/null +++ b/Libraries/Connect/Implementation/Locked.swift @@ -0,0 +1,35 @@ +// Copyright 2022-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +final class Locked: @unchecked Sendable { + private let lock = Lock() + private var _value: T + + var value: T { + get { self.lock.perform { self._value } } + set { self.lock.perform { self._value = newValue } } + } + + func perform(action: @escaping (inout T) -> Void) { + self.lock.perform { + action(&self._value) + } + } + + init(_ value: T) { + self._value = value + } +} diff --git a/Libraries/Connect/Implementation/ProtocolClient.swift b/Libraries/Connect/Implementation/ProtocolClient.swift index 150f0a32..7e06551d 100644 --- a/Libraries/Connect/Implementation/ProtocolClient.swift +++ b/Libraries/Connect/Implementation/ProtocolClient.swift @@ -39,12 +39,12 @@ extension ProtocolClient: ProtocolClientInterface { @discardableResult public func unary< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, request: Input, headers: Headers, - completion: @escaping (ResponseMessage) -> Void + completion: @escaping @Sendable (ResponseMessage) -> Void ) -> Cancelable { let codec = self.config.codec let data: Data @@ -123,11 +123,11 @@ extension ProtocolClient: ProtocolClientInterface { } public func bidirectionalStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> any BidirectionalStreamInterface { return BidirectionalStream( requestCallbacks: self.createRequestCallbacks( @@ -138,11 +138,11 @@ extension ProtocolClient: ProtocolClientInterface { } public func clientOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> any ClientOnlyStreamInterface { return BidirectionalStream( requestCallbacks: self.createRequestCallbacks( @@ -153,11 +153,11 @@ extension ProtocolClient: ProtocolClientInterface { } public func serverOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> any ServerOnlyStreamInterface { return ServerOnlyStream(bidirectionalStream: BidirectionalStream( requestCallbacks: self.createRequestCallbacks( @@ -171,7 +171,7 @@ extension ProtocolClient: ProtocolClientInterface { @available(iOS 13, *) public func unary< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, request: Input, @@ -184,7 +184,7 @@ extension ProtocolClient: ProtocolClientInterface { @available(iOS 13, *) public func bidirectionalStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers @@ -198,7 +198,7 @@ extension ProtocolClient: ProtocolClientInterface { @available(iOS 13, *) public func clientOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers @@ -212,7 +212,7 @@ extension ProtocolClient: ProtocolClientInterface { @available(iOS 13, *) public func serverOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers @@ -228,7 +228,7 @@ extension ProtocolClient: ProtocolClientInterface { // MARK: - Private - private func createRequestCallbacks( + private func createRequestCallbacks( path: String, headers: Headers, onResult: @escaping (StreamResult) -> Void @@ -261,25 +261,29 @@ extension ProtocolClient: ProtocolClientInterface { ) } } - var responseBuffer = Data() + let responseBuffer = Locked(Data()) let responseCallbacks = ResponseCallbacks( receiveResponseHeaders: { interceptAndHandleResult(.headers($0)) }, receiveResponseData: { responseChunk in // Repeating handles cases where multiple messages are received in a single chunk. - responseBuffer += responseChunk - while true { - let messageLength = Envelope.messageLength(forPackedData: responseBuffer) - if messageLength < 0 { - return - } + responseBuffer.perform { responseBuffer in + responseBuffer += responseChunk + while true { + let messageLength = Envelope.messageLength(forPackedData: responseBuffer) + if messageLength < 0 { + return + } - let prefixedMessageLength = Envelope.prefixLength + messageLength - guard responseBuffer.count >= prefixedMessageLength else { - return - } + let prefixedMessageLength = Envelope.prefixLength + messageLength + guard responseBuffer.count >= prefixedMessageLength else { + return + } - interceptAndHandleResult(.message(responseBuffer.prefix(prefixedMessageLength))) - responseBuffer = Data(responseBuffer.suffix(from: prefixedMessageLength)) + interceptAndHandleResult( + .message(responseBuffer.prefix(prefixedMessageLength)) + ) + responseBuffer = Data(responseBuffer.suffix(from: prefixedMessageLength)) + } } }, receiveClose: { code, trailers, error in @@ -306,7 +310,7 @@ extension ProtocolClient: ProtocolClientInterface { } private extension StreamResult { - func toTypedResult(using codec: Codec) throws -> StreamResult { + func toTypedResult(using codec: Codec) throws -> StreamResult { switch self { case .complete(let code, let error, let trailers): return .complete(code: code, error: error, trailers: trailers) diff --git a/Libraries/Connect/Implementation/ProtocolClientConfig.swift b/Libraries/Connect/Implementation/ProtocolClientConfig.swift index 8955146f..0b0e5849 100644 --- a/Libraries/Connect/Implementation/ProtocolClientConfig.swift +++ b/Libraries/Connect/Implementation/ProtocolClientConfig.swift @@ -15,7 +15,7 @@ import Foundation /// Configuration used to set up `ProtocolClientInterface` implementations. -public struct ProtocolClientConfig { +public struct ProtocolClientConfig: Sendable { /// Target host (e.g., `https://buf.build`). public let host: String /// Protocol to use for requests and streams. @@ -28,10 +28,10 @@ public struct ProtocolClientConfig { /// response headers like `content-encoding`. public let responseCompressionPools: [CompressionPool] /// List of interceptors that should be invoked with requests/responses. - public let interceptors: [(ProtocolClientConfig) -> Interceptor] + public let interceptors: [@Sendable (ProtocolClientConfig) -> Interceptor] /// Configuration used to specify if/how requests should be compressed. - public struct RequestCompression { + public struct RequestCompression: Sendable { /// The minimum number of bytes that a request message should be for compression to be used. public let minBytes: Int /// The compression pool that should be used for compressing outbound requests. @@ -53,7 +53,7 @@ public struct ProtocolClientConfig { codec: Codec = JSONCodec(), requestCompression: RequestCompression? = nil, responseCompressionPools: [CompressionPool] = [GzipCompressionPool()], - interceptors: [(ProtocolClientConfig) -> Interceptor] = [] + interceptors: [@Sendable (ProtocolClientConfig) -> Interceptor] = [] ) { self.host = host self.networkProtocol = networkProtocol @@ -63,9 +63,9 @@ public struct ProtocolClientConfig { switch networkProtocol { case .connect: - self.interceptors = interceptors + [ConnectInterceptor.init] + self.interceptors = interceptors + [{ ConnectInterceptor.init(config: $0) }] case .grpcWeb: - self.interceptors = interceptors + [GRPCWebInterceptor.init] + self.interceptors = interceptors + [{ GRPCWebInterceptor.init(config: $0) }] case .custom(_, let protocolInterceptor): self.interceptors = interceptors + [protocolInterceptor] } diff --git a/Libraries/Connect/Implementation/Streaming/BidirectionalAsyncStream.swift b/Libraries/Connect/Implementation/Streaming/BidirectionalAsyncStream.swift index 685bab5e..e690f789 100644 --- a/Libraries/Connect/Implementation/Streaming/BidirectionalAsyncStream.swift +++ b/Libraries/Connect/Implementation/Streaming/BidirectionalAsyncStream.swift @@ -18,7 +18,9 @@ import SwiftProtobuf /// Provides the necessary wiring to bridge from closures/callbacks to Swift's `AsyncStream` /// to work with async/await. @available(iOS 13, *) -final class BidirectionalAsyncStream { +final class BidirectionalAsyncStream< + Input: ProtobufMessage, Output: ProtobufMessage +>: @unchecked Sendable { /// The underlying async stream that will be exposed to the consumer. /// Force unwrapped because it captures `self` on `init`. private var asyncStream: AsyncStream>! diff --git a/Libraries/Connect/Implementation/Streaming/BidirectionalStream.swift b/Libraries/Connect/Implementation/Streaming/BidirectionalStream.swift index cac94dca..c112a744 100644 --- a/Libraries/Connect/Implementation/Streaming/BidirectionalStream.swift +++ b/Libraries/Connect/Implementation/Streaming/BidirectionalStream.swift @@ -15,7 +15,7 @@ import SwiftProtobuf /// Concrete implementation of `BidirectionalStreamInterface`. -final class BidirectionalStream { +final class BidirectionalStream: Sendable { private let requestCallbacks: RequestCallbacks private let codec: Codec diff --git a/Libraries/Connect/Implementation/Streaming/ServerOnlyAsyncStream.swift b/Libraries/Connect/Implementation/Streaming/ServerOnlyAsyncStream.swift index f185a81d..af345ac0 100644 --- a/Libraries/Connect/Implementation/Streaming/ServerOnlyAsyncStream.swift +++ b/Libraries/Connect/Implementation/Streaming/ServerOnlyAsyncStream.swift @@ -16,7 +16,7 @@ import SwiftProtobuf /// Concrete implementation of `ServerOnlyAsyncStreamInterface`. @available(iOS 13, *) -final class ServerOnlyAsyncStream { +final class ServerOnlyAsyncStream: Sendable { private let bidirectionalStream: BidirectionalAsyncStream init(bidirectionalStream: BidirectionalAsyncStream) { diff --git a/Libraries/Connect/Implementation/Streaming/ServerOnlyStream.swift b/Libraries/Connect/Implementation/Streaming/ServerOnlyStream.swift index ae159f3a..a54abd5d 100644 --- a/Libraries/Connect/Implementation/Streaming/ServerOnlyStream.swift +++ b/Libraries/Connect/Implementation/Streaming/ServerOnlyStream.swift @@ -15,7 +15,7 @@ import SwiftProtobuf /// Concrete implementation of `ServerOnlyStreamInterface`. -final class ServerOnlyStream { +final class ServerOnlyStream: Sendable { private let bidirectionalStream: BidirectionalStream init(bidirectionalStream: BidirectionalStream) { diff --git a/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift b/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift index 58642c1b..9de5b17b 100644 --- a/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift +++ b/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift @@ -15,10 +15,11 @@ import Foundation /// Stream implementation that wraps a `URLSession` stream. -final class URLSessionStream: NSObject { - private var closedByServer = false +final class URLSessionStream: NSObject, @unchecked Sendable { + private let closedByServer = Locked(false) private let responseCallbacks: ResponseCallbacks private let task: URLSessionUploadTask + /// Foundation.OutputStream does not conform to Sendable, hence @unchecked on the above class. private let writeStream: Foundation.OutputStream enum Error: Swift.Error { @@ -91,23 +92,23 @@ final class URLSessionStream: NSObject { let code = Code.fromURLSessionCode(response.statusCode) self.responseCallbacks.receiveResponseHeaders(response.formattedLowercasedHeaders()) if code != .ok { - self.closedByServer = true + self.closedByServer.value = true self.responseCallbacks.receiveClose(code, [:], nil) } } func handleResponseData(_ data: Data) { - if !self.closedByServer { + if !self.closedByServer.value { self.responseCallbacks.receiveResponseData(data) } } func handleCompletion(error: Swift.Error?) { - if self.closedByServer { + if self.closedByServer.value { return } - self.closedByServer = true + self.closedByServer.value = true if let error = error { self.responseCallbacks.receiveClose( Code.fromURLSessionCode((error as NSError).code), diff --git a/Libraries/Connect/Implementation/URLSessionHTTPClient.swift b/Libraries/Connect/Implementation/URLSessionHTTPClient.swift index 7312eec6..aad9aec3 100644 --- a/Libraries/Connect/Implementation/URLSessionHTTPClient.swift +++ b/Libraries/Connect/Implementation/URLSessionHTTPClient.swift @@ -42,8 +42,8 @@ open class URLSessionHTTPClient: NSObject, HTTPClientInterface { @discardableResult open func unary( request: HTTPRequest, - onMetrics: @Sendable @escaping (HTTPMetrics) -> Void, - onResponse: @Sendable @escaping (HTTPResponse) -> Void + onMetrics: @escaping @Sendable (HTTPMetrics) -> Void, + onResponse: @escaping @Sendable (HTTPResponse) -> Void ) -> Cancelable { assert(!request.isGRPC, "URLSessionHTTPClient does not support gRPC, use NIOHTTPClient") let urlRequest = URLRequest(httpRequest: request) @@ -88,7 +88,7 @@ open class URLSessionHTTPClient: NSObject, HTTPClientInterface { } self.lock.perform { self.metricsClosures[task.taskIdentifier] = onMetrics } task.resume() - return Cancelable(cancel: task.cancel) + return Cancelable { task.cancel() } } open func stream( diff --git a/Libraries/Connect/Implementation/UnaryAsyncWrapper.swift b/Libraries/Connect/Implementation/UnaryAsyncWrapper.swift index eb0fdc74..600a132b 100644 --- a/Libraries/Connect/Implementation/UnaryAsyncWrapper.swift +++ b/Libraries/Connect/Implementation/UnaryAsyncWrapper.swift @@ -21,14 +21,14 @@ import SwiftProtobuf /// https://forums.swift.org/t/how-to-use-withtaskcancellationhandler-properly/54341/37 /// https://stackoverflow.com/q/71898080 @available(iOS 13, *) -actor UnaryAsyncWrapper { +actor UnaryAsyncWrapper: Sendable { private var cancelable: Cancelable? private let sendUnary: PerformClosure /// Accepts a closure to be called upon completion of a request and returns a cancelable which, /// when invoked, will cancel the underlying request. - typealias PerformClosure = ( - @escaping (ResponseMessage) -> Void + typealias PerformClosure = @Sendable ( + @escaping @Sendable (ResponseMessage) -> Void ) -> Cancelable init(sendUnary: @escaping PerformClosure) { diff --git a/Libraries/Connect/Interfaces/Cancelable.swift b/Libraries/Connect/Interfaces/Cancelable.swift index 33c24b29..575efacc 100644 --- a/Libraries/Connect/Interfaces/Cancelable.swift +++ b/Libraries/Connect/Interfaces/Cancelable.swift @@ -13,11 +13,11 @@ // limitations under the License. /// Type that wraps an action that can be canceled. -public struct Cancelable { +public struct Cancelable: Sendable { /// Cancel the current action. - public let cancel: () -> Void + public let cancel: @Sendable () -> Void - public init(cancel: @escaping () -> Void) { + public init(cancel: @escaping @Sendable () -> Void) { self.cancel = cancel } } diff --git a/Libraries/Connect/Interfaces/Codec.swift b/Libraries/Connect/Interfaces/Codec.swift index 28fcafa3..991f46b6 100644 --- a/Libraries/Connect/Interfaces/Codec.swift +++ b/Libraries/Connect/Interfaces/Codec.swift @@ -16,7 +16,7 @@ import Foundation import SwiftProtobuf /// Defines a type that is capable of encoding and decoding messages using a specific format. -public protocol Codec { +public protocol Codec: Sendable { /// - returns: The name of the codec's format (e.g., "json", "protobuf"). Usually consumed /// in the form of adding the `content-type` header via "application/{name}". func name() -> String @@ -26,12 +26,12 @@ public protocol Codec { /// - parameter message: Typed input message. /// /// - returns: Serialized data that can be transmitted. - func serialize(message: Input) throws -> Data + func serialize(message: Input) throws -> Data /// Deserializes data in the codec's format into a typed message. /// /// - parameter source: The source data to deserialize. /// /// - returns: The typed output message. - func deserialize(source: Data) throws -> Output + func deserialize(source: Data) throws -> Output } diff --git a/Libraries/Connect/Interfaces/CompressionPool.swift b/Libraries/Connect/Interfaces/CompressionPool.swift index 8e0445d5..67fd4d00 100644 --- a/Libraries/Connect/Interfaces/CompressionPool.swift +++ b/Libraries/Connect/Interfaces/CompressionPool.swift @@ -22,7 +22,7 @@ import Foundation /// /// Outbound request compression can be specified using additional options that specify a /// `compressionName` that matches a compression pool's `name()`. -public protocol CompressionPool { +public protocol CompressionPool: Sendable { /// The name of the compression pool, which corresponds to the `content-encoding` header. /// Example: `gzip`. /// diff --git a/Libraries/Connect/Interfaces/ConnectError.swift b/Libraries/Connect/Interfaces/ConnectError.swift index e1a3ac1e..1c8f5258 100644 --- a/Libraries/Connect/Interfaces/ConnectError.swift +++ b/Libraries/Connect/Interfaces/ConnectError.swift @@ -37,7 +37,7 @@ public struct ConnectError: Swift.Error, Sendable { /// `let unpackedError: MyError? = error.unpackedDetails().first` /// /// - returns: The matching unpacked typed error details. - public func unpackedDetails() -> [Output] { + public func unpackedDetails() -> [Output] { return self.details.compactMap { detail -> Output? in guard detail.type == Output.protoMessageName else { return nil diff --git a/Libraries/Connect/Interfaces/File.swift b/Libraries/Connect/Interfaces/File.swift new file mode 100644 index 00000000..243e59ec --- /dev/null +++ b/Libraries/Connect/Interfaces/File.swift @@ -0,0 +1,17 @@ +// Copyright 2022-2023 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import SwiftProtobuf + +public protocol ProtobufMessage: SwiftProtobuf.Message, Sendable {} diff --git a/Libraries/Connect/Interfaces/HTTPClientInterface.swift b/Libraries/Connect/Interfaces/HTTPClientInterface.swift index 100065a6..fec28cda 100644 --- a/Libraries/Connect/Interfaces/HTTPClientInterface.swift +++ b/Libraries/Connect/Interfaces/HTTPClientInterface.swift @@ -25,8 +25,8 @@ public protocol HTTPClientInterface { @discardableResult func unary( request: HTTPRequest, - onMetrics: @Sendable @escaping (HTTPMetrics) -> Void, - onResponse: @Sendable @escaping (HTTPResponse) -> Void + onMetrics: @escaping @Sendable (HTTPMetrics) -> Void, + onResponse: @escaping @Sendable (HTTPResponse) -> Void ) -> Cancelable /// Initialize a new HTTP stream. diff --git a/Libraries/Connect/Interfaces/Interceptor.swift b/Libraries/Connect/Interfaces/Interceptor.swift index 5db787d9..acd635af 100644 --- a/Libraries/Connect/Interfaces/Interceptor.swift +++ b/Libraries/Connect/Interfaces/Interceptor.swift @@ -18,7 +18,7 @@ import Foundation /// and inbound responses. /// /// Interceptors are expected to be instantiated once per request/stream. -public protocol Interceptor { +public protocol Interceptor: Sendable { /// Invoked when a unary call is started. Provides a set of closures that will be called /// as the request progresses, allowing the interceptor to alter request/response data. /// @@ -37,15 +37,15 @@ public protocol Interceptor { func streamFunction() -> StreamFunction } -public struct UnaryFunction { - public let requestFunction: (HTTPRequest) -> HTTPRequest - public let responseFunction: (HTTPResponse) -> HTTPResponse - public let responseMetricsFunction: (HTTPMetrics) -> HTTPMetrics +public struct UnaryFunction: Sendable { + public let requestFunction: @Sendable (HTTPRequest) -> HTTPRequest + public let responseFunction: @Sendable (HTTPResponse) -> HTTPResponse + public let responseMetricsFunction: @Sendable (HTTPMetrics) -> HTTPMetrics public init( - requestFunction: @escaping (HTTPRequest) -> HTTPRequest, - responseFunction: @escaping (HTTPResponse) -> HTTPResponse, - responseMetricsFunction: @escaping (HTTPMetrics) -> HTTPMetrics = { $0 } + requestFunction: @escaping @Sendable (HTTPRequest) -> HTTPRequest, + responseFunction: @escaping @Sendable (HTTPResponse) -> HTTPResponse, + responseMetricsFunction: @escaping @Sendable (HTTPMetrics) -> HTTPMetrics = { $0 } ) { self.requestFunction = requestFunction self.responseFunction = responseFunction @@ -53,15 +53,15 @@ public struct UnaryFunction { } } -public struct StreamFunction { - public let requestFunction: (HTTPRequest) -> HTTPRequest - public let requestDataFunction: (Data) -> Data - public let streamResultFunction: (StreamResult) -> StreamResult +public struct StreamFunction: Sendable { + public let requestFunction: @Sendable (HTTPRequest) -> HTTPRequest + public let requestDataFunction: @Sendable (Data) -> Data + public let streamResultFunction: @Sendable (StreamResult) -> StreamResult public init( - requestFunction: @escaping (HTTPRequest) -> HTTPRequest, - requestDataFunction: @escaping (Data) -> Data, - streamResultFunction: @escaping (StreamResult) -> StreamResult + requestFunction: @escaping @Sendable (HTTPRequest) -> HTTPRequest, + requestDataFunction: @escaping @Sendable (Data) -> Data, + streamResultFunction: @escaping @Sendable (StreamResult) -> StreamResult ) { self.requestFunction = requestFunction self.requestDataFunction = requestDataFunction diff --git a/Libraries/Connect/Interfaces/NetworkProtocol.swift b/Libraries/Connect/Interfaces/NetworkProtocol.swift index fbd7be3d..23561e31 100644 --- a/Libraries/Connect/Interfaces/NetworkProtocol.swift +++ b/Libraries/Connect/Interfaces/NetworkProtocol.swift @@ -13,7 +13,7 @@ // limitations under the License. /// Protocols that are supported by the library. -public enum NetworkProtocol { +public enum NetworkProtocol: Sendable { /// The Connect protocol: /// https://connect.build/docs/protocol case connect @@ -21,7 +21,7 @@ public enum NetworkProtocol { /// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md case grpcWeb /// A custom protocol that is implemented via an interceptor. - case custom(name: String, protocolInterceptor: (ProtocolClientConfig) -> Interceptor) + case custom(name: String, protocolInterceptor: @Sendable (ProtocolClientConfig) -> Interceptor) } extension NetworkProtocol: CustomStringConvertible { diff --git a/Libraries/Connect/Interfaces/ProtocolClientInterface.swift b/Libraries/Connect/Interfaces/ProtocolClientInterface.swift index e99ef77c..206cec4b 100644 --- a/Libraries/Connect/Interfaces/ProtocolClientInterface.swift +++ b/Libraries/Connect/Interfaces/ProtocolClientInterface.swift @@ -31,12 +31,12 @@ public protocol ProtocolClientInterface { /// - returns: A `Cancelable` which provides the ability to cancel the outbound request. @discardableResult func unary< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, request: Input, headers: Headers, - completion: @escaping (ResponseMessage) -> Void + completion: @escaping @Sendable (ResponseMessage) -> Void ) -> Cancelable /// Start a new bidirectional stream. @@ -54,11 +54,11 @@ public protocol ProtocolClientInterface { /// /// - returns: An interface for interacting with and sending data over the bidirectional stream. func bidirectionalStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> any BidirectionalStreamInterface /// Start a new client-only stream. @@ -76,11 +76,11 @@ public protocol ProtocolClientInterface { /// /// - returns: An interface for interacting with and sending data over the client-only stream. func clientOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> any ClientOnlyStreamInterface /// Start a new server-only stream. @@ -98,11 +98,11 @@ public protocol ProtocolClientInterface { /// /// - returns: An interface for interacting with and sending data over the server-only stream. func serverOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> any ServerOnlyStreamInterface // MARK: - Async/await @@ -116,7 +116,7 @@ public protocol ProtocolClientInterface { /// - returns: The response which is returned asynchronously. @available(iOS 13, *) func unary< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, request: Input, @@ -137,7 +137,7 @@ public protocol ProtocolClientInterface { /// - returns: An interface for sending and receiving data over the stream using async/await. @available(iOS 13, *) func bidirectionalStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers @@ -157,7 +157,7 @@ public protocol ProtocolClientInterface { /// - returns: An interface for sending and receiving data over the stream using async/await. @available(iOS 13, *) func clientOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers @@ -177,7 +177,7 @@ public protocol ProtocolClientInterface { /// - returns: An interface for sending and receiving data over the stream using async/await. @available(iOS 13, *) func serverOnlyStream< - Input: SwiftProtobuf.Message, Output: SwiftProtobuf.Message + Input: ProtobufMessage, Output: ProtobufMessage >( path: String, headers: Headers diff --git a/Libraries/Connect/Interfaces/ResponseMessage.swift b/Libraries/Connect/Interfaces/ResponseMessage.swift index a7b209b2..73a5b6ef 100644 --- a/Libraries/Connect/Interfaces/ResponseMessage.swift +++ b/Libraries/Connect/Interfaces/ResponseMessage.swift @@ -15,7 +15,7 @@ import SwiftProtobuf /// Typed unary response from an RPC. -public struct ResponseMessage: Sendable { +public struct ResponseMessage: Sendable { /// The status code of the response. public let code: Code /// Response headers specified by the server. diff --git a/Libraries/Connect/Interfaces/Streams/BidirectionalAsyncStreamInterface.swift b/Libraries/Connect/Interfaces/Streams/BidirectionalAsyncStreamInterface.swift index 4d7eb894..d868c12a 100644 --- a/Libraries/Connect/Interfaces/Streams/BidirectionalAsyncStreamInterface.swift +++ b/Libraries/Connect/Interfaces/Streams/BidirectionalAsyncStreamInterface.swift @@ -18,10 +18,10 @@ import SwiftProtobuf @available(iOS 13, *) public protocol BidirectionalAsyncStreamInterface { /// The input (request) message type. - associatedtype Input: SwiftProtobuf.Message + associatedtype Input: ProtobufMessage /// The output (response) message type. - associatedtype Output: SwiftProtobuf.Message + associatedtype Output: ProtobufMessage /// Send a request to the server over the stream. /// diff --git a/Libraries/Connect/Interfaces/Streams/BidirectionalStreamInterface.swift b/Libraries/Connect/Interfaces/Streams/BidirectionalStreamInterface.swift index fc161a22..f334dad8 100644 --- a/Libraries/Connect/Interfaces/Streams/BidirectionalStreamInterface.swift +++ b/Libraries/Connect/Interfaces/Streams/BidirectionalStreamInterface.swift @@ -17,7 +17,7 @@ import SwiftProtobuf /// Represents a bidirectional stream that can send request messages and initiate closes. public protocol BidirectionalStreamInterface { /// The input (request) message type. - associatedtype Input: SwiftProtobuf.Message + associatedtype Input: ProtobufMessage /// Send a request to the server over the stream. /// diff --git a/Libraries/Connect/Interfaces/Streams/ClientOnlyAsyncStreamInterface.swift b/Libraries/Connect/Interfaces/Streams/ClientOnlyAsyncStreamInterface.swift index 20440978..de4334fd 100644 --- a/Libraries/Connect/Interfaces/Streams/ClientOnlyAsyncStreamInterface.swift +++ b/Libraries/Connect/Interfaces/Streams/ClientOnlyAsyncStreamInterface.swift @@ -19,10 +19,10 @@ import SwiftProtobuf @available(iOS 13, *) public protocol ClientOnlyAsyncStreamInterface { /// The input (request) message type. - associatedtype Input: SwiftProtobuf.Message + associatedtype Input: ProtobufMessage /// The output (response) message type. - associatedtype Output: SwiftProtobuf.Message + associatedtype Output: ProtobufMessage /// Send a request to the server over the stream. /// diff --git a/Libraries/Connect/Interfaces/Streams/ClientOnlyStreamInterface.swift b/Libraries/Connect/Interfaces/Streams/ClientOnlyStreamInterface.swift index f066d5d1..629881a5 100644 --- a/Libraries/Connect/Interfaces/Streams/ClientOnlyStreamInterface.swift +++ b/Libraries/Connect/Interfaces/Streams/ClientOnlyStreamInterface.swift @@ -18,7 +18,7 @@ import SwiftProtobuf /// eventually receives a response) that can send request messages and initiate closes. public protocol ClientOnlyStreamInterface { /// The input (request) message type. - associatedtype Input: SwiftProtobuf.Message + associatedtype Input: ProtobufMessage /// Send a request to the server over the stream. /// diff --git a/Libraries/Connect/Interfaces/Streams/RequestCallbacks.swift b/Libraries/Connect/Interfaces/Streams/RequestCallbacks.swift index c31958fa..aa986250 100644 --- a/Libraries/Connect/Interfaces/Streams/RequestCallbacks.swift +++ b/Libraries/Connect/Interfaces/Streams/RequestCallbacks.swift @@ -15,13 +15,15 @@ import Foundation /// Set of closures that are used for wiring outbound request data through to HTTP clients. -public final class RequestCallbacks { +public final class RequestCallbacks: Sendable { /// Closure to send data through to the server. - public let sendData: (Data) -> Void + public let sendData: @Sendable (Data) -> Void /// Closure to initiate a close for a stream. - public let sendClose: () -> Void + public let sendClose: @Sendable () -> Void - public init(sendData: @escaping (Data) -> Void, sendClose: @escaping () -> Void) { + public init( + sendData: @escaping @Sendable (Data) -> Void, sendClose: @escaping @Sendable () -> Void + ) { self.sendData = sendData self.sendClose = sendClose } diff --git a/Libraries/Connect/Interfaces/Streams/ResponseCallbacks.swift b/Libraries/Connect/Interfaces/Streams/ResponseCallbacks.swift index 17523466..441f38c7 100644 --- a/Libraries/Connect/Interfaces/Streams/ResponseCallbacks.swift +++ b/Libraries/Connect/Interfaces/Streams/ResponseCallbacks.swift @@ -15,19 +15,19 @@ import Foundation /// Set of closures that are used for wiring inbound response data through from HTTP clients. -public final class ResponseCallbacks { +public final class ResponseCallbacks: Sendable { /// Closure to call when response headers are available. - public let receiveResponseHeaders: (Headers) -> Void + public let receiveResponseHeaders: @Sendable (Headers) -> Void /// Closure to call when response data is available. - public let receiveResponseData: (Data) -> Void + public let receiveResponseData: @Sendable (Data) -> Void /// Closure to call when the stream is closed. /// Includes the status code, trailers, and potentially an error. - public let receiveClose: (Code, Trailers, Swift.Error?) -> Void + public let receiveClose: @Sendable (Code, Trailers, Swift.Error?) -> Void public init( - receiveResponseHeaders: @escaping (Headers) -> Void, - receiveResponseData: @escaping (Data) -> Void, - receiveClose: @escaping (Code, Trailers, Swift.Error?) -> Void + receiveResponseHeaders: @escaping @Sendable (Headers) -> Void, + receiveResponseData: @escaping @Sendable (Data) -> Void, + receiveClose: @escaping @Sendable (Code, Trailers, Swift.Error?) -> Void ) { self.receiveResponseHeaders = receiveResponseHeaders self.receiveResponseData = receiveResponseData diff --git a/Libraries/Connect/Interfaces/Streams/ServerOnlyAsyncStreamInterface.swift b/Libraries/Connect/Interfaces/Streams/ServerOnlyAsyncStreamInterface.swift index d36829b0..0424fcae 100644 --- a/Libraries/Connect/Interfaces/Streams/ServerOnlyAsyncStreamInterface.swift +++ b/Libraries/Connect/Interfaces/Streams/ServerOnlyAsyncStreamInterface.swift @@ -19,10 +19,10 @@ import SwiftProtobuf @available(iOS 13, *) public protocol ServerOnlyAsyncStreamInterface { /// The input (request) message type. - associatedtype Input: SwiftProtobuf.Message + associatedtype Input: ProtobufMessage /// The output (response) message type. - associatedtype Output: SwiftProtobuf.Message + associatedtype Output: ProtobufMessage /// Send a request to the server over the stream. /// diff --git a/Libraries/Connect/Interfaces/Streams/ServerOnlyStreamInterface.swift b/Libraries/Connect/Interfaces/Streams/ServerOnlyStreamInterface.swift index ca367bcc..23c88d99 100644 --- a/Libraries/Connect/Interfaces/Streams/ServerOnlyStreamInterface.swift +++ b/Libraries/Connect/Interfaces/Streams/ServerOnlyStreamInterface.swift @@ -18,7 +18,7 @@ import SwiftProtobuf /// receiving an initial request) that can send request messages. public protocol ServerOnlyStreamInterface { /// The input (request) message type. - associatedtype Input: SwiftProtobuf.Message + associatedtype Input: ProtobufMessage /// Send a request to the server over the stream. /// diff --git a/Libraries/ConnectMocks/MockBidirectionalAsyncStream.swift b/Libraries/ConnectMocks/MockBidirectionalAsyncStream.swift index 1ba02e56..2d0170e1 100644 --- a/Libraries/ConnectMocks/MockBidirectionalAsyncStream.swift +++ b/Libraries/ConnectMocks/MockBidirectionalAsyncStream.swift @@ -26,8 +26,8 @@ import SwiftProtobuf /// subclassing and overriding `results()`. @available(iOS 13, *) open class MockBidirectionalAsyncStream< - Input: SwiftProtobuf.Message, - Output: SwiftProtobuf.Message + Input: ProtobufMessage, + Output: ProtobufMessage >: BidirectionalAsyncStreamInterface { private var cancellables = [AnyCancellable]() diff --git a/Libraries/ConnectMocks/MockBidirectionalStream.swift b/Libraries/ConnectMocks/MockBidirectionalStream.swift index f13d8299..66866233 100644 --- a/Libraries/ConnectMocks/MockBidirectionalStream.swift +++ b/Libraries/ConnectMocks/MockBidirectionalStream.swift @@ -25,8 +25,8 @@ import SwiftProtobuf /// To return data over the stream, outputs can be specified using `init(outputs: ...)`. @available(iOS 13.0, *) open class MockBidirectionalStream< - Input: SwiftProtobuf.Message, - Output: SwiftProtobuf.Message + Input: ProtobufMessage, + Output: ProtobufMessage >: BidirectionalStreamInterface { /// Closure that is called when `close()` is invoked. public var onClose: (() -> Void)? diff --git a/Libraries/ConnectMocks/MockClientOnlyAsyncStream.swift b/Libraries/ConnectMocks/MockClientOnlyAsyncStream.swift index c3a374d2..1c04a196 100644 --- a/Libraries/ConnectMocks/MockClientOnlyAsyncStream.swift +++ b/Libraries/ConnectMocks/MockClientOnlyAsyncStream.swift @@ -25,6 +25,6 @@ import SwiftProtobuf /// subclassing and overriding `results()`. @available(iOS 13, *) open class MockClientOnlyAsyncStream< - Input: SwiftProtobuf.Message, - Output: SwiftProtobuf.Message + Input: ProtobufMessage, + Output: ProtobufMessage >: MockBidirectionalAsyncStream, ClientOnlyAsyncStreamInterface {} diff --git a/Libraries/ConnectMocks/MockClientOnlyStream.swift b/Libraries/ConnectMocks/MockClientOnlyStream.swift index 48a9d447..63920e34 100644 --- a/Libraries/ConnectMocks/MockClientOnlyStream.swift +++ b/Libraries/ConnectMocks/MockClientOnlyStream.swift @@ -24,6 +24,6 @@ import SwiftProtobuf /// To return data over the stream, outputs can be specified using `init(outputs: ...)`. @available(iOS 13.0, *) open class MockClientOnlyStream< - Input: SwiftProtobuf.Message, - Output: SwiftProtobuf.Message + Input: ProtobufMessage, + Output: ProtobufMessage >: MockBidirectionalStream, ClientOnlyStreamInterface {} diff --git a/Libraries/ConnectMocks/MockServerOnlyAsyncStream.swift b/Libraries/ConnectMocks/MockServerOnlyAsyncStream.swift index e18065f0..4bc5695b 100644 --- a/Libraries/ConnectMocks/MockServerOnlyAsyncStream.swift +++ b/Libraries/ConnectMocks/MockServerOnlyAsyncStream.swift @@ -26,8 +26,8 @@ import SwiftProtobuf /// subclassing and overriding `results()`. @available(iOS 13, *) open class MockServerOnlyAsyncStream< - Input: SwiftProtobuf.Message, - Output: SwiftProtobuf.Message + Input: ProtobufMessage, + Output: ProtobufMessage >: ServerOnlyAsyncStreamInterface { private var cancellables = [AnyCancellable]() diff --git a/Libraries/ConnectMocks/MockServerOnlyStream.swift b/Libraries/ConnectMocks/MockServerOnlyStream.swift index 054490e4..9ace2b30 100644 --- a/Libraries/ConnectMocks/MockServerOnlyStream.swift +++ b/Libraries/ConnectMocks/MockServerOnlyStream.swift @@ -25,8 +25,8 @@ import SwiftProtobuf /// To return data over the stream, outputs can be specified using `init(outputs: ...)`. @available(iOS 13.0, *) open class MockServerOnlyStream< - Input: SwiftProtobuf.Message, - Output: SwiftProtobuf.Message + Input: ProtobufMessage, + Output: ProtobufMessage >: ServerOnlyStreamInterface { /// Closure that is called when `send()` is invoked. public var onSend: ((Input) -> Void)? diff --git a/Package.swift b/Package.swift index f373803e..7c03d068 100644 --- a/Package.swift +++ b/Package.swift @@ -75,7 +75,8 @@ let package = Package( "buf.work.yaml", "proto", "README.md", - ] + ], + swiftSettings: [.unsafeFlags(["-Xfrontend", "-strict-concurrency=complete"])] ), .testTarget( name: "ConnectLibraryTests", diff --git a/Tests/ConnectLibraryTests/ConnectTests/ConnectErrorTests.swift b/Tests/ConnectLibraryTests/ConnectTests/ConnectErrorTests.swift index 4744fb23..69c8d00b 100644 --- a/Tests/ConnectLibraryTests/ConnectTests/ConnectErrorTests.swift +++ b/Tests/ConnectLibraryTests/ConnectTests/ConnectErrorTests.swift @@ -83,7 +83,7 @@ final class ConnectErrorTests: XCTestCase { // MARK: - Private - private func errorData(expectedDetails: [SwiftProtobuf.Message]) throws -> Data { + private func errorData(expectedDetails: [ProtobufMessage]) throws -> Data { // Example error from https://connect.build/docs/protocol/#error-end-stream let dictionary: [String: Any] = [ "code": "unavailable", diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift index 9244c547..651d97cc 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift @@ -44,7 +44,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; /// }; struct Grpc_Testing_Empty { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -61,7 +61,7 @@ extension Grpc_Testing_Empty: @unchecked Sendable {} fileprivate let _protobuf_package = "grpc.testing" -extension Grpc_Testing_Empty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_Empty: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".Empty" static let _protobuf_nameMap = SwiftProtobuf._NameMap() diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift index 2e6e0fb4..106f9f41 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift @@ -137,7 +137,7 @@ extension Grpc_Testing_GrpclbRouteType: CaseIterable { /// https://github.com/grpc/grpc/issues/6980 has been fixed. /// import "google/protobuf/wrappers.proto"; struct Grpc_Testing_BoolValue { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -151,7 +151,7 @@ struct Grpc_Testing_BoolValue { /// A block of data, to simply increase gRPC message size. struct Grpc_Testing_Payload { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -169,7 +169,7 @@ struct Grpc_Testing_Payload { /// A protobuf representation for grpc status. This is used by test /// clients to specify a status that the server should attempt to return. struct Grpc_Testing_EchoStatus { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -184,7 +184,7 @@ struct Grpc_Testing_EchoStatus { /// Unary request. struct Grpc_Testing_SimpleRequest { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -262,7 +262,7 @@ struct Grpc_Testing_SimpleRequest { /// Unary response, as configured by the request. struct Grpc_Testing_SimpleResponse { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -302,7 +302,7 @@ struct Grpc_Testing_SimpleResponse { /// Client-streaming request. struct Grpc_Testing_StreamingInputCallRequest { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -339,7 +339,7 @@ struct Grpc_Testing_StreamingInputCallRequest { /// Client-streaming response. struct Grpc_Testing_StreamingInputCallResponse { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -353,7 +353,7 @@ struct Grpc_Testing_StreamingInputCallResponse { /// Configuration for a particular response. struct Grpc_Testing_ResponseParameters { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -386,7 +386,7 @@ struct Grpc_Testing_ResponseParameters { /// Server-streaming request. struct Grpc_Testing_StreamingOutputCallRequest { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -429,7 +429,7 @@ struct Grpc_Testing_StreamingOutputCallRequest { /// Server-streaming response, as configured by the request and parameters. struct Grpc_Testing_StreamingOutputCallResponse { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -453,7 +453,7 @@ struct Grpc_Testing_StreamingOutputCallResponse { /// For reconnect interop test only. /// Client tells server what reconnection parameters it used. struct Grpc_Testing_ReconnectParams { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -468,7 +468,7 @@ struct Grpc_Testing_ReconnectParams { /// Server tells client whether its reconnects are following the spec and the /// reconnect backoffs it saw. struct Grpc_Testing_ReconnectInfo { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -482,7 +482,7 @@ struct Grpc_Testing_ReconnectInfo { } struct Grpc_Testing_LoadBalancerStatsRequest { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -498,7 +498,7 @@ struct Grpc_Testing_LoadBalancerStatsRequest { } struct Grpc_Testing_LoadBalancerStatsResponse { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -513,7 +513,7 @@ struct Grpc_Testing_LoadBalancerStatsResponse { var unknownFields = SwiftProtobuf.UnknownStorage() struct RpcsByPeer { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -530,7 +530,7 @@ struct Grpc_Testing_LoadBalancerStatsResponse { /// Request for retrieving a test client's accumulated stats. struct Grpc_Testing_LoadBalancerAccumulatedStatsRequest { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -541,7 +541,7 @@ struct Grpc_Testing_LoadBalancerAccumulatedStatsRequest { /// Accumulated stats for RPCs sent by a test client. struct Grpc_Testing_LoadBalancerAccumulatedStatsResponse { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -564,7 +564,7 @@ struct Grpc_Testing_LoadBalancerAccumulatedStatsResponse { var unknownFields = SwiftProtobuf.UnknownStorage() struct MethodStats { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -585,7 +585,7 @@ struct Grpc_Testing_LoadBalancerAccumulatedStatsResponse { /// Configurations for a test client. struct Grpc_Testing_ClientConfigureRequest { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -632,7 +632,7 @@ struct Grpc_Testing_ClientConfigureRequest { /// Metadata to be attached for the given type of RPCs. struct Metadata { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -664,7 +664,7 @@ extension Grpc_Testing_ClientConfigureRequest.RpcType: CaseIterable { /// Response for updating a test client's configuration. struct Grpc_Testing_ClientConfigureResponse { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -674,7 +674,7 @@ struct Grpc_Testing_ClientConfigureResponse { } struct Grpc_Testing_ErrorDetail { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -688,7 +688,7 @@ struct Grpc_Testing_ErrorDetail { } struct Grpc_Testing_ErrorStatus { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -750,7 +750,7 @@ extension Grpc_Testing_GrpclbRouteType: SwiftProtobuf._ProtoNameProviding { ] } -extension Grpc_Testing_BoolValue: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_BoolValue: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".BoolValue" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "value"), @@ -782,7 +782,7 @@ extension Grpc_Testing_BoolValue: SwiftProtobuf.Message, SwiftProtobuf._MessageI } } -extension Grpc_Testing_Payload: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_Payload: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".Payload" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "type"), @@ -820,7 +820,7 @@ extension Grpc_Testing_Payload: SwiftProtobuf.Message, SwiftProtobuf._MessageImp } } -extension Grpc_Testing_EchoStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_EchoStatus: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".EchoStatus" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "code"), @@ -858,7 +858,7 @@ extension Grpc_Testing_EchoStatus: SwiftProtobuf.Message, SwiftProtobuf._Message } } -extension Grpc_Testing_SimpleRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_SimpleRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".SimpleRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "response_type"), @@ -948,7 +948,7 @@ extension Grpc_Testing_SimpleRequest: SwiftProtobuf.Message, SwiftProtobuf._Mess } } -extension Grpc_Testing_SimpleResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_SimpleResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".SimpleResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "payload"), @@ -1014,7 +1014,7 @@ extension Grpc_Testing_SimpleResponse: SwiftProtobuf.Message, SwiftProtobuf._Mes } } -extension Grpc_Testing_StreamingInputCallRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingInputCallRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingInputCallRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "payload"), @@ -1056,7 +1056,7 @@ extension Grpc_Testing_StreamingInputCallRequest: SwiftProtobuf.Message, SwiftPr } } -extension Grpc_Testing_StreamingInputCallResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingInputCallResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingInputCallResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "aggregated_payload_size"), @@ -1088,7 +1088,7 @@ extension Grpc_Testing_StreamingInputCallResponse: SwiftProtobuf.Message, SwiftP } } -extension Grpc_Testing_ResponseParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ResponseParameters: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ResponseParameters" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "size"), @@ -1136,7 +1136,7 @@ extension Grpc_Testing_ResponseParameters: SwiftProtobuf.Message, SwiftProtobuf. } } -extension Grpc_Testing_StreamingOutputCallRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingOutputCallRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingOutputCallRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "response_type"), @@ -1190,7 +1190,7 @@ extension Grpc_Testing_StreamingOutputCallRequest: SwiftProtobuf.Message, SwiftP } } -extension Grpc_Testing_StreamingOutputCallResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingOutputCallResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingOutputCallResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "payload"), @@ -1226,7 +1226,7 @@ extension Grpc_Testing_StreamingOutputCallResponse: SwiftProtobuf.Message, Swift } } -extension Grpc_Testing_ReconnectParams: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ReconnectParams: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ReconnectParams" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "max_reconnect_backoff_ms"), @@ -1258,7 +1258,7 @@ extension Grpc_Testing_ReconnectParams: SwiftProtobuf.Message, SwiftProtobuf._Me } } -extension Grpc_Testing_ReconnectInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ReconnectInfo: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ReconnectInfo" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "passed"), @@ -1296,7 +1296,7 @@ extension Grpc_Testing_ReconnectInfo: SwiftProtobuf.Message, SwiftProtobuf._Mess } } -extension Grpc_Testing_LoadBalancerStatsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerStatsRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerStatsRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "num_rpcs"), @@ -1334,7 +1334,7 @@ extension Grpc_Testing_LoadBalancerStatsRequest: SwiftProtobuf.Message, SwiftPro } } -extension Grpc_Testing_LoadBalancerStatsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerStatsResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerStatsResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "rpcs_by_peer"), @@ -1378,7 +1378,7 @@ extension Grpc_Testing_LoadBalancerStatsResponse: SwiftProtobuf.Message, SwiftPr } } -extension Grpc_Testing_LoadBalancerStatsResponse.RpcsByPeer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerStatsResponse.RpcsByPeer: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Grpc_Testing_LoadBalancerStatsResponse.protoMessageName + ".RpcsByPeer" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "rpcs_by_peer"), @@ -1410,7 +1410,7 @@ extension Grpc_Testing_LoadBalancerStatsResponse.RpcsByPeer: SwiftProtobuf.Messa } } -extension Grpc_Testing_LoadBalancerAccumulatedStatsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerAccumulatedStatsRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerAccumulatedStatsRequest" static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -1429,7 +1429,7 @@ extension Grpc_Testing_LoadBalancerAccumulatedStatsRequest: SwiftProtobuf.Messag } } -extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerAccumulatedStatsResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "num_rpcs_started_by_method"), @@ -1479,7 +1479,7 @@ extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse: SwiftProtobuf.Messa } } -extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse.MethodStats: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse.MethodStats: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Grpc_Testing_LoadBalancerAccumulatedStatsResponse.protoMessageName + ".MethodStats" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "rpcs_started"), @@ -1517,7 +1517,7 @@ extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse.MethodStats: SwiftPr } } -extension Grpc_Testing_ClientConfigureRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ClientConfigureRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ClientConfigureRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "types"), @@ -1568,7 +1568,7 @@ extension Grpc_Testing_ClientConfigureRequest.RpcType: SwiftProtobuf._ProtoNameP ] } -extension Grpc_Testing_ClientConfigureRequest.Metadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ClientConfigureRequest.Metadata: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Grpc_Testing_ClientConfigureRequest.protoMessageName + ".Metadata" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "type"), @@ -1612,7 +1612,7 @@ extension Grpc_Testing_ClientConfigureRequest.Metadata: SwiftProtobuf.Message, S } } -extension Grpc_Testing_ClientConfigureResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ClientConfigureResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ClientConfigureResponse" static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -1631,7 +1631,7 @@ extension Grpc_Testing_ClientConfigureResponse: SwiftProtobuf.Message, SwiftProt } } -extension Grpc_Testing_ErrorDetail: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ErrorDetail: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ErrorDetail" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "reason"), @@ -1669,7 +1669,7 @@ extension Grpc_Testing_ErrorDetail: SwiftProtobuf.Message, SwiftProtobuf._Messag } } -extension Grpc_Testing_ErrorStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ErrorStatus: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ErrorStatus" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "code"), diff --git a/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift b/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift index 2619cd94..c26bf743 100644 --- a/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift +++ b/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift @@ -80,7 +80,7 @@ extension Server_V1_Protocol: CaseIterable { /// ServerMetadata is the metadata returned from the server started by the server binary. struct Server_V1_ServerMetadata { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -94,7 +94,7 @@ struct Server_V1_ServerMetadata { } struct Server_V1_ProtocolSupport { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -110,7 +110,7 @@ struct Server_V1_ProtocolSupport { } struct Server_V1_HTTPVersion { - // SwiftProtobuf.Message conformance is added in an extension below. See the + // ProtobufMessage conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -142,7 +142,7 @@ extension Server_V1_Protocol: SwiftProtobuf._ProtoNameProviding { ] } -extension Server_V1_ServerMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Server_V1_ServerMetadata: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ServerMetadata" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "host"), @@ -180,7 +180,7 @@ extension Server_V1_ServerMetadata: SwiftProtobuf.Message, SwiftProtobuf._Messag } } -extension Server_V1_ProtocolSupport: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Server_V1_ProtocolSupport: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ProtocolSupport" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "protocol"), @@ -224,7 +224,7 @@ extension Server_V1_ProtocolSupport: SwiftProtobuf.Message, SwiftProtobuf._Messa } } -extension Server_V1_HTTPVersion: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Server_V1_HTTPVersion: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".HTTPVersion" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "major"), From 4037cdd76a087f0cc1655f9472507b7871a6ea0a Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 22 Aug 2023 15:57:18 -0700 Subject: [PATCH 03/18] no warnings --- .../Implementation/ProtocolClient.swift | 18 +++++++++--------- .../Implementation/URLSessionHTTPClient.swift | 6 +++--- .../Interfaces/HTTPClientInterface.swift | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Libraries/Connect/Implementation/ProtocolClient.swift b/Libraries/Connect/Implementation/ProtocolClient.swift index 7e06551d..2f04fb69 100644 --- a/Libraries/Connect/Implementation/ProtocolClient.swift +++ b/Libraries/Connect/Implementation/ProtocolClient.swift @@ -17,7 +17,7 @@ import os.log import SwiftProtobuf /// Concrete implementation of the `ProtocolClientInterface`. -public final class ProtocolClient { +public final class ProtocolClient: Sendable { private let config: ProtocolClientConfig private let httpClient: HTTPClientInterface @@ -191,7 +191,7 @@ extension ProtocolClient: ProtocolClientInterface { ) -> any BidirectionalAsyncStreamInterface { let bidirectionalAsync = BidirectionalAsyncStream(codec: self.config.codec) let callbacks = self.createRequestCallbacks( - path: path, headers: headers, onResult: bidirectionalAsync.receive + path: path, headers: headers, onResult: { bidirectionalAsync.receive($0) } ) return bidirectionalAsync.configureForSending(with: callbacks) } @@ -205,7 +205,7 @@ extension ProtocolClient: ProtocolClientInterface { ) -> any ClientOnlyAsyncStreamInterface { let bidirectionalAsync = BidirectionalAsyncStream(codec: self.config.codec) let callbacks = self.createRequestCallbacks( - path: path, headers: headers, onResult: bidirectionalAsync.receive + path: path, headers: headers, onResult: { bidirectionalAsync.receive($0) } ) return bidirectionalAsync.configureForSending(with: callbacks) } @@ -219,7 +219,7 @@ extension ProtocolClient: ProtocolClientInterface { ) -> any ServerOnlyAsyncStreamInterface { let bidirectionalAsync = BidirectionalAsyncStream(codec: self.config.codec) let callbacks = self.createRequestCallbacks( - path: path, headers: headers, onResult: bidirectionalAsync.receive + path: path, headers: headers, onResult: { bidirectionalAsync.receive($0) } ) return ServerOnlyAsyncStream( bidirectionalStream: bidirectionalAsync.configureForSending(with: callbacks) @@ -231,7 +231,7 @@ extension ProtocolClient: ProtocolClientInterface { private func createRequestCallbacks( path: String, headers: Headers, - onResult: @escaping (StreamResult) -> Void + onResult: @escaping @Sendable (StreamResult) -> Void ) -> RequestCallbacks { let codec = self.config.codec let chain = self.config.createInterceptorChain().streamFunction() @@ -244,12 +244,12 @@ extension ProtocolClient: ProtocolClientInterface { trailers: nil )) - var hasCompleted = false - let interceptAndHandleResult: (StreamResult) -> Void = { streamResult in + let hasCompleted = Locked(false) + let interceptAndHandleResult: @Sendable (StreamResult) -> Void = { streamResult in do { let interceptedResult = chain.streamResultFunction(streamResult) if case .complete = interceptedResult { - hasCompleted = true + hasCompleted.value = true } onResult(try interceptedResult.toTypedResult(using: codec)) } catch let error { @@ -287,7 +287,7 @@ extension ProtocolClient: ProtocolClientInterface { } }, receiveClose: { code, trailers, error in - if !hasCompleted { + if !hasCompleted.value { interceptAndHandleResult(.complete( code: code, error: error, diff --git a/Libraries/Connect/Implementation/URLSessionHTTPClient.swift b/Libraries/Connect/Implementation/URLSessionHTTPClient.swift index aad9aec3..6c86bb82 100644 --- a/Libraries/Connect/Implementation/URLSessionHTTPClient.swift +++ b/Libraries/Connect/Implementation/URLSessionHTTPClient.swift @@ -17,11 +17,11 @@ import Foundation import os.log /// Concrete implementation of `HTTPClientInterface` backed by `URLSession`. -open class URLSessionHTTPClient: NSObject, HTTPClientInterface { +open class URLSessionHTTPClient: NSObject, HTTPClientInterface, @unchecked Sendable { /// Lock used for safely accessing stream storage. private let lock = Lock() /// Closures stored for notifying when metrics are available. - private var metricsClosures = [Int: (HTTPMetrics) -> Void]() + private var metricsClosures = [Int: @Sendable (HTTPMetrics) -> Void]() /// Force unwrapped to allow using `self` as the delegate. private var session: URLSession! /// List of active streams. @@ -114,7 +114,7 @@ open class URLSessionHTTPClient: NSObject, HTTPClientInterface { urlSessionStream.close() } }, - sendClose: urlSessionStream.close + sendClose: { urlSessionStream.close() } ) } } diff --git a/Libraries/Connect/Interfaces/HTTPClientInterface.swift b/Libraries/Connect/Interfaces/HTTPClientInterface.swift index fec28cda..a846bb80 100644 --- a/Libraries/Connect/Interfaces/HTTPClientInterface.swift +++ b/Libraries/Connect/Interfaces/HTTPClientInterface.swift @@ -13,7 +13,7 @@ // limitations under the License. /// Interface for a client that performs underlying HTTP requests and streams with primitive types. -public protocol HTTPClientInterface { +public protocol HTTPClientInterface: Sendable { /// Perform a unary HTTP request. /// /// - parameter request: The outbound request headers and data. From 172c6bf61cacb1686d50627264facf14b7b787c9 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 22 Aug 2023 15:59:40 -0700 Subject: [PATCH 04/18] fixup --- .../Generated/grpc/status/v1/status.pb.swift | 4 +- Package.swift | 3 +- .../Generated/grpc/testing/empty.pb.swift | 4 +- .../Generated/grpc/testing/messages.pb.swift | 92 +++++++++---------- .../Generated/server/v1/server.pb.swift | 12 +-- 5 files changed, 57 insertions(+), 58 deletions(-) diff --git a/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift b/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift index ae0915e8..f037f755 100644 --- a/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift +++ b/Libraries/Connect/Implementation/Generated/grpc/status/v1/status.pb.swift @@ -39,7 +39,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This struct must remain binary-compatible with /// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto. struct Grpc_Status_V1_Status { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -64,7 +64,7 @@ extension Grpc_Status_V1_Status: @unchecked Sendable {} fileprivate let _protobuf_package = "grpc.status.v1" -extension Grpc_Status_V1_Status: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Status_V1_Status: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".Status" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "code"), diff --git a/Package.swift b/Package.swift index 7c03d068..f373803e 100644 --- a/Package.swift +++ b/Package.swift @@ -75,8 +75,7 @@ let package = Package( "buf.work.yaml", "proto", "README.md", - ], - swiftSettings: [.unsafeFlags(["-Xfrontend", "-strict-concurrency=complete"])] + ] ), .testTarget( name: "ConnectLibraryTests", diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift index 651d97cc..9244c547 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/empty.pb.swift @@ -44,7 +44,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; /// }; struct Grpc_Testing_Empty { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -61,7 +61,7 @@ extension Grpc_Testing_Empty: @unchecked Sendable {} fileprivate let _protobuf_package = "grpc.testing" -extension Grpc_Testing_Empty: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_Empty: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".Empty" static let _protobuf_nameMap = SwiftProtobuf._NameMap() diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift index 106f9f41..2e6e0fb4 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/messages.pb.swift @@ -137,7 +137,7 @@ extension Grpc_Testing_GrpclbRouteType: CaseIterable { /// https://github.com/grpc/grpc/issues/6980 has been fixed. /// import "google/protobuf/wrappers.proto"; struct Grpc_Testing_BoolValue { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -151,7 +151,7 @@ struct Grpc_Testing_BoolValue { /// A block of data, to simply increase gRPC message size. struct Grpc_Testing_Payload { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -169,7 +169,7 @@ struct Grpc_Testing_Payload { /// A protobuf representation for grpc status. This is used by test /// clients to specify a status that the server should attempt to return. struct Grpc_Testing_EchoStatus { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -184,7 +184,7 @@ struct Grpc_Testing_EchoStatus { /// Unary request. struct Grpc_Testing_SimpleRequest { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -262,7 +262,7 @@ struct Grpc_Testing_SimpleRequest { /// Unary response, as configured by the request. struct Grpc_Testing_SimpleResponse { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -302,7 +302,7 @@ struct Grpc_Testing_SimpleResponse { /// Client-streaming request. struct Grpc_Testing_StreamingInputCallRequest { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -339,7 +339,7 @@ struct Grpc_Testing_StreamingInputCallRequest { /// Client-streaming response. struct Grpc_Testing_StreamingInputCallResponse { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -353,7 +353,7 @@ struct Grpc_Testing_StreamingInputCallResponse { /// Configuration for a particular response. struct Grpc_Testing_ResponseParameters { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -386,7 +386,7 @@ struct Grpc_Testing_ResponseParameters { /// Server-streaming request. struct Grpc_Testing_StreamingOutputCallRequest { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -429,7 +429,7 @@ struct Grpc_Testing_StreamingOutputCallRequest { /// Server-streaming response, as configured by the request and parameters. struct Grpc_Testing_StreamingOutputCallResponse { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -453,7 +453,7 @@ struct Grpc_Testing_StreamingOutputCallResponse { /// For reconnect interop test only. /// Client tells server what reconnection parameters it used. struct Grpc_Testing_ReconnectParams { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -468,7 +468,7 @@ struct Grpc_Testing_ReconnectParams { /// Server tells client whether its reconnects are following the spec and the /// reconnect backoffs it saw. struct Grpc_Testing_ReconnectInfo { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -482,7 +482,7 @@ struct Grpc_Testing_ReconnectInfo { } struct Grpc_Testing_LoadBalancerStatsRequest { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -498,7 +498,7 @@ struct Grpc_Testing_LoadBalancerStatsRequest { } struct Grpc_Testing_LoadBalancerStatsResponse { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -513,7 +513,7 @@ struct Grpc_Testing_LoadBalancerStatsResponse { var unknownFields = SwiftProtobuf.UnknownStorage() struct RpcsByPeer { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -530,7 +530,7 @@ struct Grpc_Testing_LoadBalancerStatsResponse { /// Request for retrieving a test client's accumulated stats. struct Grpc_Testing_LoadBalancerAccumulatedStatsRequest { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -541,7 +541,7 @@ struct Grpc_Testing_LoadBalancerAccumulatedStatsRequest { /// Accumulated stats for RPCs sent by a test client. struct Grpc_Testing_LoadBalancerAccumulatedStatsResponse { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -564,7 +564,7 @@ struct Grpc_Testing_LoadBalancerAccumulatedStatsResponse { var unknownFields = SwiftProtobuf.UnknownStorage() struct MethodStats { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -585,7 +585,7 @@ struct Grpc_Testing_LoadBalancerAccumulatedStatsResponse { /// Configurations for a test client. struct Grpc_Testing_ClientConfigureRequest { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -632,7 +632,7 @@ struct Grpc_Testing_ClientConfigureRequest { /// Metadata to be attached for the given type of RPCs. struct Metadata { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -664,7 +664,7 @@ extension Grpc_Testing_ClientConfigureRequest.RpcType: CaseIterable { /// Response for updating a test client's configuration. struct Grpc_Testing_ClientConfigureResponse { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -674,7 +674,7 @@ struct Grpc_Testing_ClientConfigureResponse { } struct Grpc_Testing_ErrorDetail { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -688,7 +688,7 @@ struct Grpc_Testing_ErrorDetail { } struct Grpc_Testing_ErrorStatus { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -750,7 +750,7 @@ extension Grpc_Testing_GrpclbRouteType: SwiftProtobuf._ProtoNameProviding { ] } -extension Grpc_Testing_BoolValue: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_BoolValue: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".BoolValue" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "value"), @@ -782,7 +782,7 @@ extension Grpc_Testing_BoolValue: ProtobufMessage, SwiftProtobuf._MessageImpleme } } -extension Grpc_Testing_Payload: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_Payload: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".Payload" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "type"), @@ -820,7 +820,7 @@ extension Grpc_Testing_Payload: ProtobufMessage, SwiftProtobuf._MessageImplement } } -extension Grpc_Testing_EchoStatus: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_EchoStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".EchoStatus" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "code"), @@ -858,7 +858,7 @@ extension Grpc_Testing_EchoStatus: ProtobufMessage, SwiftProtobuf._MessageImplem } } -extension Grpc_Testing_SimpleRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_SimpleRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".SimpleRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "response_type"), @@ -948,7 +948,7 @@ extension Grpc_Testing_SimpleRequest: ProtobufMessage, SwiftProtobuf._MessageImp } } -extension Grpc_Testing_SimpleResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_SimpleResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".SimpleResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "payload"), @@ -1014,7 +1014,7 @@ extension Grpc_Testing_SimpleResponse: ProtobufMessage, SwiftProtobuf._MessageIm } } -extension Grpc_Testing_StreamingInputCallRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingInputCallRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingInputCallRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "payload"), @@ -1056,7 +1056,7 @@ extension Grpc_Testing_StreamingInputCallRequest: ProtobufMessage, SwiftProtobuf } } -extension Grpc_Testing_StreamingInputCallResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingInputCallResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingInputCallResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "aggregated_payload_size"), @@ -1088,7 +1088,7 @@ extension Grpc_Testing_StreamingInputCallResponse: ProtobufMessage, SwiftProtobu } } -extension Grpc_Testing_ResponseParameters: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ResponseParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ResponseParameters" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "size"), @@ -1136,7 +1136,7 @@ extension Grpc_Testing_ResponseParameters: ProtobufMessage, SwiftProtobuf._Messa } } -extension Grpc_Testing_StreamingOutputCallRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingOutputCallRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingOutputCallRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "response_type"), @@ -1190,7 +1190,7 @@ extension Grpc_Testing_StreamingOutputCallRequest: ProtobufMessage, SwiftProtobu } } -extension Grpc_Testing_StreamingOutputCallResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_StreamingOutputCallResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".StreamingOutputCallResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "payload"), @@ -1226,7 +1226,7 @@ extension Grpc_Testing_StreamingOutputCallResponse: ProtobufMessage, SwiftProtob } } -extension Grpc_Testing_ReconnectParams: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ReconnectParams: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ReconnectParams" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "max_reconnect_backoff_ms"), @@ -1258,7 +1258,7 @@ extension Grpc_Testing_ReconnectParams: ProtobufMessage, SwiftProtobuf._MessageI } } -extension Grpc_Testing_ReconnectInfo: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ReconnectInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ReconnectInfo" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "passed"), @@ -1296,7 +1296,7 @@ extension Grpc_Testing_ReconnectInfo: ProtobufMessage, SwiftProtobuf._MessageImp } } -extension Grpc_Testing_LoadBalancerStatsRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerStatsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerStatsRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "num_rpcs"), @@ -1334,7 +1334,7 @@ extension Grpc_Testing_LoadBalancerStatsRequest: ProtobufMessage, SwiftProtobuf. } } -extension Grpc_Testing_LoadBalancerStatsResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerStatsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerStatsResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "rpcs_by_peer"), @@ -1378,7 +1378,7 @@ extension Grpc_Testing_LoadBalancerStatsResponse: ProtobufMessage, SwiftProtobuf } } -extension Grpc_Testing_LoadBalancerStatsResponse.RpcsByPeer: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerStatsResponse.RpcsByPeer: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Grpc_Testing_LoadBalancerStatsResponse.protoMessageName + ".RpcsByPeer" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "rpcs_by_peer"), @@ -1410,7 +1410,7 @@ extension Grpc_Testing_LoadBalancerStatsResponse.RpcsByPeer: ProtobufMessage, Sw } } -extension Grpc_Testing_LoadBalancerAccumulatedStatsRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerAccumulatedStatsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerAccumulatedStatsRequest" static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -1429,7 +1429,7 @@ extension Grpc_Testing_LoadBalancerAccumulatedStatsRequest: ProtobufMessage, Swi } } -extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".LoadBalancerAccumulatedStatsResponse" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "num_rpcs_started_by_method"), @@ -1479,7 +1479,7 @@ extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse: ProtobufMessage, Sw } } -extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse.MethodStats: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse.MethodStats: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Grpc_Testing_LoadBalancerAccumulatedStatsResponse.protoMessageName + ".MethodStats" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "rpcs_started"), @@ -1517,7 +1517,7 @@ extension Grpc_Testing_LoadBalancerAccumulatedStatsResponse.MethodStats: Protobu } } -extension Grpc_Testing_ClientConfigureRequest: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ClientConfigureRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ClientConfigureRequest" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "types"), @@ -1568,7 +1568,7 @@ extension Grpc_Testing_ClientConfigureRequest.RpcType: SwiftProtobuf._ProtoNameP ] } -extension Grpc_Testing_ClientConfigureRequest.Metadata: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ClientConfigureRequest.Metadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = Grpc_Testing_ClientConfigureRequest.protoMessageName + ".Metadata" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "type"), @@ -1612,7 +1612,7 @@ extension Grpc_Testing_ClientConfigureRequest.Metadata: ProtobufMessage, SwiftPr } } -extension Grpc_Testing_ClientConfigureResponse: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ClientConfigureResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ClientConfigureResponse" static let _protobuf_nameMap = SwiftProtobuf._NameMap() @@ -1631,7 +1631,7 @@ extension Grpc_Testing_ClientConfigureResponse: ProtobufMessage, SwiftProtobuf._ } } -extension Grpc_Testing_ErrorDetail: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ErrorDetail: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ErrorDetail" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "reason"), @@ -1669,7 +1669,7 @@ extension Grpc_Testing_ErrorDetail: ProtobufMessage, SwiftProtobuf._MessageImple } } -extension Grpc_Testing_ErrorStatus: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Grpc_Testing_ErrorStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ErrorStatus" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "code"), diff --git a/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift b/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift index c26bf743..2619cd94 100644 --- a/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift +++ b/Tests/ConnectLibraryTests/Generated/server/v1/server.pb.swift @@ -80,7 +80,7 @@ extension Server_V1_Protocol: CaseIterable { /// ServerMetadata is the metadata returned from the server started by the server binary. struct Server_V1_ServerMetadata { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -94,7 +94,7 @@ struct Server_V1_ServerMetadata { } struct Server_V1_ProtocolSupport { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -110,7 +110,7 @@ struct Server_V1_ProtocolSupport { } struct Server_V1_HTTPVersion { - // ProtobufMessage conformance is added in an extension below. See the + // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -142,7 +142,7 @@ extension Server_V1_Protocol: SwiftProtobuf._ProtoNameProviding { ] } -extension Server_V1_ServerMetadata: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Server_V1_ServerMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ServerMetadata" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "host"), @@ -180,7 +180,7 @@ extension Server_V1_ServerMetadata: ProtobufMessage, SwiftProtobuf._MessageImple } } -extension Server_V1_ProtocolSupport: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Server_V1_ProtocolSupport: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ProtocolSupport" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "protocol"), @@ -224,7 +224,7 @@ extension Server_V1_ProtocolSupport: ProtobufMessage, SwiftProtobuf._MessageImpl } } -extension Server_V1_HTTPVersion: ProtobufMessage, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { +extension Server_V1_HTTPVersion: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".HTTPVersion" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "major"), From e86a3c9b34665eaaa6c9702169b65a66ae838b84 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 22 Aug 2023 16:19:19 -0700 Subject: [PATCH 05/18] fixes + NIO --- Libraries/Connect/Implementation/Lock.swift | 5 +++++ Libraries/Connect/Implementation/Locked.swift | 14 ++++++++++---- .../Implementation/ProtocolClientConfig.swift | 4 ++-- .../{File.swift => ProtobufMessage.swift} | 2 +- .../Internal/ConnectStreamChannelHandler.swift | 4 ++-- .../Internal/ConnectUnaryChannelHandler.swift | 4 ++-- .../ConnectNIO/Internal/GRPCInterceptor.swift | 6 +++--- Libraries/ConnectNIO/Public/NIOHTTPClient.swift | 8 ++++---- .../Public/NetworkProtocol+Extensions.swift | 2 +- 9 files changed, 30 insertions(+), 19 deletions(-) rename Libraries/Connect/Interfaces/{File.swift => ProtobufMessage.swift} (90%) diff --git a/Libraries/Connect/Implementation/Lock.swift b/Libraries/Connect/Implementation/Lock.swift index dc9343c8..9e560ba1 100644 --- a/Libraries/Connect/Implementation/Lock.swift +++ b/Libraries/Connect/Implementation/Lock.swift @@ -24,6 +24,11 @@ final class Lock: Sendable { self.underlyingLock.initialize(to: os_unfair_lock()) } + /// Perform an action within the context of the lock. + /// + /// - parameter action: Closure to be executed in the context of the lock. + /// + /// - returns: The result of the closure. func perform(action: @escaping () -> T) -> T { os_unfair_lock_lock(self.underlyingLock) defer { os_unfair_lock_unlock(self.underlyingLock) } diff --git a/Libraries/Connect/Implementation/Locked.swift b/Libraries/Connect/Implementation/Locked.swift index 8f80f523..88939210 100644 --- a/Libraries/Connect/Implementation/Locked.swift +++ b/Libraries/Connect/Implementation/Locked.swift @@ -14,22 +14,28 @@ import Foundation -final class Locked: @unchecked Sendable { +/// Class containing an internal lock which can be used to ensure thread-safe access to an +/// underlying value. Conforms to `Sendable`, making it accessible from `@Sendable` closures. +public final class Locked: @unchecked Sendable { private let lock = Lock() private var _value: T - var value: T { + /// Thread-safe access to the underlying value. + public var value: T { get { self.lock.perform { self._value } } set { self.lock.perform { self._value = newValue } } } - func perform(action: @escaping (inout T) -> Void) { + /// Perform an action with the underlying value, potentially updating that value. + /// + /// - parameter action: Closure to perform with the underlying value. + public func perform(action: @escaping (inout T) -> Void) { self.lock.perform { action(&self._value) } } - init(_ value: T) { + public init(_ value: T) { self._value = value } } diff --git a/Libraries/Connect/Implementation/ProtocolClientConfig.swift b/Libraries/Connect/Implementation/ProtocolClientConfig.swift index 0b0e5849..2dac24d6 100644 --- a/Libraries/Connect/Implementation/ProtocolClientConfig.swift +++ b/Libraries/Connect/Implementation/ProtocolClientConfig.swift @@ -63,9 +63,9 @@ public struct ProtocolClientConfig: Sendable { switch networkProtocol { case .connect: - self.interceptors = interceptors + [{ ConnectInterceptor.init(config: $0) }] + self.interceptors = interceptors + [{ ConnectInterceptor(config: $0) }] case .grpcWeb: - self.interceptors = interceptors + [{ GRPCWebInterceptor.init(config: $0) }] + self.interceptors = interceptors + [{ GRPCWebInterceptor(config: $0) }] case .custom(_, let protocolInterceptor): self.interceptors = interceptors + [protocolInterceptor] } diff --git a/Libraries/Connect/Interfaces/File.swift b/Libraries/Connect/Interfaces/ProtobufMessage.swift similarity index 90% rename from Libraries/Connect/Interfaces/File.swift rename to Libraries/Connect/Interfaces/ProtobufMessage.swift index 243e59ec..662db0d9 100644 --- a/Libraries/Connect/Interfaces/File.swift +++ b/Libraries/Connect/Interfaces/ProtobufMessage.swift @@ -14,4 +14,4 @@ import SwiftProtobuf -public protocol ProtobufMessage: SwiftProtobuf.Message, Sendable {} +public typealias ProtobufMessage = SwiftProtobuf.Message & Sendable diff --git a/Libraries/ConnectNIO/Internal/ConnectStreamChannelHandler.swift b/Libraries/ConnectNIO/Internal/ConnectStreamChannelHandler.swift index a072175f..7115fc63 100644 --- a/Libraries/ConnectNIO/Internal/ConnectStreamChannelHandler.swift +++ b/Libraries/ConnectNIO/Internal/ConnectStreamChannelHandler.swift @@ -19,7 +19,7 @@ import NIOFoundationCompat import NIOHTTP1 /// NIO-based channel handler for streams made through the Connect library. -final class ConnectStreamChannelHandler: NIOCore.ChannelInboundHandler { +final class ConnectStreamChannelHandler: NIOCore.ChannelInboundHandler, @unchecked Sendable { private let eventLoop: NIOCore.EventLoop private let request: Connect.HTTPRequest private let responseCallbacks: Connect.ResponseCallbacks @@ -94,7 +94,7 @@ final class ConnectStreamChannelHandler: NIOCore.ChannelInboundHandler { .cascade(to: nil) } - private func runOnEventLoop(action: @escaping () -> Void) { + private func runOnEventLoop(action: @escaping @Sendable () -> Void) { if self.eventLoop.inEventLoop { action() } else { diff --git a/Libraries/ConnectNIO/Internal/ConnectUnaryChannelHandler.swift b/Libraries/ConnectNIO/Internal/ConnectUnaryChannelHandler.swift index 6bd9854c..104c13d6 100644 --- a/Libraries/ConnectNIO/Internal/ConnectUnaryChannelHandler.swift +++ b/Libraries/ConnectNIO/Internal/ConnectUnaryChannelHandler.swift @@ -19,7 +19,7 @@ import NIOFoundationCompat import NIOHTTP1 /// NIO-based channel handler for unary requests made through the Connect library. -final class ConnectUnaryChannelHandler: NIOCore.ChannelInboundHandler { +final class ConnectUnaryChannelHandler: NIOCore.ChannelInboundHandler, @unchecked Sendable { private let eventLoop: NIOCore.EventLoop private let request: Connect.HTTPRequest private let onMetrics: (Connect.HTTPMetrics) -> Void @@ -63,7 +63,7 @@ final class ConnectUnaryChannelHandler: NIOCore.ChannelInboundHandler { } } - private func runOnEventLoop(action: @escaping () -> Void) { + private func runOnEventLoop(action: @escaping @Sendable () -> Void) { if self.eventLoop.inEventLoop { action() } else { diff --git a/Libraries/ConnectNIO/Internal/GRPCInterceptor.swift b/Libraries/ConnectNIO/Internal/GRPCInterceptor.swift index 81ba3f0b..81d3cbb6 100644 --- a/Libraries/ConnectNIO/Internal/GRPCInterceptor.swift +++ b/Libraries/ConnectNIO/Internal/GRPCInterceptor.swift @@ -99,7 +99,7 @@ extension GRPCInterceptor: Connect.Interceptor { } func streamFunction() -> Connect.StreamFunction { - var responseHeaders: Connect.Headers? + let responseHeaders = Locked(nil) return Connect.StreamFunction( requestFunction: { request in return Connect.HTTPRequest( @@ -117,12 +117,12 @@ extension GRPCInterceptor: Connect.Interceptor { streamResultFunction: { result in switch result { case .headers(let headers): - responseHeaders = headers + responseHeaders.value = headers return result case .message(let data): do { - let responseCompressionPool = responseHeaders?[ + let responseCompressionPool = responseHeaders.value?[ Connect.HeaderConstants.grpcContentEncoding ]?.first.flatMap { self.config.responseCompressionPool(forName: $0) } return .message(try Connect.Envelope.unpackMessage( diff --git a/Libraries/ConnectNIO/Public/NIOHTTPClient.swift b/Libraries/ConnectNIO/Public/NIOHTTPClient.swift index 88393107..a1def07d 100644 --- a/Libraries/ConnectNIO/Public/NIOHTTPClient.swift +++ b/Libraries/ConnectNIO/Public/NIOHTTPClient.swift @@ -23,7 +23,7 @@ import NIOSSL import os.log /// HTTP client powered by Swift NIO which supports trailers (unlike URLSession). -open class NIOHTTPClient: Connect.HTTPClientInterface { +open class NIOHTTPClient: Connect.HTTPClientInterface, @unchecked Sendable { private lazy var bootstrap = self.createBootstrap() private let host: String private let lock = NIOConcurrencyHelpers.NIOLock() @@ -146,7 +146,7 @@ open class NIOHTTPClient: Connect.HTTPClientInterface { )) } } - return .init(cancel: handler.cancel) + return .init(cancel: { handler.cancel() }) } open func stream( @@ -169,7 +169,7 @@ open class NIOHTTPClient: Connect.HTTPClientInterface { } } return .init( - sendData: handler.sendData, + sendData: { handler.sendData($0) }, sendClose: { handler.close(trailers: nil) } ) } @@ -204,7 +204,7 @@ open class NIOHTTPClient: Connect.HTTPClientInterface { .whenComplete { [weak self] result in switch result { case .success((let channel, let multiplexer)): - channel.closeFuture.whenComplete { _ in + channel.closeFuture.whenComplete { [weak self] _ in self?.lock.withLock { self?.state = .disconnected } } self?.lock.withLock { diff --git a/Libraries/ConnectNIO/Public/NetworkProtocol+Extensions.swift b/Libraries/ConnectNIO/Public/NetworkProtocol+Extensions.swift index d22f423a..8ab0f5b6 100644 --- a/Libraries/ConnectNIO/Public/NetworkProtocol+Extensions.swift +++ b/Libraries/ConnectNIO/Public/NetworkProtocol+Extensions.swift @@ -21,6 +21,6 @@ extension NetworkProtocol { /// IMPORTANT: This protocol must be used in conjunction with an HTTP client that supports /// trailers, such as the `NIOHTTPClient` included in this library. public static var grpc: Self { - return .custom(name: "gRPC", protocolInterceptor: GRPCInterceptor.init) + return .custom(name: "gRPC", protocolInterceptor: { GRPCInterceptor(config: $0) }) } } From 1e7665de85936dfacd5fbae48fb80e9783292918 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 22 Aug 2023 16:38:11 -0700 Subject: [PATCH 06/18] tests are green --- .../Implementation/Interceptors/InterceptorChain.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift b/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift index 74963506..c5aeaf5b 100644 --- a/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift +++ b/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift @@ -24,7 +24,8 @@ struct InterceptorChain: Sendable { /// - parameter interceptors: Closures that should be called to create interceptors. /// - parameter config: Config to use for setting up interceptors. init( - interceptors: [(ProtocolClientConfig) -> Interceptor], config: ProtocolClientConfig + interceptors: [@Sendable (ProtocolClientConfig) -> Interceptor], + config: ProtocolClientConfig ) { self.interceptors = interceptors.map { initialize in initialize(config) } } @@ -85,7 +86,7 @@ struct InterceptorChain: Sendable { } } -private func executeInterceptors(_ interceptors: [(T) -> T], initial: T) -> T { +private func executeInterceptors(_ interceptors: [@Sendable (T) -> T], initial: T) -> T { var next = initial for interceptor in interceptors { next = interceptor(next) From 9b2015ad20deb9331b6efd2f029478eefb40bf88 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Wed, 6 Sep 2023 13:42:20 -0700 Subject: [PATCH 07/18] cleanup --- .swiftlint.yml | 2 +- .../Implementation/Codecs/JSONCodec.swift | 2 +- Libraries/Connect/Implementation/Locked.swift | 10 +++--- .../Implementation/ProtocolClient.swift | 20 +++--------- .../Interfaces/ProtocolClientInterface.swift | 32 +++++-------------- .../Connect/Interfaces/ResponseMessage.swift | 2 +- 6 files changed, 21 insertions(+), 47 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 8fe33263..292de188 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -115,7 +115,7 @@ custom_rules: name: "Closing braces shouldn't have empty lines before them" regex: '\n\n\}' sendable_order: - name: "Use @escaping before @Sendable" + name: "@escaping should precede @Sendable when used together" regex: '@Sendable\s+@escaping' space_before_comma: name: "Commas should never have a space before them" diff --git a/Libraries/Connect/Implementation/Codecs/JSONCodec.swift b/Libraries/Connect/Implementation/Codecs/JSONCodec.swift index fd30a205..29c7c69e 100644 --- a/Libraries/Connect/Implementation/Codecs/JSONCodec.swift +++ b/Libraries/Connect/Implementation/Codecs/JSONCodec.swift @@ -13,7 +13,7 @@ // limitations under the License. import Foundation -// TODO: Remove @preconcurrency once JSON(Encoding|Decoding)Options are Sendable +// TODO: Remove @preconcurrency once SwiftProtobuf's JSON(Encoding|Decoding)Options are Sendable @preconcurrency import SwiftProtobuf /// Codec providing functionality for serializing to/from JSON. diff --git a/Libraries/Connect/Implementation/Locked.swift b/Libraries/Connect/Implementation/Locked.swift index 88939210..5212368a 100644 --- a/Libraries/Connect/Implementation/Locked.swift +++ b/Libraries/Connect/Implementation/Locked.swift @@ -18,12 +18,12 @@ import Foundation /// underlying value. Conforms to `Sendable`, making it accessible from `@Sendable` closures. public final class Locked: @unchecked Sendable { private let lock = Lock() - private var _value: T + private var wrappedValue: T /// Thread-safe access to the underlying value. public var value: T { - get { self.lock.perform { self._value } } - set { self.lock.perform { self._value = newValue } } + get { self.lock.perform { self.wrappedValue } } + set { self.lock.perform { self.wrappedValue = newValue } } } /// Perform an action with the underlying value, potentially updating that value. @@ -31,11 +31,11 @@ public final class Locked: @unchecked Sendable { /// - parameter action: Closure to perform with the underlying value. public func perform(action: @escaping (inout T) -> Void) { self.lock.perform { - action(&self._value) + action(&self.wrappedValue) } } public init(_ value: T) { - self._value = value + self.wrappedValue = value } } diff --git a/Libraries/Connect/Implementation/ProtocolClient.swift b/Libraries/Connect/Implementation/ProtocolClient.swift index 2f04fb69..e7360b5b 100644 --- a/Libraries/Connect/Implementation/ProtocolClient.swift +++ b/Libraries/Connect/Implementation/ProtocolClient.swift @@ -38,9 +38,7 @@ extension ProtocolClient: ProtocolClientInterface { // MARK: - Callbacks @discardableResult - public func unary< - Input: ProtobufMessage, Output: ProtobufMessage - >( + public func unary( path: String, request: Input, headers: Headers, @@ -170,9 +168,7 @@ extension ProtocolClient: ProtocolClientInterface { // MARK: - Async/await @available(iOS 13, *) - public func unary< - Input: ProtobufMessage, Output: ProtobufMessage - >( + public func unary( path: String, request: Input, headers: Headers @@ -183,9 +179,7 @@ extension ProtocolClient: ProtocolClientInterface { } @available(iOS 13, *) - public func bidirectionalStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + public func bidirectionalStream( path: String, headers: Headers ) -> any BidirectionalAsyncStreamInterface { @@ -197,9 +191,7 @@ extension ProtocolClient: ProtocolClientInterface { } @available(iOS 13, *) - public func clientOnlyStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + public func clientOnlyStream( path: String, headers: Headers ) -> any ClientOnlyAsyncStreamInterface { @@ -211,9 +203,7 @@ extension ProtocolClient: ProtocolClientInterface { } @available(iOS 13, *) - public func serverOnlyStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + public func serverOnlyStream( path: String, headers: Headers ) -> any ServerOnlyAsyncStreamInterface { diff --git a/Libraries/Connect/Interfaces/ProtocolClientInterface.swift b/Libraries/Connect/Interfaces/ProtocolClientInterface.swift index 206cec4b..c6470915 100644 --- a/Libraries/Connect/Interfaces/ProtocolClientInterface.swift +++ b/Libraries/Connect/Interfaces/ProtocolClientInterface.swift @@ -30,9 +30,7 @@ public protocol ProtocolClientInterface { /// /// - returns: A `Cancelable` which provides the ability to cancel the outbound request. @discardableResult - func unary< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func unary( path: String, request: Input, headers: Headers, @@ -53,9 +51,7 @@ public protocol ProtocolClientInterface { /// (response headers, messages, trailers, etc.). /// /// - returns: An interface for interacting with and sending data over the bidirectional stream. - func bidirectionalStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func bidirectionalStream( path: String, headers: Headers, onResult: @escaping @Sendable (StreamResult) -> Void @@ -75,9 +71,7 @@ public protocol ProtocolClientInterface { /// (response headers, messages, trailers, etc.). /// /// - returns: An interface for interacting with and sending data over the client-only stream. - func clientOnlyStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func clientOnlyStream( path: String, headers: Headers, onResult: @escaping @Sendable (StreamResult) -> Void @@ -97,9 +91,7 @@ public protocol ProtocolClientInterface { /// (response headers, messages, trailers, etc.). /// /// - returns: An interface for interacting with and sending data over the server-only stream. - func serverOnlyStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func serverOnlyStream( path: String, headers: Headers, onResult: @escaping @Sendable (StreamResult) -> Void @@ -115,9 +107,7 @@ public protocol ProtocolClientInterface { /// /// - returns: The response which is returned asynchronously. @available(iOS 13, *) - func unary< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func unary( path: String, request: Input, headers: Headers @@ -136,9 +126,7 @@ public protocol ProtocolClientInterface { /// /// - returns: An interface for sending and receiving data over the stream using async/await. @available(iOS 13, *) - func bidirectionalStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func bidirectionalStream( path: String, headers: Headers ) -> any BidirectionalAsyncStreamInterface @@ -156,9 +144,7 @@ public protocol ProtocolClientInterface { /// /// - returns: An interface for sending and receiving data over the stream using async/await. @available(iOS 13, *) - func clientOnlyStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func clientOnlyStream( path: String, headers: Headers ) -> any ClientOnlyAsyncStreamInterface @@ -176,9 +162,7 @@ public protocol ProtocolClientInterface { /// /// - returns: An interface for sending and receiving data over the stream using async/await. @available(iOS 13, *) - func serverOnlyStream< - Input: ProtobufMessage, Output: ProtobufMessage - >( + func serverOnlyStream( path: String, headers: Headers ) -> any ServerOnlyAsyncStreamInterface diff --git a/Libraries/Connect/Interfaces/ResponseMessage.swift b/Libraries/Connect/Interfaces/ResponseMessage.swift index 73a5b6ef..a7dc7a86 100644 --- a/Libraries/Connect/Interfaces/ResponseMessage.swift +++ b/Libraries/Connect/Interfaces/ResponseMessage.swift @@ -15,7 +15,7 @@ import SwiftProtobuf /// Typed unary response from an RPC. -public struct ResponseMessage: Sendable { +public struct ResponseMessage: Sendable { /// The status code of the response. public let code: Code /// Response headers specified by the server. From 62d5c3af5ddce830a4e1645ad7d324955b2928bc Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Wed, 6 Sep 2023 13:45:05 -0700 Subject: [PATCH 08/18] fixup --- Libraries/Connect/Interfaces/ProtocolClientInterface.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Connect/Interfaces/ProtocolClientInterface.swift b/Libraries/Connect/Interfaces/ProtocolClientInterface.swift index c6470915..32528fa1 100644 --- a/Libraries/Connect/Interfaces/ProtocolClientInterface.swift +++ b/Libraries/Connect/Interfaces/ProtocolClientInterface.swift @@ -18,7 +18,7 @@ import SwiftProtobuf /// Primary interface consumed by generated RPCs to perform requests and streams. /// The client itself is protocol-agnostic, but can be configured during initialization /// (see `ProtocolClientConfig` and `ProtocolClientOption`). -public protocol ProtocolClientInterface { +public protocol ProtocolClientInterface: Sendable { // MARK: - Callbacks /// Perform a unary (non-streaming) request. From 6d489712ef2e18770179841bfab28bd20a20ea09 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 12 Sep 2023 12:34:20 -0700 Subject: [PATCH 09/18] fix mocks + tests --- .../GeneratedSources/eliza.connect.swift | 2 +- .../ConnectMockGenerator.swift | 26 ++---- .../ConnectPluginUtilities/Generator.swift | 7 ++ .../MethodDescriptor+Extensions.swift | 8 +- .../ConnectClientGenerator.swift | 11 +-- .../CallbackConformance.swift | 8 +- .../ConnectMocksTests/ConnectMocksTests.swift | 22 +++-- .../ProtocolClientConfigTests.swift | 4 +- .../Generated/grpc/testing/test.connect.swift | 92 +++++++++---------- .../Generated/grpc/testing/test.mock.swift | 52 +++++------ 10 files changed, 113 insertions(+), 119 deletions(-) diff --git a/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift b/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift index 59c1b72d..06b43a2f 100644 --- a/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift +++ b/Examples/ElizaSharedSources/GeneratedSources/eliza.connect.swift @@ -13,7 +13,7 @@ import SwiftProtobuf /// superficiality of human-computer communication. DOCTOR simulates a /// psychotherapist, and is commonly found as an Easter egg in emacs /// distributions. -internal protocol Connectrpc_Eliza_V1_ElizaServiceClientInterface { +internal protocol Connectrpc_Eliza_V1_ElizaServiceClientInterface: Sendable { /// Say is a unary RPC. Eliza responds to the prompt with a single sentence. @available(iOS 13, *) diff --git a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift index 73bc7489..924009e2 100644 --- a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift +++ b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift @@ -18,18 +18,7 @@ import SwiftProtobufPluginLibrary /// Responsible for generating services and RPCs that are compatible with the Connect library. final class ConnectMockGenerator: Generator { - private let propertyVisibility: String - private let typeVisibility: String - required init(_ descriptor: FileDescriptor, options: GeneratorOptions) { - switch options.visibility { - case .internal: - self.propertyVisibility = "internal" - self.typeVisibility = "internal" - case .public: - self.propertyVisibility = "public" - self.typeVisibility = "open" - } super.init(descriptor, options: options) self.printContent() } @@ -59,7 +48,10 @@ final class ConnectMockGenerator: Generator { self.printLine("/// subclassing the class and overriding its methods.") self.printLine("@available(iOS 13, *)") self.printLine( - "\(self.typeVisibility) class \(service.mockName(using: self.namer)): \(protocolName) {" + """ + \(self.visibility) class \(service.mockName(using: self.namer)): \ + \(protocolName), @unchecked Sendable { + """ ) self.indent { if self.options.generateCallbackMethods { @@ -74,7 +66,7 @@ final class ConnectMockGenerator: Generator { ) self.printLine( """ - \(self.propertyVisibility) var \(method.callbackMockPropertyName()) = \ + \(self.visibility) var \(method.callbackMockPropertyName()) = \ \(method.callbackMockPropertyValue(using: self.namer)) """ ) @@ -85,7 +77,7 @@ final class ConnectMockGenerator: Generator { ) self.printLine( """ - \(self.propertyVisibility) var \(method.asyncAwaitMockPropertyName()) = \ + \(self.visibility) var \(method.asyncAwaitMockPropertyName()) = \ \(method.asyncAwaitMockPropertyValue(using: self.namer)) """ ) @@ -93,7 +85,7 @@ final class ConnectMockGenerator: Generator { } self.printLine() - self.printLine("\(self.propertyVisibility) init() {}") + self.printLine("\(self.visibility) init() {}") for method in service.methods { if self.options.generateCallbackMethods { @@ -115,7 +107,7 @@ final class ConnectMockGenerator: Generator { } self.printLine( - "\(self.typeVisibility) " + "\(self.visibility) " + method.callbackSignature( using: self.namer, includeDefaults: true, options: self.options ) @@ -145,7 +137,7 @@ final class ConnectMockGenerator: Generator { self.printLine() self.printLine( - "\(self.typeVisibility) " + "\(self.visibility) " + method.asyncAwaitSignature( using: self.namer, includeDefaults: true, options: self.options ) diff --git a/Plugins/ConnectPluginUtilities/Generator.swift b/Plugins/ConnectPluginUtilities/Generator.swift index 8b2ac23d..11c4cd6f 100644 --- a/Plugins/ConnectPluginUtilities/Generator.swift +++ b/Plugins/ConnectPluginUtilities/Generator.swift @@ -21,6 +21,7 @@ open class Generator { public let descriptor: FileDescriptor public let namer: SwiftProtobufNamer public let options: GeneratorOptions + public let visibility: String public var output: String { return self.printer.content @@ -33,6 +34,12 @@ open class Generator { currentFile: descriptor, protoFileToModuleMappings: options.protoToModuleMappings ) + switch options.visibility { + case .internal: + self.visibility = "internal" + case .public: + self.visibility = "public" + } } // MARK: - Output helpers diff --git a/Plugins/ConnectPluginUtilities/MethodDescriptor+Extensions.swift b/Plugins/ConnectPluginUtilities/MethodDescriptor+Extensions.swift index 8a47ebbe..dc681ebd 100644 --- a/Plugins/ConnectPluginUtilities/MethodDescriptor+Extensions.swift +++ b/Plugins/ConnectPluginUtilities/MethodDescriptor+Extensions.swift @@ -37,28 +37,28 @@ extension MethodDescriptor { return """ func `\(methodName)`\ (headers: Connect.Headers\(includeDefaults ? " = [:]" : ""), \ - onResult: @escaping (Connect.StreamResult<\(outputName)>) -> Void) \ + onResult: @escaping @Sendable (Connect.StreamResult<\(outputName)>) -> Void) \ -> any Connect.BidirectionalStreamInterface<\(inputName)> """ } else if self.serverStreaming { return """ func `\(methodName)`\ (headers: Connect.Headers\(includeDefaults ? " = [:]" : ""), \ - onResult: @escaping (Connect.StreamResult<\(outputName)>) -> Void) \ + onResult: @escaping @Sendable (Connect.StreamResult<\(outputName)>) -> Void) \ -> any Connect.ServerOnlyStreamInterface<\(inputName)> """ } else if self.clientStreaming { return """ func `\(methodName)`\ (headers: Connect.Headers\(includeDefaults ? " = [:]" : ""), \ - onResult: @escaping (Connect.StreamResult<\(outputName)>) -> Void) \ + onResult: @escaping @Sendable (Connect.StreamResult<\(outputName)>) -> Void) \ -> any Connect.ClientOnlyStreamInterface<\(inputName)> """ } else { return """ func `\(methodName)`\ (request: \(inputName), headers: Connect.Headers\(includeDefaults ? " = [:]" : ""), \ - completion: @escaping (ResponseMessage<\(outputName)>) -> Void) \ + completion: @escaping @Sendable (ResponseMessage<\(outputName)>) -> Void) \ -> Connect.Cancelable """ } diff --git a/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift b/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift index e2b8d9f8..1fc1df83 100644 --- a/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift +++ b/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift @@ -18,17 +18,8 @@ import SwiftProtobufPluginLibrary /// Responsible for generating services and RPCs that are compatible with the Connect library. final class ConnectClientGenerator: Generator { - private let visibility: String - required init(_ descriptor: FileDescriptor, options: GeneratorOptions) { - switch options.visibility { - case .internal: - self.visibility = "internal" - case .public: - self.visibility = "public" - } super.init(descriptor, options: options) - self.printContent() } @@ -47,7 +38,7 @@ final class ConnectClientGenerator: Generator { self.printCommentsIfNeeded(for: service) let protocolName = service.protocolName(using: self.namer) - self.printLine("\(self.visibility) protocol \(protocolName) {") + self.printLine("\(self.visibility) protocol \(protocolName): Sendable {") self.indent { for method in service.methods { if self.options.generateCallbackMethods { diff --git a/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift b/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift index 1c91b4c5..a435d240 100644 --- a/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift +++ b/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift @@ -86,15 +86,15 @@ final class CallbackConformance: XCTestCase { try self.executeTestWithClients { client in let sizes = [31_415, 9, 2_653, 58_979] let expectation = self.expectation(description: "Stream completes") - var responseCount = 0 + let responseCount = Locked(0) let stream = client.streamingOutputCall { result in switch result { case .headers: break case .message(let output): - XCTAssertEqual(output.payload.body.count, sizes[responseCount]) - responseCount += 1 + XCTAssertEqual(output.payload.body.count, sizes[responseCount.value]) + responseCount.perform { $0 += 1 } case .complete(let code, let error, _): XCTAssertEqual(code, .ok) @@ -112,7 +112,7 @@ final class CallbackConformance: XCTestCase { }) XCTAssertEqual(XCTWaiter().wait(for: [expectation], timeout: kTimeout), .completed) - XCTAssertEqual(responseCount, 4) + XCTAssertEqual(responseCount.value, 4) } } diff --git a/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift b/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift index 5ac38041..5db685ac 100644 --- a/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift +++ b/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift @@ -29,11 +29,11 @@ final class ConnectMocksTests: XCTestCase { return ResponseMessage(result: .success(.with { $0.hostname = "pong" })) } - var receivedMessage: Grpc_Testing_SimpleResponse? + let receivedMessage = Locked(nil) client.unaryCall(request: .with { $0.fillUsername = true }) { response in - receivedMessage = response.message + receivedMessage.value = response.message } - XCTAssertEqual(receivedMessage?.hostname, "pong") + XCTAssertEqual(receivedMessage.value?.hostname, "pong") } func testMockUnaryAsyncAwait() async { @@ -69,15 +69,17 @@ final class ConnectMocksTests: XCTestCase { client.mockFullDuplexCall.onClose = { closeCalled = true } client.mockFullDuplexCall.outputs = Array(expectedResults) - var receivedResults = [StreamResult]() - let stream = client.fullDuplexCall { receivedResults.append($0) } + let receivedResults = Locked<[StreamResult]>([]) + let stream = client.fullDuplexCall { result in + receivedResults.perform { $0.append(result) } + } try stream.send(expectedInputs[0]) try stream.send(expectedInputs[1]) stream.close() XCTAssertEqual(sentInputs, expectedInputs) XCTAssertEqual(client.mockFullDuplexCall.inputs, expectedInputs) - XCTAssertEqual(receivedResults, expectedResults) + XCTAssertEqual(receivedResults.value, expectedResults) XCTAssertTrue(closeCalled) XCTAssertTrue(client.mockFullDuplexCall.isClosed) } @@ -134,13 +136,15 @@ final class ConnectMocksTests: XCTestCase { client.mockUnimplementedStreamingOutputCall.onSend = { sentInputs.append($0) } client.mockUnimplementedStreamingOutputCall.outputs = Array(expectedResults) - var receivedResults = [StreamResult]() - let stream = client.unimplementedStreamingOutputCall { receivedResults.append($0) } + let receivedResults = Locked<[StreamResult]>([]) + let stream = client.unimplementedStreamingOutputCall { result in + receivedResults.perform { $0.append(result) } + } try stream.send(expectedInput) XCTAssertEqual(sentInputs, [expectedInput]) XCTAssertEqual(client.mockUnimplementedStreamingOutputCall.inputs, [expectedInput]) - XCTAssertEqual(receivedResults, expectedResults) + XCTAssertEqual(receivedResults.value, expectedResults) } func testMockServerOnlyStreamAsyncAwait() async throws { diff --git a/Tests/ConnectLibraryTests/ConnectTests/ProtocolClientConfigTests.swift b/Tests/ConnectLibraryTests/ConnectTests/ProtocolClientConfigTests.swift index 09b47260..bbacb7fa 100644 --- a/Tests/ConnectLibraryTests/ConnectTests/ProtocolClientConfigTests.swift +++ b/Tests/ConnectLibraryTests/ConnectTests/ProtocolClientConfigTests.swift @@ -61,7 +61,7 @@ final class ProtocolClientConfigTests: XCTestCase { let config = ProtocolClientConfig( host: "https://buf.build", networkProtocol: .connect, - interceptors: [NoopInterceptor.init] + interceptors: [{ NoopInterceptor(config: $0) }] ) XCTAssertTrue(config.interceptors[0](config) is NoopInterceptor) XCTAssertTrue(config.interceptors[1](config) is ConnectInterceptor) @@ -71,7 +71,7 @@ final class ProtocolClientConfigTests: XCTestCase { let config = ProtocolClientConfig( host: "https://buf.build", networkProtocol: .grpcWeb, - interceptors: [NoopInterceptor.init] + interceptors: [{ NoopInterceptor(config: $0) }] ) XCTAssertTrue(config.interceptors[0](config) is NoopInterceptor) XCTAssertTrue(config.interceptors[1](config) is GRPCWebInterceptor) diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift index 7eef4631..2713a106 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.connect.swift @@ -9,11 +9,11 @@ import SwiftProtobuf /// A simple service to test the various types of RPCs and experiment with /// performance with various types of payload. -internal protocol Grpc_Testing_TestServiceClientInterface { +internal protocol Grpc_Testing_TestServiceClientInterface: Sendable { /// One empty request followed by one empty response. @discardableResult - func `emptyCall`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `emptyCall`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// One empty request followed by one empty response. @available(iOS 13, *) @@ -21,7 +21,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// One request followed by one response. @discardableResult - func `unaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `unaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// One request followed by one response. @available(iOS 13, *) @@ -29,7 +29,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// One request followed by one response. This RPC always fails. @discardableResult - func `failUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `failUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// One request followed by one response. This RPC always fails. @available(iOS 13, *) @@ -39,7 +39,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// headers set such that a caching HTTP proxy (such as GFE) can /// satisfy subsequent requests. @discardableResult - func `cacheableUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `cacheableUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// One request followed by one response. Response has cache control /// headers set such that a caching HTTP proxy (such as GFE) can @@ -49,7 +49,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// One request followed by a sequence of responses (streamed download). /// The server returns the payload with client desired type and sizes. - func `streamingOutputCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface + func `streamingOutputCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface /// One request followed by a sequence of responses (streamed download). /// The server returns the payload with client desired type and sizes. @@ -57,7 +57,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { func `streamingOutputCall`(headers: Connect.Headers) -> any Connect.ServerOnlyAsyncStreamInterface /// One request followed by a sequence of responses (streamed download). This RPC always fails. - func `failStreamingOutputCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface + func `failStreamingOutputCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface /// One request followed by a sequence of responses (streamed download). This RPC always fails. @available(iOS 13, *) @@ -65,7 +65,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// A sequence of requests followed by one response (streamed upload). /// The server returns the aggregated size of client payload as the result. - func `streamingInputCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ClientOnlyStreamInterface + func `streamingInputCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ClientOnlyStreamInterface /// A sequence of requests followed by one response (streamed upload). /// The server returns the aggregated size of client payload as the result. @@ -75,7 +75,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// A sequence of requests with each request served by the server immediately. /// As one request could lead to multiple responses, this interface /// demonstrates the idea of full duplexing. - func `fullDuplexCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface + func `fullDuplexCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface /// A sequence of requests with each request served by the server immediately. /// As one request could lead to multiple responses, this interface @@ -87,7 +87,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// The server buffers all the client requests and then serves them in order. A /// stream of responses are returned to the client when the server starts with /// first request. - func `halfDuplexCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface + func `halfDuplexCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface /// A sequence of requests followed by a sequence of responses. /// The server buffers all the client requests and then serves them in order. A @@ -99,7 +99,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// The test server will not implement this method. It will be used /// to test the behavior when clients call unimplemented methods. @discardableResult - func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// The test server will not implement this method. It will be used /// to test the behavior when clients call unimplemented methods. @@ -108,7 +108,7 @@ internal protocol Grpc_Testing_TestServiceClientInterface { /// The test server will not implement this method. It will be used /// to test the behavior when clients call unimplemented streaming output methods. - func `unimplementedStreamingOutputCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface + func `unimplementedStreamingOutputCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface /// The test server will not implement this method. It will be used /// to test the behavior when clients call unimplemented streaming output methods. @@ -125,7 +125,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli } @discardableResult - internal func `emptyCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `emptyCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.TestService/EmptyCall", request: request, headers: headers, completion: completion) } @@ -135,7 +135,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli } @discardableResult - internal func `unaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `unaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.TestService/UnaryCall", request: request, headers: headers, completion: completion) } @@ -145,7 +145,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli } @discardableResult - internal func `failUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `failUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.TestService/FailUnaryCall", request: request, headers: headers, completion: completion) } @@ -155,7 +155,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli } @discardableResult - internal func `cacheableUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `cacheableUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.TestService/CacheableUnaryCall", request: request, headers: headers, completion: completion) } @@ -164,7 +164,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli return await self.client.unary(path: "/grpc.testing.TestService/CacheableUnaryCall", request: request, headers: headers) } - internal func `streamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `streamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { return self.client.serverOnlyStream(path: "/grpc.testing.TestService/StreamingOutputCall", headers: headers, onResult: onResult) } @@ -173,7 +173,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli return self.client.serverOnlyStream(path: "/grpc.testing.TestService/StreamingOutputCall", headers: headers) } - internal func `failStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `failStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { return self.client.serverOnlyStream(path: "/grpc.testing.TestService/FailStreamingOutputCall", headers: headers, onResult: onResult) } @@ -182,7 +182,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli return self.client.serverOnlyStream(path: "/grpc.testing.TestService/FailStreamingOutputCall", headers: headers) } - internal func `streamingInputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ClientOnlyStreamInterface { + internal func `streamingInputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ClientOnlyStreamInterface { return self.client.clientOnlyStream(path: "/grpc.testing.TestService/StreamingInputCall", headers: headers, onResult: onResult) } @@ -191,7 +191,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli return self.client.clientOnlyStream(path: "/grpc.testing.TestService/StreamingInputCall", headers: headers) } - internal func `fullDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { + internal func `fullDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { return self.client.bidirectionalStream(path: "/grpc.testing.TestService/FullDuplexCall", headers: headers, onResult: onResult) } @@ -200,7 +200,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli return self.client.bidirectionalStream(path: "/grpc.testing.TestService/FullDuplexCall", headers: headers) } - internal func `halfDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { + internal func `halfDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { return self.client.bidirectionalStream(path: "/grpc.testing.TestService/HalfDuplexCall", headers: headers, onResult: onResult) } @@ -210,7 +210,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli } @discardableResult - internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.TestService/UnimplementedCall", request: request, headers: headers, completion: completion) } @@ -219,7 +219,7 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli return await self.client.unary(path: "/grpc.testing.TestService/UnimplementedCall", request: request, headers: headers) } - internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { return self.client.serverOnlyStream(path: "/grpc.testing.TestService/UnimplementedStreamingOutputCall", headers: headers, onResult: onResult) } @@ -247,18 +247,18 @@ internal final class Grpc_Testing_TestServiceClient: Grpc_Testing_TestServiceCli /// A simple service NOT implemented at servers so clients can test for /// that case. -internal protocol Grpc_Testing_UnimplementedServiceClientInterface { +internal protocol Grpc_Testing_UnimplementedServiceClientInterface: Sendable { /// A call that no server should implement @discardableResult - func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// A call that no server should implement @available(iOS 13, *) func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers) async -> ResponseMessage /// A call that no server should implement - func `unimplementedStreamingOutputCall`(headers: Connect.Headers, onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface + func `unimplementedStreamingOutputCall`(headers: Connect.Headers, onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface /// A call that no server should implement @available(iOS 13, *) @@ -274,7 +274,7 @@ internal final class Grpc_Testing_UnimplementedServiceClient: Grpc_Testing_Unimp } @discardableResult - internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.UnimplementedService/UnimplementedCall", request: request, headers: headers, completion: completion) } @@ -283,7 +283,7 @@ internal final class Grpc_Testing_UnimplementedServiceClient: Grpc_Testing_Unimp return await self.client.unary(path: "/grpc.testing.UnimplementedService/UnimplementedCall", request: request, headers: headers) } - internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { return self.client.serverOnlyStream(path: "/grpc.testing.UnimplementedService/UnimplementedStreamingOutputCall", headers: headers, onResult: onResult) } @@ -301,16 +301,16 @@ internal final class Grpc_Testing_UnimplementedServiceClient: Grpc_Testing_Unimp } /// A service used to control reconnect server. -internal protocol Grpc_Testing_ReconnectServiceClientInterface { +internal protocol Grpc_Testing_ReconnectServiceClientInterface: Sendable { @discardableResult - func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable @available(iOS 13, *) func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers) async -> ResponseMessage @discardableResult - func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable @available(iOS 13, *) func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers) async -> ResponseMessage @@ -325,7 +325,7 @@ internal final class Grpc_Testing_ReconnectServiceClient: Grpc_Testing_Reconnect } @discardableResult - internal func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.ReconnectService/Start", request: request, headers: headers, completion: completion) } @@ -335,7 +335,7 @@ internal final class Grpc_Testing_ReconnectServiceClient: Grpc_Testing_Reconnect } @discardableResult - internal func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.ReconnectService/Stop", request: request, headers: headers, completion: completion) } @@ -353,11 +353,11 @@ internal final class Grpc_Testing_ReconnectServiceClient: Grpc_Testing_Reconnect } /// A service used to obtain stats for verifying LB behavior. -internal protocol Grpc_Testing_LoadBalancerStatsServiceClientInterface { +internal protocol Grpc_Testing_LoadBalancerStatsServiceClientInterface: Sendable { /// Gets the backend distribution for RPCs sent by a test client. @discardableResult - func `getClientStats`(request: Grpc_Testing_LoadBalancerStatsRequest, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `getClientStats`(request: Grpc_Testing_LoadBalancerStatsRequest, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// Gets the backend distribution for RPCs sent by a test client. @available(iOS 13, *) @@ -365,7 +365,7 @@ internal protocol Grpc_Testing_LoadBalancerStatsServiceClientInterface { /// Gets the accumulated stats for RPCs sent by a test client. @discardableResult - func `getClientAccumulatedStats`(request: Grpc_Testing_LoadBalancerAccumulatedStatsRequest, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `getClientAccumulatedStats`(request: Grpc_Testing_LoadBalancerAccumulatedStatsRequest, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// Gets the accumulated stats for RPCs sent by a test client. @available(iOS 13, *) @@ -381,7 +381,7 @@ internal final class Grpc_Testing_LoadBalancerStatsServiceClient: Grpc_Testing_L } @discardableResult - internal func `getClientStats`(request: Grpc_Testing_LoadBalancerStatsRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `getClientStats`(request: Grpc_Testing_LoadBalancerStatsRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.LoadBalancerStatsService/GetClientStats", request: request, headers: headers, completion: completion) } @@ -391,7 +391,7 @@ internal final class Grpc_Testing_LoadBalancerStatsServiceClient: Grpc_Testing_L } @discardableResult - internal func `getClientAccumulatedStats`(request: Grpc_Testing_LoadBalancerAccumulatedStatsRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `getClientAccumulatedStats`(request: Grpc_Testing_LoadBalancerAccumulatedStatsRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.LoadBalancerStatsService/GetClientAccumulatedStats", request: request, headers: headers, completion: completion) } @@ -409,16 +409,16 @@ internal final class Grpc_Testing_LoadBalancerStatsServiceClient: Grpc_Testing_L } /// A service to remotely control health status of an xDS test server. -internal protocol Grpc_Testing_XdsUpdateHealthServiceClientInterface { +internal protocol Grpc_Testing_XdsUpdateHealthServiceClientInterface: Sendable { @discardableResult - func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable @available(iOS 13, *) func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers) async -> ResponseMessage @discardableResult - func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable @available(iOS 13, *) func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers) async -> ResponseMessage @@ -433,7 +433,7 @@ internal final class Grpc_Testing_XdsUpdateHealthServiceClient: Grpc_Testing_Xds } @discardableResult - internal func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.XdsUpdateHealthService/SetServing", request: request, headers: headers, completion: completion) } @@ -443,7 +443,7 @@ internal final class Grpc_Testing_XdsUpdateHealthServiceClient: Grpc_Testing_Xds } @discardableResult - internal func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.XdsUpdateHealthService/SetNotServing", request: request, headers: headers, completion: completion) } @@ -461,11 +461,11 @@ internal final class Grpc_Testing_XdsUpdateHealthServiceClient: Grpc_Testing_Xds } /// A service to dynamically update the configuration of an xDS test client. -internal protocol Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface { +internal protocol Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface: Sendable { /// Update the tes client's configuration. @discardableResult - func `configure`(request: Grpc_Testing_ClientConfigureRequest, headers: Connect.Headers, completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable + func `configure`(request: Grpc_Testing_ClientConfigureRequest, headers: Connect.Headers, completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable /// Update the tes client's configuration. @available(iOS 13, *) @@ -481,7 +481,7 @@ internal final class Grpc_Testing_XdsUpdateClientConfigureServiceClient: Grpc_Te } @discardableResult - internal func `configure`(request: Grpc_Testing_ClientConfigureRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `configure`(request: Grpc_Testing_ClientConfigureRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { return self.client.unary(path: "/grpc.testing.XdsUpdateClientConfigureService/Configure", request: request, headers: headers, completion: completion) } diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift index d6eaca29..a386c237 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift @@ -16,7 +16,7 @@ import SwiftProtobuf /// either through the properties on this class or by /// subclassing the class and overriding its methods. @available(iOS 13, *) -internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClientInterface { +internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `emptyCall()`. @@ -67,7 +67,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien internal init() {} @discardableResult - internal func `emptyCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `emptyCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockEmptyCall(request)) return Connect.Cancelable {} } @@ -77,7 +77,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien } @discardableResult - internal func `unaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `unaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockUnaryCall(request)) return Connect.Cancelable {} } @@ -87,7 +87,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien } @discardableResult - internal func `failUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `failUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockFailUnaryCall(request)) return Connect.Cancelable {} } @@ -97,7 +97,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien } @discardableResult - internal func `cacheableUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `cacheableUnaryCall`(request: Grpc_Testing_SimpleRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockCacheableUnaryCall(request)) return Connect.Cancelable {} } @@ -106,7 +106,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien return self.mockAsyncCacheableUnaryCall(request) } - internal func `streamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `streamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { self.mockStreamingOutputCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockStreamingOutputCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockStreamingOutputCall } @@ -115,7 +115,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien return self.mockAsyncStreamingOutputCall } - internal func `failStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `failStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { self.mockFailStreamingOutputCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockFailStreamingOutputCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockFailStreamingOutputCall } @@ -124,7 +124,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien return self.mockAsyncFailStreamingOutputCall } - internal func `streamingInputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ClientOnlyStreamInterface { + internal func `streamingInputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ClientOnlyStreamInterface { self.mockStreamingInputCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockStreamingInputCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockStreamingInputCall } @@ -133,7 +133,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien return self.mockAsyncStreamingInputCall } - internal func `fullDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { + internal func `fullDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { self.mockFullDuplexCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockFullDuplexCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockFullDuplexCall } @@ -142,7 +142,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien return self.mockAsyncFullDuplexCall } - internal func `halfDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { + internal func `halfDuplexCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.BidirectionalStreamInterface { self.mockHalfDuplexCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockHalfDuplexCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockHalfDuplexCall } @@ -152,7 +152,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien } @discardableResult - internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockUnimplementedCall(request)) return Connect.Cancelable {} } @@ -161,7 +161,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien return self.mockAsyncUnimplementedCall(request) } - internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { self.mockUnimplementedStreamingOutputCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockUnimplementedStreamingOutputCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockUnimplementedStreamingOutputCall } @@ -178,7 +178,7 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien /// either through the properties on this class or by /// subclassing the class and overriding its methods. @available(iOS 13, *) -internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_UnimplementedServiceClientInterface { +internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_UnimplementedServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `unimplementedCall()`. @@ -193,7 +193,7 @@ internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_Unimple internal init() {} @discardableResult - internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `unimplementedCall`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockUnimplementedCall(request)) return Connect.Cancelable {} } @@ -202,7 +202,7 @@ internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_Unimple return self.mockAsyncUnimplementedCall(request) } - internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { + internal func `unimplementedStreamingOutputCall`(headers: Connect.Headers = [:], onResult: @escaping @Sendable (Connect.StreamResult) -> Void) -> any Connect.ServerOnlyStreamInterface { self.mockUnimplementedStreamingOutputCall.$inputs.first { !$0.isEmpty }.sink { _ in self.mockUnimplementedStreamingOutputCall.outputs.forEach(onResult) }.store(in: &self.cancellables) return self.mockUnimplementedStreamingOutputCall } @@ -219,7 +219,7 @@ internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_Unimple /// either through the properties on this class or by /// subclassing the class and overriding its methods. @available(iOS 13, *) -internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectServiceClientInterface { +internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `start()`. @@ -234,7 +234,7 @@ internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectSe internal init() {} @discardableResult - internal func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `start`(request: Grpc_Testing_ReconnectParams, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockStart(request)) return Connect.Cancelable {} } @@ -244,7 +244,7 @@ internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectSe } @discardableResult - internal func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `stop`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockStop(request)) return Connect.Cancelable {} } @@ -261,7 +261,7 @@ internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectSe /// either through the properties on this class or by /// subclassing the class and overriding its methods. @available(iOS 13, *) -internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_LoadBalancerStatsServiceClientInterface { +internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_LoadBalancerStatsServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `getClientStats()`. @@ -276,7 +276,7 @@ internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_Loa internal init() {} @discardableResult - internal func `getClientStats`(request: Grpc_Testing_LoadBalancerStatsRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `getClientStats`(request: Grpc_Testing_LoadBalancerStatsRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockGetClientStats(request)) return Connect.Cancelable {} } @@ -286,7 +286,7 @@ internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_Loa } @discardableResult - internal func `getClientAccumulatedStats`(request: Grpc_Testing_LoadBalancerAccumulatedStatsRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `getClientAccumulatedStats`(request: Grpc_Testing_LoadBalancerAccumulatedStatsRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockGetClientAccumulatedStats(request)) return Connect.Cancelable {} } @@ -303,7 +303,7 @@ internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_Loa /// either through the properties on this class or by /// subclassing the class and overriding its methods. @available(iOS 13, *) -internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUpdateHealthServiceClientInterface { +internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUpdateHealthServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `setServing()`. @@ -318,7 +318,7 @@ internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUp internal init() {} @discardableResult - internal func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `setServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockSetServing(request)) return Connect.Cancelable {} } @@ -328,7 +328,7 @@ internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUp } @discardableResult - internal func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `setNotServing`(request: Grpc_Testing_Empty, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockSetNotServing(request)) return Connect.Cancelable {} } @@ -345,7 +345,7 @@ internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUp /// either through the properties on this class or by /// subclassing the class and overriding its methods. @available(iOS 13, *) -internal class Grpc_Testing_XdsUpdateClientConfigureServiceClientMock: Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface { +internal class Grpc_Testing_XdsUpdateClientConfigureServiceClientMock: Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `configure()`. @@ -356,7 +356,7 @@ internal class Grpc_Testing_XdsUpdateClientConfigureServiceClientMock: Grpc_Test internal init() {} @discardableResult - internal func `configure`(request: Grpc_Testing_ClientConfigureRequest, headers: Connect.Headers = [:], completion: @escaping (ResponseMessage) -> Void) -> Connect.Cancelable { + internal func `configure`(request: Grpc_Testing_ClientConfigureRequest, headers: Connect.Headers = [:], completion: @escaping @Sendable (ResponseMessage) -> Void) -> Connect.Cancelable { completion(self.mockConfigure(request)) return Connect.Cancelable {} } From 1f402c18f67e4778bbb13217525af97b85db5dde Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 12 Sep 2023 12:36:18 -0700 Subject: [PATCH 10/18] make mock final --- Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift index 924009e2..400a8429 100644 --- a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift +++ b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift @@ -49,7 +49,7 @@ final class ConnectMockGenerator: Generator { self.printLine("@available(iOS 13, *)") self.printLine( """ - \(self.visibility) class \(service.mockName(using: self.namer)): \ + \(self.visibility) final class \(service.mockName(using: self.namer)): \ \(protocolName), @unchecked Sendable { """ ) From eae29a7eeb1fbcfb415cdb0b4d6b90bffe748486 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 12 Sep 2023 13:42:57 -0700 Subject: [PATCH 11/18] fixes --- .../ConnectMockGenerator.swift | 3 ++ README.md | 8 ++--- .../Generated/grpc/testing/test.mock.swift | 30 +++++++++++++++---- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift index 400a8429..f5a23a30 100644 --- a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift +++ b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift @@ -46,6 +46,9 @@ final class ConnectMockGenerator: Generator { self.printLine("/// class, allowing for mocking RPC calls. Behavior can be customized") self.printLine("/// either through the properties on this class or by") self.printLine("/// subclassing the class and overriding its methods.") + self.printLine("///") + self.printLine("/// Note: This class does not handle thread-safe locking, but provides") + self.printLine("/// `@unchecked Sendable` conformance to simplify testing and mocking.") self.printLine("@available(iOS 13, *)") self.printLine( """ diff --git a/README.md b/README.md index eb725549..36400f39 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,12 @@ protocol interfaces and client implementations:
Click to expand eliza.connect.swift ```swift -public protocol Eliza_V1_ChatServiceClientInterface { +public protocol Eliza_V1_ChatServiceClientInterface: Sendable { func say(request: Eliza_V1_SayRequest, headers: Headers) async -> ResponseMessage } -public final class Eliza_V1_ChatServiceClient: Eliza_V1_ChatServiceClientInterface { +public final class Eliza_V1_ChatServiceClient: Eliza_V1_ChatServiceClientInterface, Sendable { private let client: ProtocolClientInterface public init(client: ProtocolClientInterface) { @@ -85,10 +85,10 @@ protocol interfaces as the production clients:
Click to expand eliza.mock.swift ```swift -open class Eliza_V1_ChatServiceClientMock: Eliza_V1_ChatServiceClientInterface { +public final class Eliza_V1_ChatServiceClientMock: Eliza_V1_ChatServiceClientInterface, @unchecked Sendable { public var mockAsyncSay = { (_: Eliza_V1_SayRequest) -> ResponseMessage in .init(message: .init()) } - open func say(request: Eliza_V1_SayRequest, headers: Headers = [:]) + public func say(request: Eliza_V1_SayRequest, headers: Headers = [:]) async -> ResponseMessage { return self.mockAsyncSay(request) diff --git a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift index a386c237..cdb2326c 100644 --- a/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift +++ b/Tests/ConnectLibraryTests/Generated/grpc/testing/test.mock.swift @@ -15,8 +15,11 @@ import SwiftProtobuf /// class, allowing for mocking RPC calls. Behavior can be customized /// either through the properties on this class or by /// subclassing the class and overriding its methods. +/// +/// Note: This class does not handle thread-safe locking, but provides +/// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClientInterface, @unchecked Sendable { +internal final class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `emptyCall()`. @@ -177,8 +180,11 @@ internal class Grpc_Testing_TestServiceClientMock: Grpc_Testing_TestServiceClien /// class, allowing for mocking RPC calls. Behavior can be customized /// either through the properties on this class or by /// subclassing the class and overriding its methods. +/// +/// Note: This class does not handle thread-safe locking, but provides +/// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_UnimplementedServiceClientInterface, @unchecked Sendable { +internal final class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_UnimplementedServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `unimplementedCall()`. @@ -218,8 +224,11 @@ internal class Grpc_Testing_UnimplementedServiceClientMock: Grpc_Testing_Unimple /// class, allowing for mocking RPC calls. Behavior can be customized /// either through the properties on this class or by /// subclassing the class and overriding its methods. +/// +/// Note: This class does not handle thread-safe locking, but provides +/// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectServiceClientInterface, @unchecked Sendable { +internal final class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `start()`. @@ -260,8 +269,11 @@ internal class Grpc_Testing_ReconnectServiceClientMock: Grpc_Testing_ReconnectSe /// class, allowing for mocking RPC calls. Behavior can be customized /// either through the properties on this class or by /// subclassing the class and overriding its methods. +/// +/// Note: This class does not handle thread-safe locking, but provides +/// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_LoadBalancerStatsServiceClientInterface, @unchecked Sendable { +internal final class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_LoadBalancerStatsServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `getClientStats()`. @@ -302,8 +314,11 @@ internal class Grpc_Testing_LoadBalancerStatsServiceClientMock: Grpc_Testing_Loa /// class, allowing for mocking RPC calls. Behavior can be customized /// either through the properties on this class or by /// subclassing the class and overriding its methods. +/// +/// Note: This class does not handle thread-safe locking, but provides +/// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUpdateHealthServiceClientInterface, @unchecked Sendable { +internal final class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUpdateHealthServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `setServing()`. @@ -344,8 +359,11 @@ internal class Grpc_Testing_XdsUpdateHealthServiceClientMock: Grpc_Testing_XdsUp /// class, allowing for mocking RPC calls. Behavior can be customized /// either through the properties on this class or by /// subclassing the class and overriding its methods. +/// +/// Note: This class does not handle thread-safe locking, but provides +/// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal class Grpc_Testing_XdsUpdateClientConfigureServiceClientMock: Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface, @unchecked Sendable { +internal final class Grpc_Testing_XdsUpdateClientConfigureServiceClientMock: Grpc_Testing_XdsUpdateClientConfigureServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `configure()`. From 18225707cad565ba6251adee34756f203c5506f2 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 12 Sep 2023 13:54:44 -0700 Subject: [PATCH 12/18] self review --- .../Implementation/Interceptors/InterceptorChain.swift | 5 +---- Libraries/Connect/Implementation/ProtocolClientConfig.swift | 4 ++-- .../Connect/Implementation/Streaming/URLSessionStream.swift | 4 ++-- Libraries/Connect/Interfaces/Interceptor.swift | 2 ++ Libraries/Connect/Interfaces/NetworkProtocol.swift | 2 +- .../ConnectConformance/CallbackConformance.swift | 6 ++++-- .../ConnectMocksTests/ConnectMocksTests.swift | 4 ++-- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift b/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift index c5aeaf5b..6e255e82 100644 --- a/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift +++ b/Libraries/Connect/Implementation/Interceptors/InterceptorChain.swift @@ -23,10 +23,7 @@ struct InterceptorChain: Sendable { /// /// - parameter interceptors: Closures that should be called to create interceptors. /// - parameter config: Config to use for setting up interceptors. - init( - interceptors: [@Sendable (ProtocolClientConfig) -> Interceptor], - config: ProtocolClientConfig - ) { + init(interceptors: [InterceptorInitializer], config: ProtocolClientConfig) { self.interceptors = interceptors.map { initialize in initialize(config) } } diff --git a/Libraries/Connect/Implementation/ProtocolClientConfig.swift b/Libraries/Connect/Implementation/ProtocolClientConfig.swift index 2dac24d6..16fe3403 100644 --- a/Libraries/Connect/Implementation/ProtocolClientConfig.swift +++ b/Libraries/Connect/Implementation/ProtocolClientConfig.swift @@ -28,7 +28,7 @@ public struct ProtocolClientConfig: Sendable { /// response headers like `content-encoding`. public let responseCompressionPools: [CompressionPool] /// List of interceptors that should be invoked with requests/responses. - public let interceptors: [@Sendable (ProtocolClientConfig) -> Interceptor] + public let interceptors: [InterceptorInitializer] /// Configuration used to specify if/how requests should be compressed. public struct RequestCompression: Sendable { @@ -53,7 +53,7 @@ public struct ProtocolClientConfig: Sendable { codec: Codec = JSONCodec(), requestCompression: RequestCompression? = nil, responseCompressionPools: [CompressionPool] = [GzipCompressionPool()], - interceptors: [@Sendable (ProtocolClientConfig) -> Interceptor] = [] + interceptors: [InterceptorInitializer] = [] ) { self.host = host self.networkProtocol = networkProtocol diff --git a/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift b/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift index acaa4548..0fa0065c 100644 --- a/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift +++ b/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift @@ -17,11 +17,11 @@ import Foundation /// Stream implementation that wraps a `URLSession` stream. final class URLSessionStream: NSObject, @unchecked Sendable { private let closedByServer = Locked(false) - /// Foundation.InputStream does not conform to Sendable, hence @unchecked on the above class. + /// Foundation.InputStream does not conform to Sendable, hence @unchecked on the class. private let readStream: Foundation.InputStream private let responseCallbacks: ResponseCallbacks private let task: URLSessionUploadTask - /// Foundation.OutputStream does not conform to Sendable, hence @unchecked on the above class. + /// Foundation.OutputStream does not conform to Sendable, hence @unchecked on the class. private let writeStream: Foundation.OutputStream enum Error: Swift.Error { diff --git a/Libraries/Connect/Interfaces/Interceptor.swift b/Libraries/Connect/Interfaces/Interceptor.swift index acd635af..a1d12eb9 100644 --- a/Libraries/Connect/Interfaces/Interceptor.swift +++ b/Libraries/Connect/Interfaces/Interceptor.swift @@ -37,6 +37,8 @@ public protocol Interceptor: Sendable { func streamFunction() -> StreamFunction } +public typealias InterceptorInitializer = @Sendable (ProtocolClientConfig) -> Interceptor + public struct UnaryFunction: Sendable { public let requestFunction: @Sendable (HTTPRequest) -> HTTPRequest public let responseFunction: @Sendable (HTTPResponse) -> HTTPResponse diff --git a/Libraries/Connect/Interfaces/NetworkProtocol.swift b/Libraries/Connect/Interfaces/NetworkProtocol.swift index 2e5f87bd..6863c2f4 100644 --- a/Libraries/Connect/Interfaces/NetworkProtocol.swift +++ b/Libraries/Connect/Interfaces/NetworkProtocol.swift @@ -21,7 +21,7 @@ public enum NetworkProtocol: Sendable { /// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md case grpcWeb /// A custom protocol that is implemented via an interceptor. - case custom(name: String, protocolInterceptor: @Sendable (ProtocolClientConfig) -> Interceptor) + case custom(name: String, protocolInterceptor: InterceptorInitializer) } extension NetworkProtocol: CustomStringConvertible { diff --git a/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift b/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift index a435d240..7064b9b8 100644 --- a/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift +++ b/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift @@ -93,8 +93,10 @@ final class CallbackConformance: XCTestCase { break case .message(let output): - XCTAssertEqual(output.payload.body.count, sizes[responseCount.value]) - responseCount.perform { $0 += 1 } + responseCount.perform { responseCount in + XCTAssertEqual(output.payload.body.count, sizes[responseCount]) + responseCount += 1 + } case .complete(let code, let error, _): XCTAssertEqual(code, .ok) diff --git a/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift b/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift index 5db685ac..9b834f44 100644 --- a/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift +++ b/Tests/ConnectLibraryTests/ConnectMocksTests/ConnectMocksTests.swift @@ -69,7 +69,7 @@ final class ConnectMocksTests: XCTestCase { client.mockFullDuplexCall.onClose = { closeCalled = true } client.mockFullDuplexCall.outputs = Array(expectedResults) - let receivedResults = Locked<[StreamResult]>([]) + let receivedResults = Locked([StreamResult]()) let stream = client.fullDuplexCall { result in receivedResults.perform { $0.append(result) } } @@ -136,7 +136,7 @@ final class ConnectMocksTests: XCTestCase { client.mockUnimplementedStreamingOutputCall.onSend = { sentInputs.append($0) } client.mockUnimplementedStreamingOutputCall.outputs = Array(expectedResults) - let receivedResults = Locked<[StreamResult]>([]) + let receivedResults = Locked([StreamResult]()) let stream = client.unimplementedStreamingOutputCall { result in receivedResults.perform { $0.append(result) } } From ba97c4907c337bb0fe7dd1b030c1f7f15a14bbf8 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 12 Sep 2023 14:04:52 -0700 Subject: [PATCH 13/18] fix after pulling upstream --- .../ConnectConformance/CallbackConformance.swift | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift b/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift index ed6cca79..6dc430a9 100644 --- a/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift +++ b/Tests/ConnectLibraryTests/ConnectConformance/CallbackConformance.swift @@ -435,7 +435,7 @@ final class CallbackConformance: XCTestCase { proto.domain = "connect-crosstest" } let expectation = self.expectation(description: "Stream completes") - var responseCount = 0 + let responseCount = Locked(0) let sizes = [31_415, 9, 2_653, 58_979] let stream = client.failStreamingOutputCall { result in switch result { @@ -443,8 +443,10 @@ final class CallbackConformance: XCTestCase { break case .message(let output): - XCTAssertEqual(output.payload.body.count, sizes[responseCount]) - responseCount += 1 + responseCount.perform { responseCount in + XCTAssertEqual(output.payload.body.count, sizes[responseCount]) + responseCount += 1 + } case .complete(_, let error, _): guard let connectError = error as? ConnectError else { @@ -468,7 +470,7 @@ final class CallbackConformance: XCTestCase { }) XCTAssertEqual(XCTWaiter().wait(for: [expectation], timeout: kTimeout), .completed) - XCTAssertEqual(responseCount, 4) + XCTAssertEqual(responseCount.value, 4) } } @@ -480,9 +482,9 @@ final class CallbackConformance: XCTestCase { let cancelable = client.emptyCall( request: SwiftProtobuf.Google_Protobuf_Empty() ) { response in - XCTAssertEqual(response.code, .canceled) - XCTAssertEqual(response.error?.code, .canceled) - expectation.fulfill() + XCTAssertEqual(response.code, .canceled) + XCTAssertEqual(response.error?.code, .canceled) + expectation.fulfill() } cancelable.cancel() XCTAssertEqual(XCTWaiter().wait(for: [expectation], timeout: kTimeout), .completed) From da246b05be66728c476d55ccaa558c67637cdf71 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Tue, 12 Sep 2023 16:20:20 -0700 Subject: [PATCH 14/18] update docstring generation --- .../ConnectMockGenerator.swift | 5 ++-- .../connectrpc/conformance/v1/test.mock.swift | 30 ++++++++----------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift index f5a23a30..79f9335e 100644 --- a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift +++ b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift @@ -43,9 +43,8 @@ final class ConnectMockGenerator: Generator { self.printLine("/// Mock implementation of `\(protocolName)`.") self.printLine("///") self.printLine("/// Production implementations can be substituted with instances of this") - self.printLine("/// class, allowing for mocking RPC calls. Behavior can be customized") - self.printLine("/// either through the properties on this class or by") - self.printLine("/// subclassing the class and overriding its methods.") + self.printLine("/// class to allow for mocking RPC calls, and behavior can be customized") + self.printLine("/// using its properties.") self.printLine("///") self.printLine("/// Note: This class does not handle thread-safe locking, but provides") self.printLine("/// `@unchecked Sendable` conformance to simplify testing and mocking.") diff --git a/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift b/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift index cf140764..b0c9ac72 100644 --- a/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift +++ b/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift @@ -12,9 +12,8 @@ import SwiftProtobuf /// Mock implementation of `Connectrpc_Conformance_V1_TestServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class, allowing for mocking RPC calls. Behavior can be customized -/// either through the properties on this class or by -/// subclassing the class and overriding its methods. +/// class to allow for mocking RPC calls, and behavior can be customized +/// using its properties. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -177,9 +176,8 @@ internal final class Connectrpc_Conformance_V1_TestServiceClientMock: Connectrpc /// Mock implementation of `Connectrpc_Conformance_V1_UnimplementedServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class, allowing for mocking RPC calls. Behavior can be customized -/// either through the properties on this class or by -/// subclassing the class and overriding its methods. +/// class to allow for mocking RPC calls, and behavior can be customized +/// using its properties. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -221,9 +219,8 @@ internal final class Connectrpc_Conformance_V1_UnimplementedServiceClientMock: C /// Mock implementation of `Connectrpc_Conformance_V1_ReconnectServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class, allowing for mocking RPC calls. Behavior can be customized -/// either through the properties on this class or by -/// subclassing the class and overriding its methods. +/// class to allow for mocking RPC calls, and behavior can be customized +/// using its properties. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -266,9 +263,8 @@ internal final class Connectrpc_Conformance_V1_ReconnectServiceClientMock: Conne /// Mock implementation of `Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class, allowing for mocking RPC calls. Behavior can be customized -/// either through the properties on this class or by -/// subclassing the class and overriding its methods. +/// class to allow for mocking RPC calls, and behavior can be customized +/// using its properties. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -311,9 +307,8 @@ internal final class Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientMoc /// Mock implementation of `Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class, allowing for mocking RPC calls. Behavior can be customized -/// either through the properties on this class or by -/// subclassing the class and overriding its methods. +/// class to allow for mocking RPC calls, and behavior can be customized +/// using its properties. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -356,9 +351,8 @@ internal final class Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientMock: /// Mock implementation of `Connectrpc_Conformance_V1_XdsUpdateClientConfigureServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class, allowing for mocking RPC calls. Behavior can be customized -/// either through the properties on this class or by -/// subclassing the class and overriding its methods. +/// class to allow for mocking RPC calls, and behavior can be customized +/// using its properties. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. From c0ba6db95a5335adf64be967f84bca6d77a20af5 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Wed, 13 Sep 2023 10:07:13 -0700 Subject: [PATCH 15/18] code review --- Libraries/Connect/Implementation/Codecs/JSONCodec.swift | 2 +- .../Connect/Implementation/Streaming/URLSessionStream.swift | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Libraries/Connect/Implementation/Codecs/JSONCodec.swift b/Libraries/Connect/Implementation/Codecs/JSONCodec.swift index 29c7c69e..ae7882f2 100644 --- a/Libraries/Connect/Implementation/Codecs/JSONCodec.swift +++ b/Libraries/Connect/Implementation/Codecs/JSONCodec.swift @@ -13,7 +13,7 @@ // limitations under the License. import Foundation -// TODO: Remove @preconcurrency once SwiftProtobuf's JSON(Encoding|Decoding)Options are Sendable +// TODO: Remove `@preconcurrency` once `SwiftProtobuf.JSON{Encoding|Decoding}Options` are `Sendable` @preconcurrency import SwiftProtobuf /// Codec providing functionality for serializing to/from JSON. diff --git a/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift b/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift index 0fa0065c..23e1658b 100644 --- a/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift +++ b/Libraries/Connect/Implementation/Streaming/URLSessionStream.swift @@ -15,13 +15,14 @@ import Foundation /// Stream implementation that wraps a `URLSession` stream. +/// +/// Note: This class is `@unchecked Sendable` because the `Foundation.{Input|Output}Stream` +/// types do not conform to `Sendable`. final class URLSessionStream: NSObject, @unchecked Sendable { private let closedByServer = Locked(false) - /// Foundation.InputStream does not conform to Sendable, hence @unchecked on the class. private let readStream: Foundation.InputStream private let responseCallbacks: ResponseCallbacks private let task: URLSessionUploadTask - /// Foundation.OutputStream does not conform to Sendable, hence @unchecked on the class. private let writeStream: Foundation.OutputStream enum Error: Swift.Error { From 13f764b20cc73a47914b553ae65e91a8e083f746 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Wed, 13 Sep 2023 10:23:26 -0700 Subject: [PATCH 16/18] add docstring + make mocks `open` again --- .../Implementation/URLSessionHTTPClient.swift | 4 ++++ .../ConnectMockGenerator.swift | 23 ++++++++++++++----- .../ConnectPluginUtilities/Generator.swift | 7 ------ .../ConnectClientGenerator.swift | 8 +++++++ .../connectrpc/conformance/v1/test.mock.swift | 12 +++++----- 5 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Libraries/Connect/Implementation/URLSessionHTTPClient.swift b/Libraries/Connect/Implementation/URLSessionHTTPClient.swift index 926f99ad..1137496b 100644 --- a/Libraries/Connect/Implementation/URLSessionHTTPClient.swift +++ b/Libraries/Connect/Implementation/URLSessionHTTPClient.swift @@ -17,6 +17,10 @@ import Foundation import os.log /// Concrete implementation of `HTTPClientInterface` backed by `URLSession`. +/// +/// This class is thread-safe as-is through the use of an internal lock. It is marked as +/// `open` and `@unchecked Sendable` so that consumers can subclass it if necessary, but +/// subclasses must handle their own thread safety for added functionality. open class URLSessionHTTPClient: NSObject, HTTPClientInterface, @unchecked Sendable { /// Lock used for safely accessing stream storage. private let lock = Lock() diff --git a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift index 79f9335e..3c4829fe 100644 --- a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift +++ b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift @@ -18,7 +18,18 @@ import SwiftProtobufPluginLibrary /// Responsible for generating services and RPCs that are compatible with the Connect library. final class ConnectMockGenerator: Generator { + private let propertyVisibility: String + private let typeVisibility: String + required init(_ descriptor: FileDescriptor, options: GeneratorOptions) { + switch options.visibility { + case .internal: + self.propertyVisibility = "internal" + self.typeVisibility = "internal" + case .public: + self.propertyVisibility = "public" + self.typeVisibility = "open" + } super.init(descriptor, options: options) self.printContent() } @@ -51,7 +62,7 @@ final class ConnectMockGenerator: Generator { self.printLine("@available(iOS 13, *)") self.printLine( """ - \(self.visibility) final class \(service.mockName(using: self.namer)): \ + \(self.typeVisibility) class \(service.mockName(using: self.namer)): \ \(protocolName), @unchecked Sendable { """ ) @@ -68,7 +79,7 @@ final class ConnectMockGenerator: Generator { ) self.printLine( """ - \(self.visibility) var \(method.callbackMockPropertyName()) = \ + \(self.propertyVisibility) var \(method.callbackMockPropertyName()) = \ \(method.callbackMockPropertyValue(using: self.namer)) """ ) @@ -79,7 +90,7 @@ final class ConnectMockGenerator: Generator { ) self.printLine( """ - \(self.visibility) var \(method.asyncAwaitMockPropertyName()) = \ + \(self.propertyVisibility) var \(method.asyncAwaitMockPropertyName()) = \ \(method.asyncAwaitMockPropertyValue(using: self.namer)) """ ) @@ -87,7 +98,7 @@ final class ConnectMockGenerator: Generator { } self.printLine() - self.printLine("\(self.visibility) init() {}") + self.printLine("\(self.propertyVisibility) init() {}") for method in service.methods { if self.options.generateCallbackMethods { @@ -109,7 +120,7 @@ final class ConnectMockGenerator: Generator { } self.printLine( - "\(self.visibility) " + "\(self.typeVisibility) " + method.callbackSignature( using: self.namer, includeDefaults: true, options: self.options ) @@ -139,7 +150,7 @@ final class ConnectMockGenerator: Generator { self.printLine() self.printLine( - "\(self.visibility) " + "\(self.typeVisibility) " + method.asyncAwaitSignature( using: self.namer, includeDefaults: true, options: self.options ) diff --git a/Plugins/ConnectPluginUtilities/Generator.swift b/Plugins/ConnectPluginUtilities/Generator.swift index 11c4cd6f..8b2ac23d 100644 --- a/Plugins/ConnectPluginUtilities/Generator.swift +++ b/Plugins/ConnectPluginUtilities/Generator.swift @@ -21,7 +21,6 @@ open class Generator { public let descriptor: FileDescriptor public let namer: SwiftProtobufNamer public let options: GeneratorOptions - public let visibility: String public var output: String { return self.printer.content @@ -34,12 +33,6 @@ open class Generator { currentFile: descriptor, protoFileToModuleMappings: options.protoToModuleMappings ) - switch options.visibility { - case .internal: - self.visibility = "internal" - case .public: - self.visibility = "public" - } } // MARK: - Output helpers diff --git a/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift b/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift index 1fc1df83..cf8afb88 100644 --- a/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift +++ b/Plugins/ConnectSwiftPlugin/ConnectClientGenerator.swift @@ -18,7 +18,15 @@ import SwiftProtobufPluginLibrary /// Responsible for generating services and RPCs that are compatible with the Connect library. final class ConnectClientGenerator: Generator { + private let visibility: String + required init(_ descriptor: FileDescriptor, options: GeneratorOptions) { + switch options.visibility { + case .internal: + self.visibility = "internal" + case .public: + self.visibility = "public" + } super.init(descriptor, options: options) self.printContent() } diff --git a/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift b/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift index b0c9ac72..49944121 100644 --- a/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift +++ b/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift @@ -18,7 +18,7 @@ import SwiftProtobuf /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal final class Connectrpc_Conformance_V1_TestServiceClientMock: Connectrpc_Conformance_V1_TestServiceClientInterface, @unchecked Sendable { +internal class Connectrpc_Conformance_V1_TestServiceClientMock: Connectrpc_Conformance_V1_TestServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `emptyCall()`. @@ -182,7 +182,7 @@ internal final class Connectrpc_Conformance_V1_TestServiceClientMock: Connectrpc /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal final class Connectrpc_Conformance_V1_UnimplementedServiceClientMock: Connectrpc_Conformance_V1_UnimplementedServiceClientInterface, @unchecked Sendable { +internal class Connectrpc_Conformance_V1_UnimplementedServiceClientMock: Connectrpc_Conformance_V1_UnimplementedServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `unimplementedCall()`. @@ -225,7 +225,7 @@ internal final class Connectrpc_Conformance_V1_UnimplementedServiceClientMock: C /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal final class Connectrpc_Conformance_V1_ReconnectServiceClientMock: Connectrpc_Conformance_V1_ReconnectServiceClientInterface, @unchecked Sendable { +internal class Connectrpc_Conformance_V1_ReconnectServiceClientMock: Connectrpc_Conformance_V1_ReconnectServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `start()`. @@ -269,7 +269,7 @@ internal final class Connectrpc_Conformance_V1_ReconnectServiceClientMock: Conne /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal final class Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientMock: Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientInterface, @unchecked Sendable { +internal class Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientMock: Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `getClientStats()`. @@ -313,7 +313,7 @@ internal final class Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientMoc /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal final class Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientMock: Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientInterface, @unchecked Sendable { +internal class Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientMock: Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `setServing()`. @@ -357,7 +357,7 @@ internal final class Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientMock: /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @available(iOS 13, *) -internal final class Connectrpc_Conformance_V1_XdsUpdateClientConfigureServiceClientMock: Connectrpc_Conformance_V1_XdsUpdateClientConfigureServiceClientInterface, @unchecked Sendable { +internal class Connectrpc_Conformance_V1_XdsUpdateClientConfigureServiceClientMock: Connectrpc_Conformance_V1_XdsUpdateClientConfigureServiceClientInterface, @unchecked Sendable { private var cancellables = [Combine.AnyCancellable]() /// Mocked for calls to `configure()`. From 23da20c581eca4724eb3809d10d5f2ddc57adb9f Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Wed, 13 Sep 2023 10:30:50 -0700 Subject: [PATCH 17/18] update mocks --- .../ConnectMockGenerator.swift | 5 ++-- README.md | 4 +-- .../connectrpc/conformance/v1/test.mock.swift | 30 +++++++++++-------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift index 3c4829fe..3e791043 100644 --- a/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift +++ b/Plugins/ConnectMocksPlugin/ConnectMockGenerator.swift @@ -54,8 +54,9 @@ final class ConnectMockGenerator: Generator { self.printLine("/// Mock implementation of `\(protocolName)`.") self.printLine("///") self.printLine("/// Production implementations can be substituted with instances of this") - self.printLine("/// class to allow for mocking RPC calls, and behavior can be customized") - self.printLine("/// using its properties.") + self.printLine("/// class to mock RPC calls. Behavior can be customized") + self.printLine("/// either through the properties on this class or by") + self.printLine("/// subclassing the mock and overriding its methods.") self.printLine("///") self.printLine("/// Note: This class does not handle thread-safe locking, but provides") self.printLine("/// `@unchecked Sendable` conformance to simplify testing and mocking.") diff --git a/README.md b/README.md index c5f31c95..10ebe53c 100644 --- a/README.md +++ b/README.md @@ -85,10 +85,10 @@ protocol interfaces as the production clients:
Click to expand eliza.mock.swift ```swift -public final class Eliza_V1_ChatServiceClientMock: Eliza_V1_ChatServiceClientInterface, @unchecked Sendable { +open class Eliza_V1_ChatServiceClientMock: Eliza_V1_ChatServiceClientInterface, @unchecked Sendable { public var mockAsyncSay = { (_: Eliza_V1_SayRequest) -> ResponseMessage in .init(message: .init()) } - public func say(request: Eliza_V1_SayRequest, headers: Headers = [:]) + open func say(request: Eliza_V1_SayRequest, headers: Headers = [:]) async -> ResponseMessage { return self.mockAsyncSay(request) diff --git a/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift b/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift index 49944121..d9152833 100644 --- a/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift +++ b/Tests/ConnectLibraryTests/Generated/connectrpc/conformance/v1/test.mock.swift @@ -12,8 +12,9 @@ import SwiftProtobuf /// Mock implementation of `Connectrpc_Conformance_V1_TestServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class to allow for mocking RPC calls, and behavior can be customized -/// using its properties. +/// class to mock RPC calls. Behavior can be customized +/// either through the properties on this class or by +/// subclassing the mock and overriding its methods. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -176,8 +177,9 @@ internal class Connectrpc_Conformance_V1_TestServiceClientMock: Connectrpc_Confo /// Mock implementation of `Connectrpc_Conformance_V1_UnimplementedServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class to allow for mocking RPC calls, and behavior can be customized -/// using its properties. +/// class to mock RPC calls. Behavior can be customized +/// either through the properties on this class or by +/// subclassing the mock and overriding its methods. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -219,8 +221,9 @@ internal class Connectrpc_Conformance_V1_UnimplementedServiceClientMock: Connect /// Mock implementation of `Connectrpc_Conformance_V1_ReconnectServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class to allow for mocking RPC calls, and behavior can be customized -/// using its properties. +/// class to mock RPC calls. Behavior can be customized +/// either through the properties on this class or by +/// subclassing the mock and overriding its methods. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -263,8 +266,9 @@ internal class Connectrpc_Conformance_V1_ReconnectServiceClientMock: Connectrpc_ /// Mock implementation of `Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class to allow for mocking RPC calls, and behavior can be customized -/// using its properties. +/// class to mock RPC calls. Behavior can be customized +/// either through the properties on this class or by +/// subclassing the mock and overriding its methods. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -307,8 +311,9 @@ internal class Connectrpc_Conformance_V1_LoadBalancerStatsServiceClientMock: Con /// Mock implementation of `Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class to allow for mocking RPC calls, and behavior can be customized -/// using its properties. +/// class to mock RPC calls. Behavior can be customized +/// either through the properties on this class or by +/// subclassing the mock and overriding its methods. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. @@ -351,8 +356,9 @@ internal class Connectrpc_Conformance_V1_XdsUpdateHealthServiceClientMock: Conne /// Mock implementation of `Connectrpc_Conformance_V1_XdsUpdateClientConfigureServiceClientInterface`. /// /// Production implementations can be substituted with instances of this -/// class to allow for mocking RPC calls, and behavior can be customized -/// using its properties. +/// class to mock RPC calls. Behavior can be customized +/// either through the properties on this class or by +/// subclassing the mock and overriding its methods. /// /// Note: This class does not handle thread-safe locking, but provides /// `@unchecked Sendable` conformance to simplify testing and mocking. From abcae99ecf8ccbb375797a5e96f2f18d17b31a35 Mon Sep 17 00:00:00 2001 From: Michael Rebello Date: Wed, 13 Sep 2023 10:46:56 -0700 Subject: [PATCH 18/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10ebe53c..5174249a 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ func testMessagingViewModel() async { let client = Eliza_V1_ChatServiceClientMock() client.mockAsyncSay = { request in XCTAssertEqual(request.sentence, "hello!") - return ResponseMessage(message: .with { $0.sentence = "hi, i'm eliza!" }) + return ResponseMessage(result: .success(.with { $0.sentence = "hi, i'm eliza!" })) } let viewModel = MessagingViewModel(elizaClient: client)