diff --git a/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift index 29285c243..1d935151f 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ClientCodeTranslator.swift @@ -25,19 +25,19 @@ /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) /// public protocol Foo_BarClientProtocol: Sendable { /// func baz( -/// request: GRPCCore.ClientRequest.Single, +/// request: GRPCCore.ClientRequest, /// serializer: some GRPCCore.MessageSerializer, /// deserializer: some GRPCCore.MessageDeserializer, /// options: GRPCCore.CallOptions = .defaults, -/// _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R +/// _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R /// ) async throws -> R where R: Sendable /// } /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) /// extension Foo_Bar.ClientProtocol { /// public func baz( -/// request: GRPCCore.ClientRequest.Single, +/// request: GRPCCore.ClientRequest, /// options: GRPCCore.CallOptions = .defaults, -/// _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { +/// _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { /// try $0.message /// } /// ) async throws -> R where R: Sendable { @@ -56,11 +56,11 @@ /// self.client = client /// } /// public func methodA( -/// request: GRPCCore.ClientRequest.Stream, +/// request: GRPCCore.StreamingClientRequest, /// serializer: some GRPCCore.MessageSerializer, /// deserializer: some GRPCCore.MessageDeserializer, /// options: GRPCCore.CallOptions = .defaults, -/// _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { +/// _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { /// try $0.message /// } /// ) async throws -> R where R: Sendable { @@ -263,13 +263,13 @@ extension ClientCodeTranslator { // All methods have a response handler. var responseHandler = ParameterDescription(label: "onResponse", name: "handleResponse") - let responseKind = method.isOutputStreaming ? "Stream" : "Single" + let responseKind = method.isOutputStreaming ? "Streaming" : "" responseHandler.type = .closure( ClosureSignatureDescription( parameters: [ ParameterDescription( type: .generic( - wrapper: .member(["GRPCCore", "ClientResponse", responseKind]), + wrapper: .member(["GRPCCore", "\(responseKind)ClientResponse"]), wrapped: .member(method.outputType) ) ) @@ -299,21 +299,21 @@ extension ClientCodeTranslator { ) -> [CodeBlock] { // Produces the following: // - // let request = GRPCCore.ClientRequest.Single(message: message, metadata: metadata) + // let request = GRPCCore.ClientRequest(message: message, metadata: metadata) // return try await method(request: request, options: options, responseHandler: responseHandler) // // or: // - // let request = GRPCCore.ClientRequest.Stream(metadata: metadata, producer: writer) + // let request = GRPCCore.StreamingClientRequest(metadata: metadata, producer: writer) // return try await method(request: request, options: options, responseHandler: responseHandler) // First, make the init for the ClientRequest - let requestType = method.isInputStreaming ? "Stream" : "Single" + let requestType = method.isInputStreaming ? "Streaming" : "" var requestInit = FunctionCallDescription( calledExpression: .identifier( .type( .generic( - wrapper: .member(["GRPCCore", "ClientRequest", requestType]), + wrapper: .member(["GRPCCore", "\(requestType)ClientRequest"]), wrapped: .member(method.inputType) ) ) @@ -490,9 +490,10 @@ extension ClientCodeTranslator { for method: CodeGenerationRequest.ServiceDescriptor.MethodDescriptor, in service: CodeGenerationRequest.ServiceDescriptor ) -> ParameterDescription { - let requestType = method.isInputStreaming ? "Stream" : "Single" + let requestType = method.isInputStreaming ? "Streaming" : "" let clientRequestType = ExistingTypeDescription.member([ - "GRPCCore", "ClientRequest", requestType, + "GRPCCore", + "\(requestType)ClientRequest", ]) return ParameterDescription( label: "request", @@ -538,9 +539,9 @@ extension ClientCodeTranslator { in service: CodeGenerationRequest.ServiceDescriptor, includeDefaultResponseHandler: Bool ) -> ParameterDescription { - let clientStreaming = method.isOutputStreaming ? "Stream" : "Single" + let clientStreaming = method.isOutputStreaming ? "Streaming" : "" let closureParameterType = ExistingTypeDescription.generic( - wrapper: .member(["GRPCCore", "ClientResponse", clientStreaming]), + wrapper: .member(["GRPCCore", "\(clientStreaming)ClientResponse"]), wrapped: .member(method.outputType) ) diff --git a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift index d392bf5b0..100233d11 100644 --- a/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift +++ b/Sources/GRPCCodeGen/Internal/Translator/ServerCodeTranslator.swift @@ -25,8 +25,8 @@ /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) /// public protocol Foo_BarStreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// func baz( -/// request: GRPCCore.ServerRequest.Stream -/// ) async throws -> GRPCCore.ServerResponse.Stream +/// request: GRPCCore.StreamingServerRequest +/// ) async throws -> GRPCCore.StreamingServerResponse /// } /// // Conformance to `GRPCCore.RegistrableRPCService`. /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) @@ -43,17 +43,17 @@ /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) /// public protocol Foo_BarServiceProtocol: Foo_Bar.StreamingServiceProtocol { /// func baz( -/// request: GRPCCore.ServerRequest.Single -/// ) async throws -> GRPCCore.ServerResponse.Single +/// request: GRPCCore.ServerRequest +/// ) async throws -> GRPCCore.ServerResponse /// } /// // Partial conformance to `Foo_BarStreamingServiceProtocol`. /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) /// extension Foo_Bar.ServiceProtocol { /// public func baz( -/// request: GRPCCore.ServerRequest.Stream -/// ) async throws -> GRPCCore.ServerResponse.Stream { -/// let response = try await self.baz(request: GRPCCore.ServerRequest.Single(stream: request)) -/// return GRPCCore.ServerResponse.Stream(single: response) +/// request: GRPCCore.StreamingServerRequest +/// ) async throws -> GRPCCore.StreamingServerResponse { +/// let response = try await self.baz(request: GRPCCore.ServerRequest(stream: request)) +/// return GRPCCore.StreamingServerResponse(single: response) /// } /// } ///``` @@ -147,7 +147,7 @@ extension ServerCodeTranslator { .init( label: "request", type: .generic( - wrapper: .member(["GRPCCore", "ServerRequest", "Stream"]), + wrapper: .member(["GRPCCore", "StreamingServerRequest"]), wrapped: .member(method.inputType) ) ), @@ -156,7 +156,7 @@ extension ServerCodeTranslator { keywords: [.async, .throws], returnType: .identifierType( .generic( - wrapper: .member(["GRPCCore", "ServerResponse", "Stream"]), + wrapper: .member(["GRPCCore", "StreamingServerResponse"]), wrapped: .member(method.outputType) ) ) @@ -313,8 +313,8 @@ extension ServerCodeTranslator { in service: CodeGenerationRequest.ServiceDescriptor, accessModifier: AccessModifier? = nil ) -> Declaration { - let inputStreaming = method.isInputStreaming ? "Stream" : "Single" - let outputStreaming = method.isOutputStreaming ? "Stream" : "Single" + let inputStreaming = method.isInputStreaming ? "Streaming" : "" + let outputStreaming = method.isOutputStreaming ? "Streaming" : "" let functionSignature = FunctionSignatureDescription( accessModifier: accessModifier, @@ -324,7 +324,7 @@ extension ServerCodeTranslator { label: "request", type: .generic( - wrapper: .member(["GRPCCore", "ServerRequest", inputStreaming]), + wrapper: .member(["GRPCCore", "\(inputStreaming)ServerRequest"]), wrapped: .member(method.inputType) ) ), @@ -333,7 +333,7 @@ extension ServerCodeTranslator { keywords: [.async, .throws], returnType: .identifierType( .generic( - wrapper: .member(["GRPCCore", "ServerResponse", outputStreaming]), + wrapper: .member(["GRPCCore", "\(outputStreaming)ServerResponse"]), wrapped: .member(method.outputType) ) ) @@ -391,12 +391,7 @@ extension ServerCodeTranslator { if !method.isInputStreaming { // Transform the streaming request into a unary request. serverRequest = Expression.functionCall( - calledExpression: .memberAccess( - MemberAccessDescription( - left: .identifierPattern("GRPCCore.ServerRequest"), - right: "Single" - ) - ), + calledExpression: .identifierType(.member(["GRPCCore", "ServerRequest"])), arguments: [ FunctionArgumentDescription(label: "stream", expression: .identifierPattern("request")) ] @@ -433,12 +428,7 @@ extension ServerCodeTranslator { // Transforming the unary response into a streaming one. if !method.isOutputStreaming { returnValue = .functionCall( - calledExpression: .memberAccess( - MemberAccessDescription( - left: .identifierType(.member(["GRPCCore", "ServerResponse"])), - right: "Stream" - ) - ), + calledExpression: .identifier(.type(.member(["GRPCCore", "StreamingServerResponse"]))), arguments: [ (FunctionArgumentDescription(label: "single", expression: .identifierPattern("response"))) ] diff --git a/Sources/GRPCCore/Call/Client/ClientInterceptor.swift b/Sources/GRPCCore/Call/Client/ClientInterceptor.swift index 93ddf9cf5..2a81a0ddc 100644 --- a/Sources/GRPCCore/Call/Client/ClientInterceptor.swift +++ b/Sources/GRPCCore/Call/Client/ClientInterceptor.swift @@ -40,13 +40,13 @@ /// let fetchMetadata: @Sendable () async -> String /// /// func intercept( -/// request: ClientRequest.Stream, +/// request: StreamingClientRequest, /// context: ClientContext, /// next: @Sendable ( -/// _ request: ClientRequest.Stream, +/// _ request: StreamingClientRequest, /// _ context: ClientContext -/// ) async throws -> ClientResponse.Stream -/// ) async throws -> ClientResponse.Stream { +/// ) async throws -> StreamingClientResponse +/// ) async throws -> StreamingClientResponse { /// // Fetch the metadata value and attach it. /// let value = await self.fetchMetadata() /// var request = request @@ -65,13 +65,13 @@ /// ```swift /// struct LoggingClientInterceptor: ClientInterceptor { /// func intercept( -/// request: ClientRequest.Stream, +/// request: StreamingClientRequest, /// context: ClientContext, /// next: @Sendable ( -/// _ request: ClientRequest.Stream, +/// _ request: StreamingClientRequest, /// _ context: ClientContext -/// ) async throws -> ClientResponse.Stream -/// ) async throws -> ClientResponse.Stream { +/// ) async throws -> StreamingClientResponse +/// ) async throws -> StreamingClientResponse { /// print("Invoking method '\(context.descriptor)'") /// let response = try await next(request, context) /// @@ -100,11 +100,11 @@ public protocol ClientInterceptor: Sendable { /// interceptor in the chain. /// - Returns: A response object. func intercept( - request: ClientRequest.Stream, + request: StreamingClientRequest, context: ClientContext, next: ( - _ request: ClientRequest.Stream, + _ request: StreamingClientRequest, _ context: ClientContext - ) async throws -> ClientResponse.Stream - ) async throws -> ClientResponse.Stream + ) async throws -> StreamingClientResponse + ) async throws -> StreamingClientResponse } diff --git a/Sources/GRPCCore/Call/Client/ClientRequest.swift b/Sources/GRPCCore/Call/Client/ClientRequest.swift index 17e5e1077..fbbf686e6 100644 --- a/Sources/GRPCCore/Call/Client/ClientRequest.swift +++ b/Sources/GRPCCore/Call/Client/ClientRequest.swift @@ -14,91 +14,84 @@ * limitations under the License. */ -/// A namespace for request message types used by clients. -public enum ClientRequest {} - -extension ClientRequest { - /// A request created by the client for a single message. - /// - /// This is used for unary and server-streaming RPCs. - /// - /// See ``ClientRequest/Stream`` for streaming requests and ``ServerRequest/Single`` for the - /// servers representation of a single-message request. - /// - /// ## Creating ``Single`` requests +/// A request created by the client for a single message. +/// +/// This is used for unary and server-streaming RPCs. +/// +/// See ``StreamingClientRequest`` for streaming requests and ``ServerRequest`` for the +/// servers representation of a single-message request. +/// +/// ## Creating ``Single`` requests +/// +/// ```swift +/// let request = ClientRequest(message: "Hello, gRPC!") +/// print(request.metadata) // prints '[:]' +/// print(request.message) // prints 'Hello, gRPC!' +/// ``` +public struct ClientRequest: Sendable { + /// Caller-specified metadata to send to the server at the start of the RPC. /// - /// ```swift - /// let request = ClientRequest.Single(message: "Hello, gRPC!") - /// print(request.metadata) // prints '[:]' - /// print(request.message) // prints 'Hello, gRPC!' - /// ``` - public struct Single: Sendable { - /// Caller-specified metadata to send to the server at the start of the RPC. - /// - /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with - /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert - /// their own metadata, you should avoid using key names which may clash with transport specific - /// metadata. Note that transports may also impose limits in the amount of metadata which may - /// be sent. - public var metadata: Metadata + /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with + /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert + /// their own metadata, you should avoid using key names which may clash with transport specific + /// metadata. Note that transports may also impose limits in the amount of metadata which may + /// be sent. + public var metadata: Metadata - /// The message to send to the server. - public var message: Message + /// The message to send to the server. + public var message: Message - /// Create a new single client request. - /// - /// - Parameters: - /// - message: The message to send to the server. - /// - metadata: Metadata to send to the server at the start of the request. Defaults to empty. - public init( - message: Message, - metadata: Metadata = [:] - ) { - self.metadata = metadata - self.message = message - } + /// Create a new single client request. + /// + /// - Parameters: + /// - message: The message to send to the server. + /// - metadata: Metadata to send to the server at the start of the request. Defaults to empty. + public init( + message: Message, + metadata: Metadata = [:] + ) { + self.metadata = metadata + self.message = message } } -extension ClientRequest { - /// A request created by the client for a stream of messages. - /// - /// This is used for client-streaming and bidirectional-streaming RPCs. +/// A request created by the client for a stream of messages. +/// +/// This is used for client-streaming and bidirectional-streaming RPCs. +/// +/// See ``ClientRequest`` for single-message requests and ``StreamingServerRequest`` for the +/// servers representation of a streaming-message request. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct StreamingClientRequest: Sendable { + /// Caller-specified metadata sent to the server at the start of the RPC. /// - /// See ``ClientRequest/Single`` for single-message requests and ``ServerRequest/Stream`` for the - /// servers representation of a streaming-message request. - @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) - public struct Stream: Sendable { - /// Caller-specified metadata sent to the server at the start of the RPC. - /// - /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with - /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert - /// their own metadata, you should avoid using key names which may clash with transport specific - /// metadata. Note that transports may also impose limits in the amount of metadata which may - /// be sent. - public var metadata: Metadata + /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with + /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert + /// their own metadata, you should avoid using key names which may clash with transport specific + /// metadata. Note that transports may also impose limits in the amount of metadata which may + /// be sent. + public var metadata: Metadata - /// A closure which, when called, writes messages in the writer. - /// - /// The producer will only be consumed once by gRPC and therefore isn't required to be - /// idempotent. If the producer throws an error then the RPC will be cancelled. Once the - /// producer returns the request stream is closed. - public var producer: @Sendable (RPCWriter) async throws -> Void + /// A closure which, when called, writes messages in the writer. + /// + /// The producer will only be consumed once by gRPC and therefore isn't required to be + /// idempotent. If the producer throws an error then the RPC will be cancelled. Once the + /// producer returns the request stream is closed. + public var producer: @Sendable (RPCWriter) async throws -> Void - /// Create a new streaming client request. - /// - /// - Parameters: - /// - messageType: The type of message contained in this request, defaults to `Message.self`. - /// - metadata: Metadata to send to the server at the start of the request. Defaults to empty. - /// - producer: A closure which writes messages to send to the server. The closure is called - /// at most once and may not be called. - public init( - of messageType: Message.Type = Message.self, - metadata: Metadata = [:], - producer: @escaping @Sendable (RPCWriter) async throws -> Void - ) { - self.metadata = metadata - self.producer = producer - } + /// Create a new streaming client request. + /// + /// - Parameters: + /// - messageType: The type of message contained in this request, defaults to `Message.self`. + /// - metadata: Metadata to send to the server at the start of the request. Defaults to empty. + /// - producer: A closure which writes messages to send to the server. The closure is called + /// at most once and may not be called. + public init( + of messageType: Message.Type = Message.self, + metadata: Metadata = [:], + producer: @escaping @Sendable (RPCWriter) async throws -> Void + ) { + self.metadata = metadata + self.producer = producer } } diff --git a/Sources/GRPCCore/Call/Client/ClientResponse.swift b/Sources/GRPCCore/Call/Client/ClientResponse.swift index a031933fd..dd2e71a38 100644 --- a/Sources/GRPCCore/Call/Client/ClientResponse.swift +++ b/Sources/GRPCCore/Call/Client/ClientResponse.swift @@ -14,255 +14,248 @@ * limitations under the License. */ -/// A namespace for response message types used by clients. -public enum ClientResponse {} - -extension ClientResponse { - /// A response for a single message received by a client. - /// - /// Single responses are used for unary and client-streaming RPCs. For streaming responses - /// see ``ClientResponse/Stream``. - /// - /// A single response captures every part of the response stream and distinguishes successful - /// and unsuccessful responses via the ``accepted`` property. The value for the `success` case - /// contains the initial metadata, response message, and the trailing metadata and implicitly - /// has an ``Status/Code-swift.struct/ok`` status code. - /// - /// The `failure` case indicates that the server chose not to process the RPC, or the processing - /// of the RPC failed, or the client failed to execute the request. The failure case contains - /// an ``RPCError`` describing why the RPC failed, including an error code, error message and any - /// metadata sent by the server. - /// - /// ### Using ``Single`` responses - /// - /// Each response has a ``accepted`` property which contains all RPC information. You can create - /// one by calling ``init(accepted:)`` or one of the two convenience initializers: - /// - ``init(message:metadata:trailingMetadata:)`` to create a successful response, or - /// - ``init(of:error:)`` to create a failed response. - /// - /// You can interrogate a response by inspecting the ``accepted`` property directly or by using - /// its convenience properties: - /// - ``metadata`` extracts the initial metadata, - /// - ``message`` extracts the message, or throws if the response failed, and - /// - ``trailingMetadata`` extracts the trailing metadata. - /// - /// The following example demonstrates how you can use the API: - /// - /// ```swift - /// // Create a successful response - /// let response = ClientResponse.Single( - /// message: "Hello, World!", - /// metadata: ["hello": "initial metadata"], - /// trailingMetadata: ["goodbye": "trailing metadata"] - /// ) - /// - /// // The explicit API: - /// switch response { - /// case .success(let contents): - /// print("Received response with message '\(try contents.message.get())'") - /// case .failure(let error): - /// print("RPC failed with code '\(error.code)'") - /// } - /// - /// // The convenience API: - /// do { - /// print("Received response with message '\(try response.message)'") - /// } catch let error as RPCError { - /// print("RPC failed with code '\(error.code)'") - /// } - /// ``` - public struct Single: Sendable { - /// The contents of an accepted response with a single message. - public struct Contents: Sendable { - /// Metadata received from the server at the beginning of the response. - /// - /// The metadata may contain transport-specific information in addition to any application - /// level metadata provided by the service. - public var metadata: Metadata - - /// The response message received from the server, or an error of the RPC failed with a - /// non-ok status. - public var message: Result - - /// Metadata received from the server at the end of the response. - /// - /// The metadata may contain transport-specific information in addition to any application - /// level metadata provided by the service. - public var trailingMetadata: Metadata +/// A response for a single message received by a client. +/// +/// Single responses are used for unary and client-streaming RPCs. For streaming responses +/// see ``StreamingClientResponse``. +/// +/// A single response captures every part of the response stream and distinguishes successful +/// and unsuccessful responses via the ``accepted`` property. The value for the `success` case +/// contains the initial metadata, response message, and the trailing metadata and implicitly +/// has an ``Status/Code-swift.struct/ok`` status code. +/// +/// The `failure` case indicates that the server chose not to process the RPC, or the processing +/// of the RPC failed, or the client failed to execute the request. The failure case contains +/// an ``RPCError`` describing why the RPC failed, including an error code, error message and any +/// metadata sent by the server. +/// +/// ### Using ``Single`` responses +/// +/// Each response has a ``accepted`` property which contains all RPC information. You can create +/// one by calling ``init(accepted:)`` or one of the two convenience initializers: +/// - ``init(message:metadata:trailingMetadata:)`` to create a successful response, or +/// - ``init(of:error:)`` to create a failed response. +/// +/// You can interrogate a response by inspecting the ``accepted`` property directly or by using +/// its convenience properties: +/// - ``metadata`` extracts the initial metadata, +/// - ``message`` extracts the message, or throws if the response failed, and +/// - ``trailingMetadata`` extracts the trailing metadata. +/// +/// The following example demonstrates how you can use the API: +/// +/// ```swift +/// // Create a successful response +/// let response = ClientResponse( +/// message: "Hello, World!", +/// metadata: ["hello": "initial metadata"], +/// trailingMetadata: ["goodbye": "trailing metadata"] +/// ) +/// +/// // The explicit API: +/// switch response { +/// case .success(let contents): +/// print("Received response with message '\(try contents.message.get())'") +/// case .failure(let error): +/// print("RPC failed with code '\(error.code)'") +/// } +/// +/// // The convenience API: +/// do { +/// print("Received response with message '\(try response.message)'") +/// } catch let error as RPCError { +/// print("RPC failed with code '\(error.code)'") +/// } +/// ``` +public struct ClientResponse: Sendable { + /// The contents of an accepted response with a single message. + public struct Contents: Sendable { + /// Metadata received from the server at the beginning of the response. + /// + /// The metadata may contain transport-specific information in addition to any application + /// level metadata provided by the service. + public var metadata: Metadata - /// Creates a `Contents`. - /// - /// - Parameters: - /// - metadata: Metadata received from the server at the beginning of the response. - /// - message: The response message received from the server. - /// - trailingMetadata: Metadata received from the server at the end of the response. - public init( - metadata: Metadata, - message: Message, - trailingMetadata: Metadata - ) { - self.metadata = metadata - self.message = .success(message) - self.trailingMetadata = trailingMetadata - } + /// The response message received from the server, or an error of the RPC failed with a + /// non-ok status. + public var message: Result - /// Creates a `Contents`. - /// - /// - Parameters: - /// - metadata: Metadata received from the server at the beginning of the response. - /// - error: Error received from the server. - public init( - metadata: Metadata, - error: RPCError - ) { - self.metadata = metadata - self.message = .failure(error) - self.trailingMetadata = error.metadata - } - } + /// Metadata received from the server at the end of the response. + /// + /// The metadata may contain transport-specific information in addition to any application + /// level metadata provided by the service. + public var trailingMetadata: Metadata - /// Whether the RPC was accepted or rejected. + /// Creates a `Contents`. /// - /// The `success` case indicates the RPC completed successfully with an - /// ``Status/Code-swift.struct/ok`` status code. The `failure` case indicates that the RPC was - /// rejected by the server and wasn't processed or couldn't be processed successfully. - public var accepted: Result + /// - Parameters: + /// - metadata: Metadata received from the server at the beginning of the response. + /// - message: The response message received from the server. + /// - trailingMetadata: Metadata received from the server at the end of the response. + public init( + metadata: Metadata, + message: Message, + trailingMetadata: Metadata + ) { + self.metadata = metadata + self.message = .success(message) + self.trailingMetadata = trailingMetadata + } - /// Creates a new response. + /// Creates a `Contents`. /// - /// - Parameter accepted: The result of the RPC. - public init(accepted: Result) { - self.accepted = accepted + /// - Parameters: + /// - metadata: Metadata received from the server at the beginning of the response. + /// - error: Error received from the server. + public init( + metadata: Metadata, + error: RPCError + ) { + self.metadata = metadata + self.message = .failure(error) + self.trailingMetadata = error.metadata } } -} -extension ClientResponse { - /// A response for a stream of messages received by a client. - /// - /// Stream responses are used for server-streaming and bidirectional-streaming RPCs. For single - /// responses see ``ClientResponse/Single``. - /// - /// A stream response captures every part of the response stream over time and distinguishes - /// accepted and rejected requests via the ``accepted`` property. An "accepted" request is one - /// where the the server responds with initial metadata and attempts to process the request. A - /// "rejected" request is one where the server responds with a status as the first and only - /// response part and doesn't process the request body. + /// Whether the RPC was accepted or rejected. /// - /// The value for the `success` case contains the initial metadata and a ``RPCAsyncSequence`` of - /// message parts (messages followed by a single status). If the sequence completes without - /// throwing then the response implicitly has an ``Status/Code-swift.struct/ok`` status code. - /// However, the response sequence may also throw an ``RPCError`` if the server fails to complete - /// processing the request. - /// - /// The `failure` case indicates that the server chose not to process the RPC or the client failed - /// to execute the request. The failure case contains an ``RPCError`` describing why the RPC - /// failed, including an error code, error message and any metadata sent by the server. - /// - /// ### Using ``Stream`` responses - /// - /// Each response has a ``accepted`` property which contains RPC information. You can create - /// one by calling ``init(accepted:)`` or one of the two convenience initializers: - /// - ``init(of:metadata:bodyParts:)`` to create an accepted response, or - /// - ``init(of:error:)`` to create a failed response. - /// - /// You can interrogate a response by inspecting the ``accepted`` property directly or by using - /// its convenience properties: - /// - ``metadata`` extracts the initial metadata, - /// - ``messages`` extracts the sequence of response message, or throws if the response failed. - /// - /// The following example demonstrates how you can use the API: - /// - /// ```swift - /// // Create a failed response - /// let response = ClientResponse.Stream( - /// of: String.self, - /// error: RPCError(code: .notFound, message: "The requested resource couldn't be located") - /// ) - /// - /// // The explicit API: - /// switch response { - /// case .success(let contents): - /// for try await part in contents.bodyParts { - /// switch part { - /// case .message(let message): - /// print("Received message '\(message)'") - /// case .trailingMetadata(let metadata): - /// print("Received trailing metadata '\(metadata)'") - /// } - /// } - /// case .failure(let error): - /// print("RPC failed with code '\(error.code)'") - /// } + /// The `success` case indicates the RPC completed successfully with an + /// ``Status/Code-swift.struct/ok`` status code. The `failure` case indicates that the RPC was + /// rejected by the server and wasn't processed or couldn't be processed successfully. + public var accepted: Result + + /// Creates a new response. /// - /// // The convenience API: - /// do { - /// for try await message in response.messages { - /// print("Received message '\(message)'") - /// } - /// } catch let error as RPCError { - /// print("RPC failed with code '\(error.code)'") - /// } - /// ``` - @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) - public struct Stream: Sendable { - public struct Contents: Sendable { - /// Metadata received from the server at the beginning of the response. - /// - /// The metadata may contain transport-specific information in addition to any application - /// level metadata provided by the service. - public var metadata: Metadata + /// - Parameter accepted: The result of the RPC. + public init(accepted: Result) { + self.accepted = accepted + } +} - /// A sequence of stream parts received from the server ending with metadata if the RPC - /// succeeded. - /// - /// If the RPC fails then the sequence will throw an ``RPCError``. - /// - /// The sequence may only be iterated once. - public var bodyParts: RPCAsyncSequence +/// A response for a stream of messages received by a client. +/// +/// Stream responses are used for server-streaming and bidirectional-streaming RPCs. For single +/// responses see ``ClientResponse``. +/// +/// A stream response captures every part of the response stream over time and distinguishes +/// accepted and rejected requests via the ``accepted`` property. An "accepted" request is one +/// where the the server responds with initial metadata and attempts to process the request. A +/// "rejected" request is one where the server responds with a status as the first and only +/// response part and doesn't process the request body. +/// +/// The value for the `success` case contains the initial metadata and a ``RPCAsyncSequence`` of +/// message parts (messages followed by a single status). If the sequence completes without +/// throwing then the response implicitly has an ``Status/Code-swift.struct/ok`` status code. +/// However, the response sequence may also throw an ``RPCError`` if the server fails to complete +/// processing the request. +/// +/// The `failure` case indicates that the server chose not to process the RPC or the client failed +/// to execute the request. The failure case contains an ``RPCError`` describing why the RPC +/// failed, including an error code, error message and any metadata sent by the server. +/// +/// ### Using ``Stream`` responses +/// +/// Each response has a ``accepted`` property which contains RPC information. You can create +/// one by calling ``init(accepted:)`` or one of the two convenience initializers: +/// - ``init(of:metadata:bodyParts:)`` to create an accepted response, or +/// - ``init(of:error:)`` to create a failed response. +/// +/// You can interrogate a response by inspecting the ``accepted`` property directly or by using +/// its convenience properties: +/// - ``metadata`` extracts the initial metadata, +/// - ``messages`` extracts the sequence of response message, or throws if the response failed. +/// +/// The following example demonstrates how you can use the API: +/// +/// ```swift +/// // Create a failed response +/// let response = StreamingClientResponse( +/// of: String.self, +/// error: RPCError(code: .notFound, message: "The requested resource couldn't be located") +/// ) +/// +/// // The explicit API: +/// switch response { +/// case .success(let contents): +/// for try await part in contents.bodyParts { +/// switch part { +/// case .message(let message): +/// print("Received message '\(message)'") +/// case .trailingMetadata(let metadata): +/// print("Received trailing metadata '\(metadata)'") +/// } +/// } +/// case .failure(let error): +/// print("RPC failed with code '\(error.code)'") +/// } +/// +/// // The convenience API: +/// do { +/// for try await message in response.messages { +/// print("Received message '\(message)'") +/// } +/// } catch let error as RPCError { +/// print("RPC failed with code '\(error.code)'") +/// } +/// ``` +@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) +public struct StreamingClientResponse: Sendable { + public struct Contents: Sendable { + /// Metadata received from the server at the beginning of the response. + /// + /// The metadata may contain transport-specific information in addition to any application + /// level metadata provided by the service. + public var metadata: Metadata - /// Parts received from the server. - public enum BodyPart: Sendable { - /// A response message. - case message(Message) - /// Metadata. Must be the final value of the sequence unless the stream throws an error. - case trailingMetadata(Metadata) - } + /// A sequence of stream parts received from the server ending with metadata if the RPC + /// succeeded. + /// + /// If the RPC fails then the sequence will throw an ``RPCError``. + /// + /// The sequence may only be iterated once. + public var bodyParts: RPCAsyncSequence - /// Creates a ``Contents``. - /// - /// - Parameters: - /// - metadata: Metadata received from the server at the beginning of the response. - /// - bodyParts: An `AsyncSequence` of parts received from the server. - public init( - metadata: Metadata, - bodyParts: RPCAsyncSequence - ) { - self.metadata = metadata - self.bodyParts = bodyParts - } + /// Parts received from the server. + public enum BodyPart: Sendable { + /// A response message. + case message(Message) + /// Metadata. Must be the final value of the sequence unless the stream throws an error. + case trailingMetadata(Metadata) } - /// Whether the RPC was accepted or rejected. - /// - /// The `success` case indicates the RPC was accepted by the server for - /// processing, however, the RPC may still fail by throwing an error from its - /// `messages` sequence. The `failure` case indicates that the RPC was - /// rejected by the server. - public var accepted: Result - - /// Creates a new response. + /// Creates a ``Contents``. /// - /// - Parameter accepted: The result of the RPC. - public init(accepted: Result) { - self.accepted = accepted + /// - Parameters: + /// - metadata: Metadata received from the server at the beginning of the response. + /// - bodyParts: An `AsyncSequence` of parts received from the server. + public init( + metadata: Metadata, + bodyParts: RPCAsyncSequence + ) { + self.metadata = metadata + self.bodyParts = bodyParts } } + + /// Whether the RPC was accepted or rejected. + /// + /// The `success` case indicates the RPC was accepted by the server for + /// processing, however, the RPC may still fail by throwing an error from its + /// `messages` sequence. The `failure` case indicates that the RPC was + /// rejected by the server. + public var accepted: Result + + /// Creates a new response. + /// + /// - Parameter accepted: The result of the RPC. + public init(accepted: Result) { + self.accepted = accepted + } } // MARK: - Convenience API -extension ClientResponse.Single { +extension ClientResponse { /// Creates a new accepted response. /// /// - Parameters: @@ -333,7 +326,7 @@ extension ClientResponse.Single { } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ClientResponse.Stream { +extension StreamingClientResponse { /// Creates a new accepted response. /// /// - Parameters: diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift index bf57dae23..ca85fabdb 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+HedgingExecutor.swift @@ -66,10 +66,10 @@ extension ClientRPCExecutor { extension ClientRPCExecutor.HedgingExecutor { @inlinable func execute( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async throws -> R { // The high level approach is to have two levels of task group. In the outer level tasks are // run to: @@ -102,7 +102,7 @@ extension ClientRPCExecutor.HedgingExecutor { } group.addTask { - let replayableRequest = ClientRequest.Stream(metadata: request.metadata) { writer in + let replayableRequest = StreamingClientRequest(metadata: request.metadata) { writer in try await writer.write(contentsOf: broadcast.stream) } @@ -148,10 +148,10 @@ extension ClientRPCExecutor.HedgingExecutor { @inlinable func executeAttempt( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async -> Result { await withTaskGroup( of: _HedgingAttemptTaskResult.self, @@ -201,7 +201,7 @@ extension ClientRPCExecutor.HedgingExecutor { } // Stop the most recent unusable response in case no response succeeds. - var unusableResponse: ClientResponse.Stream? + var unusableResponse: StreamingClientResponse? while let next = await group.next() { switch next { @@ -312,13 +312,13 @@ extension ClientRPCExecutor.HedgingExecutor { @inlinable func _startAttempt( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, attempt: Int, state: SharedState, picker: (stream: BroadcastAsyncSequence, continuation: BroadcastAsyncSequence.Source), - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async -> _HedgingAttemptTaskResult.AttemptResult { do { return try await self.transport.withStream( @@ -562,7 +562,7 @@ enum _HedgingAttemptTaskResult: Sendable { @usableFromInline enum AttemptResult: Sendable { - case unusableResponse(ClientResponse.Stream, Metadata.RetryPushback?) + case unusableResponse(StreamingClientResponse, Metadata.RetryPushback?) case usableResponse(Result) case noStreamAvailable(any Error) } diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift index a1288999c..493949fbc 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+OneShotExecutor.swift @@ -58,10 +58,10 @@ extension ClientRPCExecutor { extension ClientRPCExecutor.OneShotExecutor { @inlinable func execute( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async throws -> R { let result: Result @@ -94,10 +94,10 @@ extension ClientRPCExecutor.OneShotExecutor { extension ClientRPCExecutor.OneShotExecutor { @inlinable func _execute( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async -> Result { return await withTaskGroup(of: Void.self, returning: Result.self) { group in do { diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift index d808b1f4a..7188b4a6f 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor+RetryExecutor.swift @@ -64,10 +64,10 @@ extension ClientRPCExecutor { extension ClientRPCExecutor.RetryExecutor { @inlinable func execute( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async throws -> R { // There's quite a lot going on here... // @@ -201,13 +201,13 @@ extension ClientRPCExecutor.RetryExecutor { retryStream: BroadcastAsyncSequence, method: MethodDescriptor, attempt: Int, - responseHandler: @Sendable @escaping (ClientResponse.Stream) async throws -> R + responseHandler: @Sendable @escaping (StreamingClientResponse) async throws -> R ) async -> _RetryExecutorTask { return await withTaskGroup( of: Void.self, returning: _RetryExecutorTask.self ) { group in - let request = ClientRequest.Stream(metadata: metadata) { + let request = StreamingClientRequest(metadata: metadata) { try await $0.write(contentsOf: retryStream) } diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift index 33e46fd2d..f6e91d94f 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRPCExecutor.swift @@ -33,14 +33,14 @@ enum ClientRPCExecutor { /// - Returns: The result returns from the `handler`. @inlinable static func execute( - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, options: CallOptions, serializer: some MessageSerializer, deserializer: some MessageDeserializer, transport: some ClientTransport, interceptors: [any ClientInterceptor], - handler: @Sendable @escaping (ClientResponse.Stream) async throws -> Result + handler: @Sendable @escaping (StreamingClientResponse) async throws -> Result ) async throws -> Result { let deadline = options.timeout.map { ContinuousClock.now + $0 } @@ -116,14 +116,14 @@ extension ClientRPCExecutor { @inlinable // would be private static func _execute( in group: inout TaskGroup, - request: ClientRequest.Stream, + request: StreamingClientRequest, method: MethodDescriptor, attempt: Int, serializer: some MessageSerializer, deserializer: some MessageDeserializer, interceptors: [any ClientInterceptor], stream: RPCStream - ) async -> ClientResponse.Stream { + ) async -> StreamingClientResponse { let context = ClientContext(descriptor: method) if interceptors.isEmpty { @@ -159,15 +159,15 @@ extension ClientRPCExecutor { @inlinable static func _intercept( in group: inout TaskGroup, - request: ClientRequest.Stream, + request: StreamingClientRequest, context: ClientContext, iterator: Array.Iterator, finally: ( _ group: inout TaskGroup, - _ request: ClientRequest.Stream, + _ request: StreamingClientRequest, _ context: ClientContext - ) async -> ClientResponse.Stream - ) async -> ClientResponse.Stream { + ) async -> StreamingClientResponse + ) async -> StreamingClientResponse { var iterator = iterator switch iterator.next() { @@ -184,10 +184,10 @@ extension ClientRPCExecutor { ) } } catch let error as RPCError { - return ClientResponse.Stream(error: error) + return StreamingClientResponse(error: error) } catch let other { let error = RPCError(code: .unknown, message: "", cause: other) - return ClientResponse.Stream(error: error) + return StreamingClientResponse(error: error) } case .none: diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift b/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift index 74beb368b..9f9b3223b 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientRequest+Convenience.swift @@ -15,8 +15,8 @@ */ @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) -extension ClientRequest.Stream { - internal init(single request: ClientRequest.Single) { +extension StreamingClientRequest { + internal init(single request: ClientRequest) { self.init(metadata: request.metadata) { try await $0.write(request.message) } diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift b/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift index ecba7cf57..c6e315ba8 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientResponse+Convenience.swift @@ -15,11 +15,11 @@ */ @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ClientResponse.Single { +extension ClientResponse { /// Converts a streaming response into a single response. /// /// - Parameter response: The streaming response to convert. - init(stream response: ClientResponse.Stream) async { + init(stream response: StreamingClientResponse) async { switch response.accepted { case .success(let contents): do { @@ -83,7 +83,7 @@ extension ClientResponse.Single { } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ClientResponse.Stream { +extension StreamingClientResponse { /// Creates a streaming response from the given status and metadata. /// /// If the ``Status`` has code ``Status/Code-swift.struct/ok`` then an accepted stream is created @@ -104,7 +104,7 @@ extension ClientResponse.Stream { } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ClientResponse.Stream { +extension StreamingClientResponse { /// Returns a new response which maps the messages of this response. /// /// - Parameter transform: The function to transform each message with. @@ -112,10 +112,10 @@ extension ClientResponse.Stream { @inlinable func map( _ transform: @escaping @Sendable (Message) throws -> Mapped - ) -> ClientResponse.Stream { + ) -> StreamingClientResponse { switch self.accepted { case .success(let contents): - return ClientResponse.Stream( + return StreamingClientResponse( metadata: self.metadata, bodyParts: RPCAsyncSequence( wrapping: contents.bodyParts.map { @@ -130,7 +130,7 @@ extension ClientResponse.Stream { ) case .failure(let error): - return ClientResponse.Stream(accepted: .failure(error)) + return StreamingClientResponse(accepted: .failure(error)) } } } diff --git a/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift b/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift index 8b635bca8..728f4e337 100644 --- a/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift +++ b/Sources/GRPCCore/Call/Client/Internal/ClientStreamExecutor.swift @@ -31,13 +31,13 @@ internal enum ClientStreamExecutor { @inlinable static func execute( in group: inout TaskGroup, - request: ClientRequest.Stream, + request: StreamingClientRequest, context: ClientContext, attempt: Int, serializer: some MessageSerializer, deserializer: some MessageDeserializer, stream: RPCStream - ) async -> ClientResponse.Stream { + ) async -> StreamingClientResponse { // Let the server know this is a retry. var metadata = request.metadata if attempt > 1 { @@ -63,7 +63,7 @@ internal enum ClientStreamExecutor { ) // Expected happy case: the server is processing the request. - return ClientResponse.Stream( + return StreamingClientResponse( metadata: metadata, bodyParts: RPCAsyncSequence(wrapping: bodyParts) ) @@ -75,18 +75,18 @@ internal enum ClientStreamExecutor { } // Expected unhappy (but okay) case; the server rejected the request. - return ClientResponse.Stream(status: status, metadata: metadata) + return StreamingClientResponse(status: status, metadata: metadata) case .failed(let error): // Very unhappy case: the server did something unexpected. - return ClientResponse.Stream(error: error) + return StreamingClientResponse(error: error) } } @inlinable // would be private static func _processRequest( on stream: some ClosableRPCWriterProtocol, - request: ClientRequest.Stream, + request: StreamingClientRequest, serializer: some MessageSerializer ) async { let result = await Result { @@ -194,7 +194,7 @@ internal enum ClientStreamExecutor { @usableFromInline struct AsyncIterator: AsyncIteratorProtocol { @usableFromInline - typealias Element = ClientResponse.Stream.Contents.BodyPart + typealias Element = StreamingClientResponse.Contents.BodyPart @usableFromInline var base: Base.AsyncIterator @@ -210,7 +210,7 @@ internal enum ClientStreamExecutor { @inlinable mutating func next( isolation actor: isolated (any Actor)? - ) async throws(any Error) -> ClientResponse.Stream.Contents.BodyPart? { + ) async throws(any Error) -> StreamingClientResponse.Contents.BodyPart? { guard let part = try await self.base.next(isolation: `actor`) else { return nil } switch part { @@ -238,7 +238,7 @@ internal enum ClientStreamExecutor { } @inlinable - mutating func next() async throws -> ClientResponse.Stream.Contents.BodyPart? { + mutating func next() async throws -> StreamingClientResponse.Contents.BodyPart? { try await self.next(isolation: nil) } } diff --git a/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift b/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift index a67bfbe37..79fba9b5c 100644 --- a/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift +++ b/Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift @@ -37,9 +37,9 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @Sendable @escaping ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse ) async { // Wait for the first request part from the transport. let firstPart = await Self._waitForFirstRequestPart(inbound: stream.inbound) @@ -75,9 +75,9 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @escaping @Sendable ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse ) async { if let timeout = metadata.timeout { await Self._processRPCWithTimeout( @@ -116,9 +116,9 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @escaping @Sendable ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse ) async { await withTaskGroup(of: ServerExecutorTask.self) { group in group.addTask { @@ -170,9 +170,9 @@ struct ServerRPCExecutor { serializer: some MessageSerializer, interceptors: [any ServerInterceptor], handler: @escaping @Sendable ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse ) async { let messages = UncheckedAsyncIteratorSequence(inbound.wrappedValue).map { part in switch part { @@ -192,7 +192,7 @@ struct ServerRPCExecutor { let response = await Result { // Run the request through the interceptors, finally passing it to the handler. return try await Self._intercept( - request: ServerRequest.Stream( + request: StreamingServerRequest( metadata: metadata, messages: RPCAsyncSequence(wrapping: messages) ), @@ -300,14 +300,14 @@ struct ServerRPCExecutor { extension ServerRPCExecutor { @inlinable static func _intercept( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext, interceptors: [any ServerInterceptor], finally: @escaping @Sendable ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse + ) async throws -> StreamingServerResponse { return try await self._intercept( request: request, context: context, @@ -318,14 +318,14 @@ extension ServerRPCExecutor { @inlinable static func _intercept( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext, iterator: Array.Iterator, finally: @escaping @Sendable ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse + ) async throws -> StreamingServerResponse { var iterator = iterator switch iterator.next() { @@ -336,10 +336,10 @@ extension ServerRPCExecutor { try await self._intercept(request: $0, context: $1, iterator: iter, finally: finally) } } catch let error as RPCError { - return ServerResponse.Stream(error: error) + return StreamingServerResponse(error: error) } catch let other { let error = RPCError(code: .unknown, message: "", cause: other) - return ServerResponse.Stream(error: error) + return StreamingServerResponse(error: error) } case .none: diff --git a/Sources/GRPCCore/Call/Server/RPCRouter.swift b/Sources/GRPCCore/Call/Server/RPCRouter.swift index bc2f58fef..35d14cbd5 100644 --- a/Sources/GRPCCore/Call/Server/RPCRouter.swift +++ b/Sources/GRPCCore/Call/Server/RPCRouter.swift @@ -53,9 +53,9 @@ public struct RPCRouter: Sendable { deserializer: some MessageDeserializer, serializer: some MessageSerializer, handler: @Sendable @escaping ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse ) { self._fn = { stream, context, interceptors in await ServerRPCExecutor.execute( @@ -123,9 +123,9 @@ public struct RPCRouter: Sendable { deserializer: some MessageDeserializer, serializer: some MessageSerializer, handler: @Sendable @escaping ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse ) { self.handlers[descriptor] = RPCHandler( method: descriptor, diff --git a/Sources/GRPCCore/Call/Server/ServerInterceptor.swift b/Sources/GRPCCore/Call/Server/ServerInterceptor.swift index c10c166ca..aa1fff090 100644 --- a/Sources/GRPCCore/Call/Server/ServerInterceptor.swift +++ b/Sources/GRPCCore/Call/Server/ServerInterceptor.swift @@ -37,13 +37,13 @@ /// let isAuthorized: @Sendable (String, MethodDescriptor) async throws -> Void /// /// func intercept( -/// request: ServerRequest.Stream, +/// request: StreamingServerRequest, /// context: ServerInterceptorContext, /// next: @Sendable ( -/// _ request: ServerRequest.Stream, +/// _ request: StreamingServerRequest, /// _ context: ServerInterceptorContext -/// ) async throws -> ServerResponse.Stream -/// ) async throws -> ServerResponse.Stream { +/// ) async throws -> StreamingServerResponse +/// ) async throws -> StreamingServerResponse { /// // Extract the auth token. /// guard let token = request.metadata["authorization"] else { /// throw RPCError(code: .unauthenticated, message: "Not authenticated") @@ -71,11 +71,11 @@ public protocol ServerInterceptor: Sendable { /// interceptor in the chain. /// - Returns: A response object. func intercept( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext, next: @Sendable ( - _ request: ServerRequest.Stream, + _ request: StreamingServerRequest, _ context: ServerContext - ) async throws -> ServerResponse.Stream - ) async throws -> ServerResponse.Stream + ) async throws -> StreamingServerResponse + ) async throws -> StreamingServerResponse } diff --git a/Sources/GRPCCore/Call/Server/ServerRequest.swift b/Sources/GRPCCore/Call/Server/ServerRequest.swift index 90618bdfe..b0318ee15 100644 --- a/Sources/GRPCCore/Call/Server/ServerRequest.swift +++ b/Sources/GRPCCore/Call/Server/ServerRequest.swift @@ -14,72 +14,65 @@ * limitations under the License. */ -/// A namespace for request message types used by servers. -public enum ServerRequest {} +/// A request received at the server containing a single message. +public struct ServerRequest: Sendable { + /// Metadata received from the client at the start of the RPC. + /// + /// The metadata contains gRPC and transport specific entries in addition to user-specified + /// metadata. + public var metadata: Metadata -extension ServerRequest { - /// A request received at the server containing a single message. - public struct Single: Sendable { - /// Metadata received from the client at the start of the RPC. - /// - /// The metadata contains gRPC and transport specific entries in addition to user-specified - /// metadata. - public var metadata: Metadata - - /// The message received from the client. - public var message: Message + /// The message received from the client. + public var message: Message - /// Create a new single server request. - /// - /// - Parameters: - /// - metadata: Metadata received from the client. - /// - message: The message received from the client. - public init(metadata: Metadata, message: Message) { - self.metadata = metadata - self.message = message - } + /// Create a new single server request. + /// + /// - Parameters: + /// - metadata: Metadata received from the client. + /// - message: The message received from the client. + public init(metadata: Metadata, message: Message) { + self.metadata = metadata + self.message = message } } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ServerRequest { - /// A request received at the server containing a stream of messages. - public struct Stream: Sendable { - /// Metadata received from the client at the start of the RPC. - /// - /// The metadata contains gRPC and transport specific entries in addition to user-specified - /// metadata. - public var metadata: Metadata +/// A request received at the server containing a stream of messages. +public struct StreamingServerRequest: Sendable { + /// Metadata received from the client at the start of the RPC. + /// + /// The metadata contains gRPC and transport specific entries in addition to user-specified + /// metadata. + public var metadata: Metadata - /// A sequence of messages received from the client. - /// - /// The sequence may be iterated at most once. - public var messages: RPCAsyncSequence + /// A sequence of messages received from the client. + /// + /// The sequence may be iterated at most once. + public var messages: RPCAsyncSequence - /// Create a new streaming request. - /// - /// - Parameters: - /// - metadata: Metadata received from the client. - /// - messages: A sequence of messages received from the client. - public init(metadata: Metadata, messages: RPCAsyncSequence) { - self.metadata = metadata - self.messages = messages - } + /// Create a new streaming request. + /// + /// - Parameters: + /// - metadata: Metadata received from the client. + /// - messages: A sequence of messages received from the client. + public init(metadata: Metadata, messages: RPCAsyncSequence) { + self.metadata = metadata + self.messages = messages } } // MARK: - Conversion @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ServerRequest.Stream { - public init(single request: ServerRequest.Single) { +extension StreamingServerRequest { + public init(single request: ServerRequest) { self.init(metadata: request.metadata, messages: .one(request.message)) } } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) -extension ServerRequest.Single { - public init(stream request: ServerRequest.Stream) async throws { +extension ServerRequest { + public init(stream request: StreamingServerRequest) async throws { var iterator = request.messages.makeAsyncIterator() guard let message = try await iterator.next() else { @@ -90,6 +83,6 @@ extension ServerRequest.Single { throw RPCError(code: .internalError, message: "Too many messages.") } - self = ServerRequest.Single(metadata: request.metadata, message: message) + self = ServerRequest(metadata: request.metadata, message: message) } } diff --git a/Sources/GRPCCore/Call/Server/ServerResponse.swift b/Sources/GRPCCore/Call/Server/ServerResponse.swift index a0b516815..778d1b395 100644 --- a/Sources/GRPCCore/Call/Server/ServerResponse.swift +++ b/Sources/GRPCCore/Call/Server/ServerResponse.swift @@ -14,220 +14,213 @@ * limitations under the License. */ -/// A namespace for response message types used by servers. -public enum ServerResponse {} - -extension ServerResponse { - /// A response for a single message sent by a server. - /// - /// Single responses are used for unary and client-streaming RPCs. For streaming responses - /// see ``ServerResponse/Stream``. - /// - /// A single response captures every part of the response stream and distinguishes successful - /// and unsuccessful responses via the ``accepted`` property. The value for the `success` case - /// contains the initial metadata, response message, and the trailing metadata and implicitly - /// has an ``Status/Code-swift.struct/ok`` status code. - /// - /// The `failure` case indicates that the server chose not to process the RPC, or the processing - /// of the RPC failed. The failure case contains an ``RPCError`` describing why the RPC failed, - /// including an error code, error message and any metadata sent by the server. - /// - /// ### Using ``Single`` responses - /// - /// Each response has an ``accepted`` property which contains all RPC information. You can create - /// one by calling ``init(accepted:)`` or one of the two convenience initializers: - /// - ``init(message:metadata:trailingMetadata:)`` to create a successful response, or - /// - ``init(of:error:)`` to create a failed response. - /// - /// You can interrogate a response by inspecting the ``accepted`` property directly or by using - /// its convenience properties: - /// - ``metadata`` extracts the initial metadata, - /// - ``message`` extracts the message, or throws if the response failed, and - /// - ``trailingMetadata`` extracts the trailing metadata. - /// - /// The following example demonstrates how you can use the API: - /// - /// ```swift - /// // Create a successful response - /// let response = ServerResponse.Single( - /// message: "Hello, World!", - /// metadata: ["hello": "initial metadata"], - /// trailingMetadata: ["goodbye": "trailing metadata"] - /// ) - /// - /// // The explicit API: - /// switch response { - /// case .success(let contents): - /// print("Received response with message '\(contents.message)'") - /// case .failure(let error): - /// print("RPC failed with code '\(error.code)'") - /// } - /// - /// // The convenience API: - /// do { - /// print("Received response with message '\(try response.message)'") - /// } catch let error as RPCError { - /// print("RPC failed with code '\(error.code)'") - /// } - /// ``` - public struct Single: Sendable { - /// An accepted RPC with a successful outcome. - public struct Contents: Sendable { - /// Caller-specified metadata to send to the client at the start of the response. - /// - /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with - /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert - /// their own metadata, you should avoid using key names which may clash with transport - /// specific metadata. Note that transports may also impose limits in the amount of metadata - /// which may be sent. - public var metadata: Metadata - - /// The message to send to the client. - public var message: Message - - /// Caller-specified metadata to send to the client at the end of the response. - /// - /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with - /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert - /// their own metadata, you should avoid using key names which may clash with transport - /// specific metadata. Note that transports may also impose limits in the amount of metadata - /// which may be sent. - public var trailingMetadata: Metadata +/// A response for a single message sent by a server. +/// +/// Single responses are used for unary and client-streaming RPCs. For streaming responses +/// see ``StreamingServerResponse``. +/// +/// A single response captures every part of the response stream and distinguishes successful +/// and unsuccessful responses via the ``accepted`` property. The value for the `success` case +/// contains the initial metadata, response message, and the trailing metadata and implicitly +/// has an ``Status/Code-swift.struct/ok`` status code. +/// +/// The `failure` case indicates that the server chose not to process the RPC, or the processing +/// of the RPC failed. The failure case contains an ``RPCError`` describing why the RPC failed, +/// including an error code, error message and any metadata sent by the server. +/// +/// ### Using ``Single`` responses +/// +/// Each response has an ``accepted`` property which contains all RPC information. You can create +/// one by calling ``init(accepted:)`` or one of the two convenience initializers: +/// - ``init(message:metadata:trailingMetadata:)`` to create a successful response, or +/// - ``init(of:error:)`` to create a failed response. +/// +/// You can interrogate a response by inspecting the ``accepted`` property directly or by using +/// its convenience properties: +/// - ``metadata`` extracts the initial metadata, +/// - ``message`` extracts the message, or throws if the response failed, and +/// - ``trailingMetadata`` extracts the trailing metadata. +/// +/// The following example demonstrates how you can use the API: +/// +/// ```swift +/// // Create a successful response +/// let response = ServerResponse( +/// message: "Hello, World!", +/// metadata: ["hello": "initial metadata"], +/// trailingMetadata: ["goodbye": "trailing metadata"] +/// ) +/// +/// // The explicit API: +/// switch response { +/// case .success(let contents): +/// print("Received response with message '\(contents.message)'") +/// case .failure(let error): +/// print("RPC failed with code '\(error.code)'") +/// } +/// +/// // The convenience API: +/// do { +/// print("Received response with message '\(try response.message)'") +/// } catch let error as RPCError { +/// print("RPC failed with code '\(error.code)'") +/// } +/// ``` +public struct ServerResponse: Sendable { + /// An accepted RPC with a successful outcome. + public struct Contents: Sendable { + /// Caller-specified metadata to send to the client at the start of the response. + /// + /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with + /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert + /// their own metadata, you should avoid using key names which may clash with transport + /// specific metadata. Note that transports may also impose limits in the amount of metadata + /// which may be sent. + public var metadata: Metadata - /// Create a new single client request. - /// - /// - Parameters: - /// - message: The message to send to the server. - /// - metadata: Metadata to send to the client at the start of the response. Defaults to - /// empty. - /// - trailingMetadata: Metadata to send to the client at the end of the response. Defaults - /// to empty. - public init( - message: Message, - metadata: Metadata = [:], - trailingMetadata: Metadata = [:] - ) { - self.metadata = metadata - self.message = message - self.trailingMetadata = trailingMetadata - } - } + /// The message to send to the client. + public var message: Message - /// Whether the RPC was accepted or rejected. + /// Caller-specified metadata to send to the client at the end of the response. /// - /// The `success` indicates the server accepted the RPC for processing and the RPC completed - /// successfully and implies the RPC succeeded with the ``Status/Code-swift.struct/ok`` status - /// code. The `failure` case indicates that the service rejected the RPC without processing it - /// or could not process it successfully. - public var accepted: Result + /// Both gRPC Swift and its transport layer may insert additional metadata. Keys prefixed with + /// "grpc-" are prohibited and may result in undefined behaviour. Transports may also insert + /// their own metadata, you should avoid using key names which may clash with transport + /// specific metadata. Note that transports may also impose limits in the amount of metadata + /// which may be sent. + public var trailingMetadata: Metadata - /// Creates a response. + /// Create a new single client request. /// - /// - Parameter accepted: Whether the RPC was accepted or rejected. - public init(accepted: Result) { - self.accepted = accepted + /// - Parameters: + /// - message: The message to send to the server. + /// - metadata: Metadata to send to the client at the start of the response. Defaults to + /// empty. + /// - trailingMetadata: Metadata to send to the client at the end of the response. Defaults + /// to empty. + public init( + message: Message, + metadata: Metadata = [:], + trailingMetadata: Metadata = [:] + ) { + self.metadata = metadata + self.message = message + self.trailingMetadata = trailingMetadata } } -} -extension ServerResponse { - /// A response for a stream of messages sent by a server. - /// - /// Stream responses are used for server-streaming and bidirectional-streaming RPCs. For single - /// responses see ``ServerResponse/Single``. + /// Whether the RPC was accepted or rejected. /// - /// A stream response captures every part of the response stream and distinguishes whether the - /// request was processed by the server via the ``accepted`` property. The value for the `success` - /// case contains the initial metadata and a closure which is provided with a message write and - /// returns trailing metadata. If the closure returns without error then the response implicitly - /// has an ``Status/Code-swift.struct/ok`` status code. You can throw an error from the producer - /// to indicate that the request couldn't be handled successfully. If an ``RPCError`` is thrown - /// then the client will receive an equivalent error populated with the same code and message. If - /// an error of any other type is thrown then the client will receive an error with the - /// ``Status/Code-swift.struct/unknown`` status code. - /// - /// The `failure` case indicates that the server chose not to process the RPC. The failure case - /// contains an ``RPCError`` describing why the RPC failed, including an error code, error - /// message and any metadata to send to the client. - /// - /// ### Using ``Stream`` responses - /// - /// Each response has an ``accepted`` property which contains all RPC information. You can create - /// one by calling ``init(accepted:)`` or one of the two convenience initializers: - /// - ``init(of:metadata:producer:)`` to create a successful response, or - /// - ``init(of:error:)`` to create a failed response. - /// - /// You can interrogate a response by inspecting the ``accepted`` property directly. The following - /// example demonstrates how you can use the API: - /// - /// ```swift - /// // Create a successful response - /// let response = ServerResponse.Stream( - /// of: String.self, - /// metadata: ["hello": "initial metadata"] - /// ) { writer in - /// // Write a few messages. - /// try await writer.write("Hello") - /// try await writer.write("World") - /// - /// // Send trailing metadata to the client. - /// return ["goodbye": "trailing metadata"] - /// } - /// ``` - @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) - public struct Stream: Sendable { - /// The contents of a response to a request which has been accepted for processing. - public struct Contents: Sendable { - /// Metadata to send to the client at the beginning of the response stream. - public var metadata: Metadata + /// The `success` indicates the server accepted the RPC for processing and the RPC completed + /// successfully and implies the RPC succeeded with the ``Status/Code-swift.struct/ok`` status + /// code. The `failure` case indicates that the service rejected the RPC without processing it + /// or could not process it successfully. + public var accepted: Result - /// A closure which, when called, writes values into the provided writer and returns trailing - /// metadata indicating the end of the response stream. - /// - /// Returning metadata indicates a successful response and gRPC will terminate the RPC with - /// an ``Status/Code-swift.struct/ok`` status code. Throwing an error will terminate the RPC - /// with an appropriate status code. You can control the status code, message and metadata - /// returned to the client by throwing an ``RPCError``. If the error thrown is a type other - /// than ``RPCError`` then a status with code ``Status/Code-swift.struct/unknown`` will - /// be returned to the client. - /// - /// gRPC will invoke this function at most once therefore it isn't required to be idempotent. - public var producer: @Sendable (RPCWriter) async throws -> Metadata + /// Creates a response. + /// + /// - Parameter accepted: Whether the RPC was accepted or rejected. + public init(accepted: Result) { + self.accepted = accepted + } +} - /// Create a ``Contents``. - /// - /// - Parameters: - /// - metadata: Metadata to send to the client at the start of the response. - /// - producer: A function which produces values - public init( - metadata: Metadata, - producer: @escaping @Sendable (RPCWriter) async throws -> Metadata - ) { - self.metadata = metadata - self.producer = producer - } - } +/// A response for a stream of messages sent by a server. +/// +/// Stream responses are used for server-streaming and bidirectional-streaming RPCs. For single +/// responses see ``ServerResponse``. +/// +/// A stream response captures every part of the response stream and distinguishes whether the +/// request was processed by the server via the ``accepted`` property. The value for the `success` +/// case contains the initial metadata and a closure which is provided with a message write and +/// returns trailing metadata. If the closure returns without error then the response implicitly +/// has an ``Status/Code-swift.struct/ok`` status code. You can throw an error from the producer +/// to indicate that the request couldn't be handled successfully. If an ``RPCError`` is thrown +/// then the client will receive an equivalent error populated with the same code and message. If +/// an error of any other type is thrown then the client will receive an error with the +/// ``Status/Code-swift.struct/unknown`` status code. +/// +/// The `failure` case indicates that the server chose not to process the RPC. The failure case +/// contains an ``RPCError`` describing why the RPC failed, including an error code, error +/// message and any metadata to send to the client. +/// +/// ### Using ``Stream`` responses +/// +/// Each response has an ``accepted`` property which contains all RPC information. You can create +/// one by calling ``init(accepted:)`` or one of the two convenience initializers: +/// - ``init(of:metadata:producer:)`` to create a successful response, or +/// - ``init(of:error:)`` to create a failed response. +/// +/// You can interrogate a response by inspecting the ``accepted`` property directly. The following +/// example demonstrates how you can use the API: +/// +/// ```swift +/// // Create a successful response +/// let response = StreamingServerResponse( +/// of: String.self, +/// metadata: ["hello": "initial metadata"] +/// ) { writer in +/// // Write a few messages. +/// try await writer.write("Hello") +/// try await writer.write("World") +/// +/// // Send trailing metadata to the client. +/// return ["goodbye": "trailing metadata"] +/// } +/// ``` +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct StreamingServerResponse: Sendable { + /// The contents of a response to a request which has been accepted for processing. + public struct Contents: Sendable { + /// Metadata to send to the client at the beginning of the response stream. + public var metadata: Metadata - /// Whether the RPC was accepted or rejected. + /// A closure which, when called, writes values into the provided writer and returns trailing + /// metadata indicating the end of the response stream. /// - /// The `success` case indicates that the service accepted the RPC for processing and will - /// send initial metadata back to the client before producing response messages. The RPC may - /// still result in failure by later throwing an error. + /// Returning metadata indicates a successful response and gRPC will terminate the RPC with + /// an ``Status/Code-swift.struct/ok`` status code. Throwing an error will terminate the RPC + /// with an appropriate status code. You can control the status code, message and metadata + /// returned to the client by throwing an ``RPCError``. If the error thrown is a type other + /// than ``RPCError`` then a status with code ``Status/Code-swift.struct/unknown`` will + /// be returned to the client. /// - /// The `failure` case indicates that the server rejected the RPC and will not process it. Only - /// the status and trailing metadata will be sent to the client. - public var accepted: Result + /// gRPC will invoke this function at most once therefore it isn't required to be idempotent. + public var producer: @Sendable (RPCWriter) async throws -> Metadata - /// Creates a response. + /// Create a ``Contents``. /// - /// - Parameter accepted: Whether the RPC was accepted or rejected. - public init(accepted: Result) { - self.accepted = accepted + /// - Parameters: + /// - metadata: Metadata to send to the client at the start of the response. + /// - producer: A function which produces values + public init( + metadata: Metadata, + producer: @escaping @Sendable (RPCWriter) async throws -> Metadata + ) { + self.metadata = metadata + self.producer = producer } } + + /// Whether the RPC was accepted or rejected. + /// + /// The `success` case indicates that the service accepted the RPC for processing and will + /// send initial metadata back to the client before producing response messages. The RPC may + /// still result in failure by later throwing an error. + /// + /// The `failure` case indicates that the server rejected the RPC and will not process it. Only + /// the status and trailing metadata will be sent to the client. + public var accepted: Result + + /// Creates a response. + /// + /// - Parameter accepted: Whether the RPC was accepted or rejected. + public init(accepted: Result) { + self.accepted = accepted + } } -extension ServerResponse.Single { +extension ServerResponse { /// Creates a new accepted response. /// /// - Parameters: @@ -287,7 +280,7 @@ extension ServerResponse.Single { } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) -extension ServerResponse.Stream { +extension StreamingServerResponse { /// Creates a new accepted response. /// /// - Parameters: @@ -326,8 +319,8 @@ extension ServerResponse.Stream { } @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) -extension ServerResponse.Stream { - public init(single response: ServerResponse.Single) { +extension StreamingServerResponse { + public init(single response: ServerResponse) { switch response.accepted { case .success(let contents): let contents = Contents(metadata: contents.metadata) { diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step01.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step01.swift index ef1120c64..b4b20841a 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step01.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step01.swift @@ -1,11 +1,11 @@ struct Greeter: Helloworld_GreeterServiceProtocol { func sayHello( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { var reply = Helloworld_HelloReply() let recipient = request.message.name.isEmpty ? "stranger" : request.message.name reply.message = "Hello, \(recipient)" - return ServerResponse.Single(message: reply) + return ServerResponse(message: reply) } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step02.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step02.swift index 44e571bec..9ecccd975 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step02.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Resources/hello-world-sec04-step02.swift @@ -1,21 +1,21 @@ struct Greeter: Helloworld_GreeterServiceProtocol { func sayHello( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { var reply = Helloworld_HelloReply() let recipient = request.message.name.isEmpty ? "stranger" : request.message.name reply.message = "Hello, \(recipient)" - return ServerResponse.Single(message: reply) + return ServerResponse(message: reply) } func sayHelloAgain( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { var reply = Helloworld_HelloReply() let recipient = request.message.name.isEmpty ? "stranger" : request.message.name reply.message = "Hello again, \(recipient)" - return ServerResponse.Single(message: reply) + return ServerResponse(message: reply) } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step02-unimplemented.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step02-unimplemented.swift index b2651be95..283c9a8fb 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step02-unimplemented.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step02-unimplemented.swift @@ -2,26 +2,26 @@ import GRPCCore struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step03-features.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step03-features.swift index 46925a6bb..84ce31e89 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step03-features.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step03-features.swift @@ -11,26 +11,26 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step04-unary.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step04-unary.swift index 11fbc8215..cf1b88e21 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step04-unary.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step04-unary.swift @@ -18,9 +18,9 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude @@ -28,20 +28,20 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step05-unary.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step05-unary.swift index d2d82d553..dcbde29fa 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step05-unary.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step05-unary.swift @@ -18,16 +18,16 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude ) if let feature { - return ServerResponse.Single(message: feature) + return ServerResponse(message: feature) } else { // No feature: return a feature with an empty name. let unknownFeature = Routeguide_Feature.with { @@ -37,25 +37,25 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.longitude = request.message.longitude } } - return ServerResponse.Single(message: unknownFeature) + return ServerResponse(message: unknownFeature) } } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step06-server-streaming.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step06-server-streaming.swift index b833d72f8..779857268 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step06-server-streaming.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step06-server-streaming.swift @@ -18,16 +18,16 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude ) if let feature { - return ServerResponse.Single(message: feature) + return ServerResponse(message: feature) } else { // No feature: return a feature with an empty name. let unknownFeature = Routeguide_Feature.with { @@ -37,15 +37,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.longitude = request.message.longitude } } - return ServerResponse.Single(message: unknownFeature) + return ServerResponse(message: unknownFeature) } } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { - return ServerResponse.Stream { writer in + ) async throws -> StreamingServerResponse { + return StreamingServerResponse { writer in for feature in self.features { if !feature.name.isEmpty, feature.isContained(by: request.message) { try await writer.write(feature) @@ -55,15 +55,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step07-server-streaming.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step07-server-streaming.swift index 6c64829e5..8fe80e2dd 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step07-server-streaming.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step07-server-streaming.swift @@ -18,16 +18,16 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude ) if let feature { - return ServerResponse.Single(message: feature) + return ServerResponse(message: feature) } else { // No feature: return a feature with an empty name. let unknownFeature = Routeguide_Feature.with { @@ -37,15 +37,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.longitude = request.message.longitude } } - return ServerResponse.Single(message: unknownFeature) + return ServerResponse(message: unknownFeature) } } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { - return ServerResponse.Stream { writer in + ) async throws -> StreamingServerResponse { + return StreamingServerResponse { writer in for feature in self.features { if !feature.name.isEmpty, feature.isContained(by: request.message) { try await writer.write(feature) @@ -57,15 +57,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step08-client-streaming.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step08-client-streaming.swift index d9221cd01..2004a8ddc 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step08-client-streaming.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step08-client-streaming.swift @@ -19,16 +19,16 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude ) if let feature { - return ServerResponse.Single(message: feature) + return ServerResponse(message: feature) } else { // No feature: return a feature with an empty name. let unknownFeature = Routeguide_Feature.with { @@ -38,15 +38,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.longitude = request.message.longitude } } - return ServerResponse.Single(message: unknownFeature) + return ServerResponse(message: unknownFeature) } } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { - return ServerResponse.Stream { writer in + ) async throws -> StreamingServerResponse { + return StreamingServerResponse { writer in for feature in self.features { if !feature.name.isEmpty, feature.isContained(by: request.message) { try await writer.write(feature) @@ -58,9 +58,9 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let startTime = ContinuousClock.now var pointsVisited = 0 var featuresVisited = 0 @@ -89,13 +89,13 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.distance = Int32(distanceTravelled) } - return ServerResponse.Single(message: summary) + return ServerResponse(message: summary) } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step09-bidi-streaming.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step09-bidi-streaming.swift index c8f9010b5..d48385753 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step09-bidi-streaming.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step09-bidi-streaming.swift @@ -50,16 +50,16 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude ) if let feature { - return ServerResponse.Single(message: feature) + return ServerResponse(message: feature) } else { // No feature: return a feature with an empty name. let unknownFeature = Routeguide_Feature.with { @@ -69,15 +69,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.longitude = request.message.longitude } } - return ServerResponse.Single(message: unknownFeature) + return ServerResponse(message: unknownFeature) } } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { - return ServerResponse.Stream { writer in + ) async throws -> StreamingServerResponse { + return StreamingServerResponse { writer in for feature in self.features { if !feature.name.isEmpty, feature.isContained(by: request.message) { try await writer.write(feature) @@ -89,9 +89,9 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let startTime = ContinuousClock.now var pointsVisited = 0 var featuresVisited = 0 @@ -120,13 +120,13 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.distance = Int32(distanceTravelled) } - return ServerResponse.Single(message: summary) + return ServerResponse(message: summary) } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse { } } diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step10-bidi-streaming.swift b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step10-bidi-streaming.swift index 8f4027b5e..eb2b88a78 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step10-bidi-streaming.swift +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec04-step10-bidi-streaming.swift @@ -50,16 +50,16 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func getFeature( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let feature = self.findFeature( latitude: request.message.latitude, longitude: request.message.longitude ) if let feature { - return ServerResponse.Single(message: feature) + return ServerResponse(message: feature) } else { // No feature: return a feature with an empty name. let unknownFeature = Routeguide_Feature.with { @@ -69,15 +69,15 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.longitude = request.message.longitude } } - return ServerResponse.Single(message: unknownFeature) + return ServerResponse(message: unknownFeature) } } func listFeatures( - request: ServerRequest.Single, + request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { - return ServerResponse.Stream { writer in + ) async throws -> StreamingServerResponse { + return StreamingServerResponse { writer in for feature in self.features { if !feature.name.isEmpty, feature.isContained(by: request.message) { try await writer.write(feature) @@ -89,9 +89,9 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { } func recordRoute( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Single { + ) async throws -> ServerResponse { let startTime = ContinuousClock.now var pointsVisited = 0 var featuresVisited = 0 @@ -120,14 +120,14 @@ struct RouteGuideService: Routeguide_RouteGuide.ServiceProtocol { $0.distance = Int32(distanceTravelled) } - return ServerResponse.Single(message: summary) + return ServerResponse(message: summary) } func routeChat( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext - ) async throws -> ServerResponse.Stream { - return ServerResponse.Stream { writer in + ) async throws -> StreamingServerResponse { + return StreamingServerResponse { writer in for try await note in request.messages { let notes = self.receivedNotes.recordNote(note) try await writer.write(contentsOf: notes) diff --git a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Route-Guide.tutorial b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Route-Guide.tutorial index 0380b6540..ef4f3809f 100644 --- a/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Route-Guide.tutorial +++ b/Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Route-Guide.tutorial @@ -242,14 +242,14 @@ @Step { `GetFeature` is a unary RPC which takes a single point as input and returns a single feature back to the client. Its generated method, `getFeature`, has one parameter: - `ServerRequest.Single` describing the request. To return our response to + `ServerRequest` describing the request. To return our response to the client and complete the call we must first lookup a feature at the given point. @Code(name: "Sources/RouteGuideService.swift", file: "route-guide-sec04-step04-unary.swift") } @Step { - Then create and return an appropriate `ServerResponse.Single` to the + Then create and return an appropriate `ServerResponse` to the client. @Code(name: "Sources/RouteGuideService.swift", file: "route-guide-sec04-step05-unary.swift") @@ -257,11 +257,11 @@ @Step { Next, let's look at one of our streaming RPCs. Like the unary RPC, this method gets a - request object, `ServerRequest.Single`, which has a message describing + request object, `ServerRequest`, which has a message describing the area in which the client wants to list features. As this is a server-side streaming RPC we can send back multiple `Routeguide_Feature` messages to our client. - To implement the method we must return a `ServerResponse.Stream` which is initialized with + To implement the method we must return a `StreamingServerResponse` which is initialized with a closure to produce messages. The closure is passed a writer allowing you to write back messages. We can write back a message for each feature we find in the rectangle. @@ -280,8 +280,8 @@ method `RecordRoute`, where we get a stream of `Routeguide_Point`s from the client and return a single `Routeguide_RouteSummary` with information about their trip. - As you can see our method gets a `ServerRequest.Stream` parameter and - returns a `ServerResponse.Single`. In the method we iterate over + As you can see our method gets a `StreamingServerRequest` parameter and + returns a `ServerResponse`. In the method we iterate over the asynchronous stream of points sent by the client. For each point we check if there's a feature at that point and calculate the distance between that and the last point we saw. After the *client* has finished sending points we populate a `Routeguide_RouteSummary` which @@ -300,7 +300,7 @@ } @Step { - To implement the RPC we return a `ServerResponse.Stream`. Like in the + To implement the RPC we return a `StreamingServerResponse`. Like in the server-side streaming RPC it's initialized with a closure for writing back messages. In the body of the closure we iterate the request messages and for each one call our helper class to record the note and get all other notes recorded in the same location. We then diff --git a/Sources/GRPCCore/GRPCClient.swift b/Sources/GRPCCore/GRPCClient.swift index a3f9fe2d9..31a1aed67 100644 --- a/Sources/GRPCCore/GRPCClient.swift +++ b/Sources/GRPCCore/GRPCClient.swift @@ -89,7 +89,7 @@ private import Synchronization /// /// // Execute a request against the "echo.Echo" service. /// try await client.unary( -/// request: ClientRequest.Single<[UInt8]>(message: [72, 101, 108, 108, 111, 33]), +/// request: ClientRequest<[UInt8]>(message: [72, 101, 108, 108, 111, 33]), /// descriptor: MethodDescriptor(service: "echo.Echo", method: "Get"), /// serializer: IdentitySerializer(), /// deserializer: IdentityDeserializer(), @@ -256,21 +256,21 @@ public final class GRPCClient: Sendable { /// /// - Returns: The return value from the `handler`. public func unary( - request: ClientRequest.Single, + request: ClientRequest, descriptor: MethodDescriptor, serializer: some MessageSerializer, deserializer: some MessageDeserializer, options: CallOptions, - handler: @Sendable @escaping (ClientResponse.Single) async throws -> ReturnValue + handler: @Sendable @escaping (ClientResponse) async throws -> ReturnValue ) async throws -> ReturnValue { try await self.bidirectionalStreaming( - request: ClientRequest.Stream(single: request), + request: StreamingClientRequest(single: request), descriptor: descriptor, serializer: serializer, deserializer: deserializer, options: options ) { stream in - let singleResponse = await ClientResponse.Single(stream: stream) + let singleResponse = await ClientResponse(stream: stream) return try await handler(singleResponse) } } @@ -287,12 +287,12 @@ public final class GRPCClient: Sendable { /// /// - Returns: The return value from the `handler`. public func clientStreaming( - request: ClientRequest.Stream, + request: StreamingClientRequest, descriptor: MethodDescriptor, serializer: some MessageSerializer, deserializer: some MessageDeserializer, options: CallOptions, - handler: @Sendable @escaping (ClientResponse.Single) async throws -> ReturnValue + handler: @Sendable @escaping (ClientResponse) async throws -> ReturnValue ) async throws -> ReturnValue { try await self.bidirectionalStreaming( request: request, @@ -301,7 +301,7 @@ public final class GRPCClient: Sendable { deserializer: deserializer, options: options ) { stream in - let singleResponse = await ClientResponse.Single(stream: stream) + let singleResponse = await ClientResponse(stream: stream) return try await handler(singleResponse) } } @@ -318,15 +318,15 @@ public final class GRPCClient: Sendable { /// /// - Returns: The return value from the `handler`. public func serverStreaming( - request: ClientRequest.Single, + request: ClientRequest, descriptor: MethodDescriptor, serializer: some MessageSerializer, deserializer: some MessageDeserializer, options: CallOptions, - handler: @Sendable @escaping (ClientResponse.Stream) async throws -> ReturnValue + handler: @Sendable @escaping (StreamingClientResponse) async throws -> ReturnValue ) async throws -> ReturnValue { try await self.bidirectionalStreaming( - request: ClientRequest.Stream(single: request), + request: StreamingClientRequest(single: request), descriptor: descriptor, serializer: serializer, deserializer: deserializer, @@ -350,12 +350,12 @@ public final class GRPCClient: Sendable { /// /// - Returns: The return value from the `handler`. public func bidirectionalStreaming( - request: ClientRequest.Stream, + request: StreamingClientRequest, descriptor: MethodDescriptor, serializer: some MessageSerializer, deserializer: some MessageDeserializer, options: CallOptions, - handler: @Sendable @escaping (ClientResponse.Stream) async throws -> ReturnValue + handler: @Sendable @escaping (StreamingClientResponse) async throws -> ReturnValue ) async throws -> ReturnValue { try self.state.withLock { try $0.checkExecutable() } let methodConfig = self.transport.config(forMethod: descriptor) diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift index 17b50ad0b..129db4c26 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ClientCodeTranslatorSnippetBasedTests.swift @@ -47,19 +47,19 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_ClientProtocol: Sendable { /// Documentation for MethodA func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R ) async throws -> R where R: Sendable } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ClientProtocol { public func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -79,11 +79,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { _ message: NamespaceA_ServiceARequest, metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> Result = { + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { try $0.message } ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Single( + let request = GRPCCore.ClientRequest( message: message, metadata: metadata ) @@ -105,11 +105,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodA public func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -154,19 +154,19 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_ClientProtocol: Sendable { /// Documentation for MethodA func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R ) async throws -> R where R: Sendable } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ClientProtocol { public func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -186,11 +186,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, requestProducer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> Result = { + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { try $0.message } ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Stream( + let request = GRPCCore.StreamingClientRequest( metadata: metadata, producer: requestProducer ) @@ -212,11 +212,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodA public func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -261,19 +261,19 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_ClientProtocol: Sendable { /// Documentation for MethodA func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ClientProtocol { public func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable { try await self.methodA( request: request, @@ -291,9 +291,9 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { _ message: NamespaceA_ServiceARequest, metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> Result + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Single( + let request = GRPCCore.ClientRequest( message: message, metadata: metadata ) @@ -315,11 +315,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodA public func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable { try await self.client.serverStreaming( request: request, @@ -362,19 +362,19 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_ClientProtocol: Sendable { /// Documentation for MethodA func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ClientProtocol { public func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable { try await self.methodA( request: request, @@ -392,9 +392,9 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, requestProducer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> Result + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Stream( + let request = GRPCCore.StreamingClientRequest( metadata: metadata, producer: requestProducer ) @@ -416,11 +416,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodA public func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable { try await self.client.bidirectionalStreaming( request: request, @@ -471,28 +471,28 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { package protocol NamespaceA_ServiceA_ClientProtocol: Sendable { /// Documentation for MethodA func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R ) async throws -> R where R: Sendable /// Documentation for MethodB func methodB( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ClientProtocol { package func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -506,9 +506,9 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { } package func methodB( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable { try await self.methodB( request: request, @@ -526,11 +526,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, requestProducer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> Result = { + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { try $0.message } ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Stream( + let request = GRPCCore.StreamingClientRequest( metadata: metadata, producer: requestProducer ) @@ -546,9 +546,9 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { _ message: NamespaceA_ServiceARequest, metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> Result + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Single( + let request = GRPCCore.ClientRequest( message: message, metadata: metadata ) @@ -570,11 +570,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodA package func methodA( - request: GRPCCore.ClientRequest.Stream, + request: GRPCCore.StreamingClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -590,11 +590,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodB package func methodB( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Stream) async throws -> R + _ body: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> R ) async throws -> R where R: Sendable { try await self.client.serverStreaming( request: request, @@ -637,19 +637,19 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { internal protocol ServiceA_ClientProtocol: Sendable { /// Documentation for MethodA func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R ) async throws -> R where R: Sendable } @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension ServiceA.ClientProtocol { internal func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { @@ -669,11 +669,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { _ message: ServiceARequest, metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> Result = { + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { try $0.message } ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest.Single( + let request = GRPCCore.ClientRequest( message: message, metadata: metadata ) @@ -695,11 +695,11 @@ final class ClientCodeTranslatorSnippetBasedTests: XCTestCase { /// Documentation for MethodA internal func methodA( - request: GRPCCore.ClientRequest.Single, + request: GRPCCore.ClientRequest, serializer: some GRPCCore.MessageSerializer, deserializer: some GRPCCore.MessageDeserializer, options: GRPCCore.CallOptions = .defaults, - _ body: @Sendable @escaping (GRPCCore.ClientResponse.Single) async throws -> R = { + _ body: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> R = { try $0.message } ) async throws -> R where R: Sendable { diff --git a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift index 9125eea40..d2b0f624c 100644 --- a/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift +++ b/Tests/GRPCCodeGenTests/Internal/Translator/ServerCodeTranslatorSnippetBasedTests.swift @@ -55,9 +55,9 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for unaryMethod func unary( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -82,22 +82,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for unaryMethod func unary( - request: GRPCCore.ServerRequest.Single, + request: GRPCCore.ServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Single + ) async throws -> GRPCCore.ServerResponse } /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { public func unary( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream { + ) async throws -> GRPCCore.StreamingServerResponse { let response = try await self.unary( - request: GRPCCore.ServerRequest.Single(stream: request), + request: GRPCCore.ServerRequest(stream: request), context: context ) - return GRPCCore.ServerResponse.Stream(single: response) + return GRPCCore.StreamingServerResponse(single: response) } } """ @@ -139,9 +139,9 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { package protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for inputStreamingMethod func inputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -166,22 +166,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { package protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for inputStreamingMethod func inputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Single + ) async throws -> GRPCCore.ServerResponse } /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { package func inputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream { + ) async throws -> GRPCCore.StreamingServerResponse { let response = try await self.inputStreaming( request: request, context: context ) - return GRPCCore.ServerResponse.Stream(single: response) + return GRPCCore.StreamingServerResponse(single: response) } } """ @@ -227,9 +227,9 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for outputStreamingMethod func outputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -254,19 +254,19 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { public protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for outputStreamingMethod func outputStreaming( - request: GRPCCore.ServerRequest.Single, + request: GRPCCore.ServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { public func outputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream { + ) async throws -> GRPCCore.StreamingServerResponse { let response = try await self.outputStreaming( - request: GRPCCore.ServerRequest.Single(stream: request), + request: GRPCCore.ServerRequest(stream: request), context: context ) return response @@ -315,9 +315,9 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { package protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for bidirectionalStreamingMethod func bidirectionalStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -342,9 +342,9 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { package protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for bidirectionalStreamingMethod func bidirectionalStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -405,15 +405,15 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { internal protocol NamespaceA_ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for inputStreamingMethod func inputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse /// Documentation for outputStreamingMethod func outputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -449,36 +449,36 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { internal protocol NamespaceA_ServiceA_ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol { /// Documentation for inputStreamingMethod func inputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Single + ) async throws -> GRPCCore.ServerResponse /// Documentation for outputStreamingMethod func outputStreaming( - request: GRPCCore.ServerRequest.Single, + request: GRPCCore.ServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Partial conformance to `NamespaceA_ServiceA_StreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension NamespaceA_ServiceA.ServiceProtocol { internal func inputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream { + ) async throws -> GRPCCore.StreamingServerResponse { let response = try await self.inputStreaming( request: request, context: context ) - return GRPCCore.ServerResponse.Stream(single: response) + return GRPCCore.StreamingServerResponse(single: response) } internal func outputStreaming( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream { + ) async throws -> GRPCCore.StreamingServerResponse { let response = try await self.outputStreaming( - request: GRPCCore.ServerRequest.Single(stream: request), + request: GRPCCore.ServerRequest(stream: request), context: context ) return response @@ -519,9 +519,9 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { internal protocol ServiceA_StreamingServiceProtocol: GRPCCore.RegistrableRPCService { /// Documentation for MethodA func methodA( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream + ) async throws -> GRPCCore.StreamingServerResponse } /// Conformance to `GRPCCore.RegistrableRPCService`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) @@ -546,22 +546,22 @@ final class ServerCodeTranslatorSnippetBasedTests: XCTestCase { internal protocol ServiceA_ServiceProtocol: ServiceA.StreamingServiceProtocol { /// Documentation for MethodA func methodA( - request: GRPCCore.ServerRequest.Single, + request: GRPCCore.ServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Single + ) async throws -> GRPCCore.ServerResponse } /// Partial conformance to `ServiceA_StreamingServiceProtocol`. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) extension ServiceA.ServiceProtocol { internal func methodA( - request: GRPCCore.ServerRequest.Stream, + request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse.Stream { + ) async throws -> GRPCCore.StreamingServerResponse { let response = try await self.methodA( - request: GRPCCore.ServerRequest.Single(stream: request), + request: GRPCCore.ServerRequest(stream: request), context: context ) - return GRPCCore.ServerResponse.Stream(single: response) + return GRPCCore.StreamingServerResponse(single: response) } } """ diff --git a/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift b/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift index 7d0304260..5e802a622 100644 --- a/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/ClientRequestTests.swift @@ -22,8 +22,8 @@ import XCTest final class ClientRequestTests: XCTestCase { func testSingleToStreamConversion() async throws { let (messages, continuation) = AsyncStream.makeStream(of: String.self) - let single = ClientRequest.Single(message: "foo", metadata: ["bar": "baz"]) - let stream = ClientRequest.Stream(single: single) + let single = ClientRequest(message: "foo", metadata: ["bar": "baz"]) + let stream = StreamingClientRequest(single: single) XCTAssertEqual(stream.metadata, ["bar": "baz"]) try await stream.producer(.gathering(into: continuation)) diff --git a/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift b/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift index a284112be..d0fcf3611 100644 --- a/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/ClientResponseTests.swift @@ -21,7 +21,7 @@ import XCTest @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) final class ClientResponseTests: XCTestCase { func testAcceptedSingleResponseConvenienceMethods() { - let response = ClientResponse.Single( + let response = ClientResponse( message: "message", metadata: ["foo": "bar"], trailingMetadata: ["bar": "baz"] @@ -34,7 +34,7 @@ final class ClientResponseTests: XCTestCase { func testRejectedSingleResponseConvenienceMethods() { let error = RPCError(code: .aborted, message: "error message", metadata: ["bar": "baz"]) - let response = ClientResponse.Single(of: String.self, error: error) + let response = ClientResponse(of: String.self, error: error) XCTAssertEqual(response.metadata, [:]) XCTAssertThrowsRPCError(try response.message) { @@ -45,7 +45,7 @@ final class ClientResponseTests: XCTestCase { func testAcceptedButFailedSingleResponseConvenienceMethods() { let error = RPCError(code: .aborted, message: "error message", metadata: ["bar": "baz"]) - let response = ClientResponse.Single(of: String.self, metadata: ["foo": "bar"], error: error) + let response = ClientResponse(of: String.self, metadata: ["foo": "bar"], error: error) XCTAssertEqual(response.metadata, ["foo": "bar"]) XCTAssertThrowsRPCError(try response.message) { @@ -55,7 +55,7 @@ final class ClientResponseTests: XCTestCase { } func testAcceptedStreamResponseConvenienceMethods() async throws { - let response = ClientResponse.Stream( + let response = StreamingClientResponse( of: String.self, metadata: ["foo": "bar"], bodyParts: RPCAsyncSequence( @@ -76,7 +76,7 @@ final class ClientResponseTests: XCTestCase { func testRejectedStreamResponseConvenienceMethods() async throws { let error = RPCError(code: .aborted, message: "error message", metadata: ["bar": "baz"]) - let response = ClientResponse.Stream(of: String.self, error: error) + let response = StreamingClientResponse(of: String.self, error: error) XCTAssertEqual(response.metadata, [:]) await XCTAssertThrowsRPCErrorAsync { @@ -87,13 +87,13 @@ final class ClientResponseTests: XCTestCase { } func testStreamToSingleConversionForValidStream() async throws { - let stream = ClientResponse.Stream( + let stream = StreamingClientResponse( of: String.self, metadata: ["foo": "bar"], bodyParts: .elements(.message("foo"), .trailingMetadata(["bar": "baz"])) ) - let single = await ClientResponse.Single(stream: stream) + let single = await ClientResponse(stream: stream) XCTAssertEqual(single.metadata, ["foo": "bar"]) XCTAssertEqual(try single.message, "foo") XCTAssertEqual(single.trailingMetadata, ["bar": "baz"]) @@ -101,9 +101,9 @@ final class ClientResponseTests: XCTestCase { func testStreamToSingleConversionForFailedStream() async throws { let error = RPCError(code: .aborted, message: "aborted", metadata: ["bar": "baz"]) - let stream = ClientResponse.Stream(of: String.self, error: error) + let stream = StreamingClientResponse(of: String.self, error: error) - let single = await ClientResponse.Single(stream: stream) + let single = await ClientResponse(stream: stream) XCTAssertEqual(single.metadata, [:]) XCTAssertThrowsRPCError(try single.message) { XCTAssertEqual($0, error) @@ -112,19 +112,19 @@ final class ClientResponseTests: XCTestCase { } func testStreamToSingleConversionForInvalidSingleStream() async throws { - let bodies: [[ClientResponse.Stream.Contents.BodyPart]] = [ + let bodies: [[StreamingClientResponse.Contents.BodyPart]] = [ [.message("1"), .message("2")], // Too many messages. [.trailingMetadata([:])], // Too few messages ] for body in bodies { - let stream = ClientResponse.Stream( + let stream = StreamingClientResponse( of: String.self, metadata: ["foo": "bar"], bodyParts: .elements(body) ) - let single = await ClientResponse.Single(stream: stream) + let single = await ClientResponse(stream: stream) XCTAssertEqual(single.metadata, [:]) XCTAssertThrowsRPCError(try single.message) { error in XCTAssertEqual(error.code, .unimplemented) @@ -134,20 +134,20 @@ final class ClientResponseTests: XCTestCase { } func testStreamToSingleConversionForInvalidStream() async throws { - let bodies: [[ClientResponse.Stream.Contents.BodyPart]] = [ + let bodies: [[StreamingClientResponse.Contents.BodyPart]] = [ [], // Empty stream [.trailingMetadata([:]), .trailingMetadata([:])], // Multiple metadatas [.trailingMetadata([:]), .message("")], // Metadata then message ] for body in bodies { - let stream = ClientResponse.Stream( + let stream = StreamingClientResponse( of: String.self, metadata: ["foo": "bar"], bodyParts: .elements(body) ) - let single = await ClientResponse.Single(stream: stream) + let single = await ClientResponse(stream: stream) XCTAssertEqual(single.metadata, [:]) XCTAssertThrowsRPCError(try single.message) { error in XCTAssertEqual(error.code, .internalError) @@ -158,26 +158,26 @@ final class ClientResponseTests: XCTestCase { func testStreamToSingleConversionForStreamThrowingRPCError() async throws { let error = RPCError(code: .dataLoss, message: "oops") - let stream = ClientResponse.Stream( + let stream = StreamingClientResponse( of: String.self, metadata: [:], bodyParts: .throwing(error) ) - let single = await ClientResponse.Single(stream: stream) + let single = await ClientResponse(stream: stream) XCTAssertThrowsRPCError(try single.message) { XCTAssertEqual($0, error) } } func testStreamToSingleConversionForStreamThrowingUnknownError() async throws { - let stream = ClientResponse.Stream( + let stream = StreamingClientResponse( of: String.self, metadata: [:], bodyParts: .throwing(CancellationError()) ) - let single = await ClientResponse.Single(stream: stream) + let single = await ClientResponse(stream: stream) XCTAssertThrowsRPCError(try single.message) { error in XCTAssertEqual(error.code, .unknown) } diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift index 7bfef6912..4ead582fd 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTestSupport/ClientRPCExecutorTestHarness.swift @@ -67,41 +67,45 @@ struct ClientRPCExecutorTestHarness { } func unary( - request: ClientRequest.Single<[UInt8]>, + request: ClientRequest<[UInt8]>, options: CallOptions = .defaults, - handler: @escaping @Sendable (ClientResponse.Single<[UInt8]>) async throws -> Void + handler: @escaping @Sendable (ClientResponse<[UInt8]>) async throws -> Void ) async throws { - try await self.bidirectional(request: ClientRequest.Stream(single: request), options: options) { - response in - try await handler(ClientResponse.Single(stream: response)) + try await self.bidirectional( + request: StreamingClientRequest(single: request), + options: options + ) { response in + try await handler(ClientResponse(stream: response)) } } func clientStreaming( - request: ClientRequest.Stream<[UInt8]>, + request: StreamingClientRequest<[UInt8]>, options: CallOptions = .defaults, - handler: @escaping @Sendable (ClientResponse.Single<[UInt8]>) async throws -> Void + handler: @escaping @Sendable (ClientResponse<[UInt8]>) async throws -> Void ) async throws { try await self.bidirectional(request: request, options: options) { response in - try await handler(ClientResponse.Single(stream: response)) + try await handler(ClientResponse(stream: response)) } } func serverStreaming( - request: ClientRequest.Single<[UInt8]>, + request: ClientRequest<[UInt8]>, options: CallOptions = .defaults, - handler: @escaping @Sendable (ClientResponse.Stream<[UInt8]>) async throws -> Void + handler: @escaping @Sendable (StreamingClientResponse<[UInt8]>) async throws -> Void ) async throws { - try await self.bidirectional(request: ClientRequest.Stream(single: request), options: options) { - response in + try await self.bidirectional( + request: StreamingClientRequest(single: request), + options: options + ) { response in try await handler(response) } } func bidirectional( - request: ClientRequest.Stream<[UInt8]>, + request: StreamingClientRequest<[UInt8]>, options: CallOptions = .defaults, - handler: @escaping @Sendable (ClientResponse.Stream<[UInt8]>) async throws -> Void + handler: @escaping @Sendable (StreamingClientResponse<[UInt8]>) async throws -> Void ) async throws { try await self.execute( request: request, @@ -113,11 +117,11 @@ struct ClientRPCExecutorTestHarness { } private func execute( - request: ClientRequest.Stream, + request: StreamingClientRequest, serializer: some MessageSerializer, deserializer: some MessageDeserializer, options: CallOptions, - handler: @escaping @Sendable (ClientResponse.Stream) async throws -> Void + handler: @escaping @Sendable (StreamingClientResponse) async throws -> Void ) async throws { try await withThrowingTaskGroup(of: Void.self) { group in group.addTask { diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift index 6dceb9976..ae924eea8 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Hedging.swift @@ -24,7 +24,7 @@ extension ClientRPCExecutorTests { ) try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -48,7 +48,7 @@ extension ClientRPCExecutorTests { ) try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -84,7 +84,7 @@ extension ClientRPCExecutorTests { let start = ContinuousClock.now try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -128,7 +128,7 @@ extension ClientRPCExecutorTests { let start = ContinuousClock.now try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -169,7 +169,7 @@ extension ClientRPCExecutorTests { ) try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) }, options: .hedge(delay: .seconds(60), nonFatalCodes: [.unavailable]) diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift index 6c2e6cd1e..2c5ab960d 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests+Retries.swift @@ -44,7 +44,7 @@ extension ClientRPCExecutorTests { consumeInboundStream: true ) try await harness.bidirectional( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -70,7 +70,7 @@ extension ClientRPCExecutorTests { func testRetriesRespectRetryableCodes() async throws { let harness = self.makeHarnessForRetries(rejectUntilAttempt: 3, withCode: .unavailable) try await harness.bidirectional( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([0, 1, 2]) }, options: .retry(codes: [.aborted]) @@ -91,7 +91,7 @@ extension ClientRPCExecutorTests { func testRetriesRespectRetryLimit() async throws { let harness = self.makeHarnessForRetries(rejectUntilAttempt: 5, withCode: .unavailable) try await harness.bidirectional( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([0, 1, 2]) }, options: .retry(maximumAttempts: 2, codes: [.unavailable]) @@ -118,7 +118,7 @@ extension ClientRPCExecutorTests { ) try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { for _ in 0 ..< 1000 { try await $0.write([]) } @@ -148,7 +148,7 @@ extension ClientRPCExecutorTests { await XCTAssertThrowsErrorAsync { try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -169,7 +169,7 @@ extension ClientRPCExecutorTests { await XCTAssertThrowsErrorAsync { try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -193,7 +193,7 @@ extension ClientRPCExecutorTests { await XCTAssertThrowsErrorAsync { try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) try await $0.write([1]) try await $0.write([2]) @@ -233,7 +233,7 @@ extension ClientRPCExecutorTests { let start = ContinuousClock.now try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) }, options: .retry(retryPolicy) @@ -269,7 +269,7 @@ extension ClientRPCExecutorTests { ) try await harness.bidirectional( - request: ClientRequest.Stream { + request: StreamingClientRequest { try await $0.write([0]) }, options: .retry(retryPolicy) diff --git a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift index c2396fdef..310486aa3 100644 --- a/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift +++ b/Tests/GRPCCoreTests/Call/Client/Internal/ClientRPCExecutorTests.swift @@ -23,7 +23,7 @@ final class ClientRPCExecutorTests: XCTestCase { func testUnaryEcho() async throws { let tester = ClientRPCExecutorTestHarness(server: .echo) try await tester.unary( - request: ClientRequest.Single(message: [1, 2, 3], metadata: ["foo": "bar"]) + request: ClientRequest(message: [1, 2, 3], metadata: ["foo": "bar"]) ) { response in XCTAssertEqual(response.metadata, ["foo": "bar"]) XCTAssertEqual(try response.message, [1, 2, 3]) @@ -36,7 +36,7 @@ final class ClientRPCExecutorTests: XCTestCase { func testClientStreamingEcho() async throws { let tester = ClientRPCExecutorTestHarness(server: .echo) try await tester.clientStreaming( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([1, 2, 3]) } ) { response in @@ -51,7 +51,7 @@ final class ClientRPCExecutorTests: XCTestCase { func testServerStreamingEcho() async throws { let tester = ClientRPCExecutorTestHarness(server: .echo) try await tester.serverStreaming( - request: ClientRequest.Single(message: [1, 2, 3], metadata: ["foo": "bar"]) + request: ClientRequest(message: [1, 2, 3], metadata: ["foo": "bar"]) ) { response in XCTAssertEqual(response.metadata, ["foo": "bar"]) let messages = try await response.messages.collect() @@ -65,7 +65,7 @@ final class ClientRPCExecutorTests: XCTestCase { func testBidirectionalStreamingEcho() async throws { let tester = ClientRPCExecutorTestHarness(server: .echo) try await tester.bidirectional( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([1, 2, 3]) } ) { response in @@ -82,7 +82,7 @@ final class ClientRPCExecutorTests: XCTestCase { let error = RPCError(code: .unauthenticated, message: "", metadata: ["metadata": "error"]) let tester = ClientRPCExecutorTestHarness(server: .reject(withError: error)) try await tester.unary( - request: ClientRequest.Single(message: [1, 2, 3], metadata: ["foo": "bar"]) + request: ClientRequest(message: [1, 2, 3], metadata: ["foo": "bar"]) ) { response in XCTAssertThrowsRPCError(try response.message) { XCTAssertEqual($0, error) @@ -97,7 +97,7 @@ final class ClientRPCExecutorTests: XCTestCase { let error = RPCError(code: .unauthenticated, message: "", metadata: ["metadata": "error"]) let tester = ClientRPCExecutorTestHarness(server: .reject(withError: error)) try await tester.clientStreaming( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([1, 2, 3]) } ) { response in @@ -114,7 +114,7 @@ final class ClientRPCExecutorTests: XCTestCase { let error = RPCError(code: .unauthenticated, message: "", metadata: ["metadata": "error"]) let tester = ClientRPCExecutorTestHarness(server: .reject(withError: error)) try await tester.serverStreaming( - request: ClientRequest.Single(message: [1, 2, 3], metadata: ["foo": "bar"]) + request: ClientRequest(message: [1, 2, 3], metadata: ["foo": "bar"]) ) { response in await XCTAssertThrowsRPCErrorAsync { try await response.messages.collect() @@ -131,7 +131,7 @@ final class ClientRPCExecutorTests: XCTestCase { let error = RPCError(code: .unauthenticated, message: "", metadata: ["metadata": "error"]) let tester = ClientRPCExecutorTestHarness(server: .reject(withError: error)) try await tester.bidirectional( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([1, 2, 3]) } ) { response in @@ -154,7 +154,7 @@ final class ClientRPCExecutorTests: XCTestCase { await XCTAssertThrowsRPCErrorAsync { try await tester.unary( - request: ClientRequest.Single(message: [1, 2, 3], metadata: ["foo": "bar"]) + request: ClientRequest(message: [1, 2, 3], metadata: ["foo": "bar"]) ) { _ in } } errorHandler: { error in XCTAssertEqual(error.code, .aborted) @@ -173,7 +173,7 @@ final class ClientRPCExecutorTests: XCTestCase { await XCTAssertThrowsRPCErrorAsync { try await tester.clientStreaming( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([1, 2, 3]) } ) { _ in } @@ -194,7 +194,7 @@ final class ClientRPCExecutorTests: XCTestCase { await XCTAssertThrowsRPCErrorAsync { try await tester.serverStreaming( - request: ClientRequest.Single(message: [1, 2, 3], metadata: ["foo": "bar"]) + request: ClientRequest(message: [1, 2, 3], metadata: ["foo": "bar"]) ) { _ in } } errorHandler: { XCTAssertEqual($0.code, .aborted) @@ -213,7 +213,7 @@ final class ClientRPCExecutorTests: XCTestCase { await XCTAssertThrowsRPCErrorAsync { try await tester.bidirectional( - request: ClientRequest.Stream(metadata: ["foo": "bar"]) { + request: StreamingClientRequest(metadata: ["foo": "bar"]) { try await $0.write([1, 2, 3]) } ) { _ in } @@ -254,7 +254,7 @@ final class ClientRPCExecutorTests: XCTestCase { let tester = ClientRPCExecutorTestHarness(transport: .inProcess, server: .echo) try await tester.unary( - request: ClientRequest.Single(message: []), + request: ClientRequest(message: []), options: options ) { response in let timeoutMetadata = Array(response.metadata[stringValues: "grpc-timeout"]) diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift index 8d7e0a543..f53c46232 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift @@ -20,19 +20,20 @@ import XCTest @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) struct ServerRPCExecutorTestHarness { struct ServerHandler: Sendable { - let fn: @Sendable (ServerRequest.Stream) async throws -> ServerResponse.Stream + let fn: + @Sendable (StreamingServerRequest) async throws -> StreamingServerResponse init( _ fn: @escaping @Sendable ( - ServerRequest.Stream - ) async throws -> ServerResponse.Stream + StreamingServerRequest + ) async throws -> StreamingServerResponse ) { self.fn = fn } func handle( - _ request: ServerRequest.Stream - ) async throws -> ServerResponse.Stream { + _ request: StreamingServerRequest + ) async throws -> StreamingServerResponse { try await self.fn(request) } @@ -51,8 +52,8 @@ struct ServerRPCExecutorTestHarness { deserializer: some MessageDeserializer, serializer: some MessageSerializer, handler: @escaping @Sendable ( - ServerRequest.Stream - ) async throws -> ServerResponse.Stream, + StreamingServerRequest + ) async throws -> StreamingServerResponse, producer: @escaping @Sendable ( RPCWriter.Closable ) async throws -> Void, @@ -137,7 +138,7 @@ struct ServerRPCExecutorTestHarness { extension ServerRPCExecutorTestHarness.ServerHandler where Input == Output { static var echo: Self { return Self { request in - return ServerResponse.Stream(metadata: request.metadata) { writer in + return StreamingServerResponse(metadata: request.metadata) { writer in try await writer.write(contentsOf: request.messages) return [:] } diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift index 5d2aa0029..df894dd8e 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift @@ -87,7 +87,7 @@ final class ServerRPCExecutorTests: XCTestCase { ) { request in let messages = try await request.messages.collect() XCTAssertEqual(messages, ["hello"]) - return ServerResponse.Stream(metadata: request.metadata) { writer in + return StreamingServerResponse(metadata: request.metadata) { writer in try await writer.write("hello") return [:] } @@ -116,7 +116,7 @@ final class ServerRPCExecutorTests: XCTestCase { ) { request in let messages = try await request.messages.collect() XCTAssertEqual(messages, ["hello", "world"]) - return ServerResponse.Stream(metadata: request.metadata) { writer in + return StreamingServerResponse(metadata: request.metadata) { writer in try await writer.write("hello") try await writer.write("world") return [:] @@ -146,7 +146,7 @@ final class ServerRPCExecutorTests: XCTestCase { deserializer: IdentityDeserializer(), serializer: IdentitySerializer() ) { request in - return ServerResponse.Stream(metadata: request.metadata) { _ in + return StreamingServerResponse(metadata: request.metadata) { _ in return ["bar": "baz"] } } producer: { inbound in @@ -244,7 +244,7 @@ final class ServerRPCExecutorTests: XCTestCase { } XCTFail("Server handler should've been cancelled by timeout.") - return ServerResponse.Stream(error: RPCError(code: .failedPrecondition, message: "")) + return StreamingServerResponse(error: RPCError(code: .failedPrecondition, message: "")) } producer: { inbound in try await inbound.write(.metadata(["grpc-timeout": "1000n"])) await inbound.finish() @@ -271,7 +271,7 @@ final class ServerRPCExecutorTests: XCTestCase { serializer: IdentitySerializer() ) { request in XCTFail("Unexpected request") - return ServerResponse.Stream( + return StreamingServerResponse( of: [UInt8].self, error: RPCError(code: .failedPrecondition, message: "") ) diff --git a/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift b/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift index 532e5e51c..658a2855e 100644 --- a/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/ServerRequestTests.swift @@ -19,8 +19,8 @@ import XCTest @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) final class ServerRequestTests: XCTestCase { func testSingleToStreamConversion() async throws { - let single = ServerRequest.Single(metadata: ["bar": "baz"], message: "foo") - let stream = ServerRequest.Stream(single: single) + let single = ServerRequest(metadata: ["bar": "baz"], message: "foo") + let stream = StreamingServerRequest(single: single) XCTAssertEqual(stream.metadata, ["bar": "baz"]) let collected = try await stream.messages.collect() diff --git a/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift b/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift index d5614e906..02196a9dd 100644 --- a/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift +++ b/Tests/GRPCCoreTests/Call/Server/ServerResponseTests.swift @@ -19,7 +19,7 @@ import XCTest @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) final class ServerResponseTests: XCTestCase { func testSingleConvenienceInit() { - var response = ServerResponse.Single( + var response = ServerResponse( message: "message", metadata: ["metadata": "initial"], trailingMetadata: ["metadata": "trailing"] @@ -35,7 +35,7 @@ final class ServerResponseTests: XCTestCase { } let error = RPCError(code: .aborted, message: "Aborted") - response = ServerResponse.Single(of: String.self, error: error) + response = ServerResponse(of: String.self, error: error) switch response.accepted { case .success: XCTFail("Unexpected success") @@ -45,7 +45,10 @@ final class ServerResponseTests: XCTestCase { } func testStreamConvenienceInit() async throws { - var response = ServerResponse.Stream(of: String.self, metadata: ["metadata": "initial"]) { _ in + var response = StreamingServerResponse( + of: String.self, + metadata: ["metadata": "initial"] + ) { _ in // Empty body. return ["metadata": "trailing"] } @@ -60,7 +63,7 @@ final class ServerResponseTests: XCTestCase { } let error = RPCError(code: .aborted, message: "Aborted") - response = ServerResponse.Stream(of: String.self, error: error) + response = StreamingServerResponse(of: String.self, error: error) switch response.accepted { case .success: XCTFail("Unexpected success") @@ -70,13 +73,13 @@ final class ServerResponseTests: XCTestCase { } func testSingleToStreamConversionForSuccessfulResponse() async throws { - let single = ServerResponse.Single( + let single = ServerResponse( message: "foo", metadata: ["metadata": "initial"], trailingMetadata: ["metadata": "trailing"] ) - let stream = ServerResponse.Stream(single: single) + let stream = StreamingServerResponse(single: single) let (messages, continuation) = AsyncStream.makeStream(of: String.self) let trailingMetadata: Metadata @@ -96,8 +99,8 @@ final class ServerResponseTests: XCTestCase { func testSingleToStreamConversionForFailedResponse() async throws { let error = RPCError(code: .aborted, message: "aborted") - let single = ServerResponse.Single(of: String.self, error: error) - let stream = ServerResponse.Stream(single: single) + let single = ServerResponse(of: String.self, error: error) + let stream = StreamingServerResponse(single: single) XCTAssertThrowsRPCError(try stream.accepted.get()) { XCTAssertEqual($0, error) diff --git a/Tests/GRPCCoreTests/GRPCClientTests.swift b/Tests/GRPCCoreTests/GRPCClientTests.swift index b5558ae48..f55f921dd 100644 --- a/Tests/GRPCCoreTests/GRPCClientTests.swift +++ b/Tests/GRPCCoreTests/GRPCClientTests.swift @@ -356,7 +356,7 @@ final class GRPCClientTests: XCTestCase { let task = Task { try await client.clientStreaming( - request: ClientRequest.Stream { writer in + request: StreamingClientRequest { writer in try await Task.sleep(for: .seconds(5)) }, descriptor: BinaryEcho.Methods.collect, diff --git a/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift b/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift index a45d64fd5..dd73cb96d 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Call/Client/ClientInterceptors.swift @@ -50,17 +50,17 @@ struct RejectAllClientInterceptor: ClientInterceptor { } func intercept( - request: ClientRequest.Stream, + request: StreamingClientRequest, context: ClientContext, next: ( - ClientRequest.Stream, + StreamingClientRequest, ClientContext - ) async throws -> ClientResponse.Stream - ) async throws -> ClientResponse.Stream { + ) async throws -> StreamingClientResponse + ) async throws -> StreamingClientResponse { if self.throw { throw self.error } else { - return ClientResponse.Stream(error: self.error) + return StreamingClientResponse(error: self.error) } } } @@ -75,13 +75,13 @@ struct RequestCountingClientInterceptor: ClientInterceptor { } func intercept( - request: ClientRequest.Stream, + request: StreamingClientRequest, context: ClientContext, next: ( - ClientRequest.Stream, + StreamingClientRequest, ClientContext - ) async throws -> ClientResponse.Stream - ) async throws -> ClientResponse.Stream { + ) async throws -> StreamingClientResponse + ) async throws -> StreamingClientResponse { self.counter.increment() return try await next(request, context) } diff --git a/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift b/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift index 9a3dc96c7..1467cddad 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Call/Server/ServerInterceptors.swift @@ -49,17 +49,17 @@ struct RejectAllServerInterceptor: ServerInterceptor { } func intercept( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext, next: @Sendable ( - ServerRequest.Stream, + StreamingServerRequest, ServerContext - ) async throws -> ServerResponse.Stream - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse + ) async throws -> StreamingServerResponse { if self.throw { throw self.error } else { - return ServerResponse.Stream(error: self.error) + return StreamingServerResponse(error: self.error) } } } @@ -74,13 +74,13 @@ struct RequestCountingServerInterceptor: ServerInterceptor { } func intercept( - request: ServerRequest.Stream, + request: StreamingServerRequest, context: ServerContext, next: @Sendable ( - ServerRequest.Stream, + StreamingServerRequest, ServerContext - ) async throws -> ServerResponse.Stream - ) async throws -> ServerResponse.Stream { + ) async throws -> StreamingServerResponse + ) async throws -> StreamingServerResponse { self.counter.increment() return try await next(request, context) } diff --git a/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift b/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift index e5438c550..817539a9d 100644 --- a/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift +++ b/Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift @@ -19,22 +19,22 @@ import XCTest @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) struct BinaryEcho: RegistrableRPCService { func get( - _ request: ServerRequest.Single<[UInt8]> - ) async throws -> ServerResponse.Single<[UInt8]> { - ServerResponse.Single(message: request.message, metadata: request.metadata) + _ request: ServerRequest<[UInt8]> + ) async throws -> ServerResponse<[UInt8]> { + ServerResponse(message: request.message, metadata: request.metadata) } func collect( - _ request: ServerRequest.Stream<[UInt8]> - ) async throws -> ServerResponse.Single<[UInt8]> { + _ request: StreamingServerRequest<[UInt8]> + ) async throws -> ServerResponse<[UInt8]> { let collected = try await request.messages.reduce(into: []) { $0.append(contentsOf: $1) } - return ServerResponse.Single(message: collected, metadata: request.metadata) + return ServerResponse(message: collected, metadata: request.metadata) } func expand( - _ request: ServerRequest.Single<[UInt8]> - ) async throws -> ServerResponse.Stream<[UInt8]> { - return ServerResponse.Stream(metadata: request.metadata) { + _ request: ServerRequest<[UInt8]> + ) async throws -> StreamingServerResponse<[UInt8]> { + return StreamingServerResponse(metadata: request.metadata) { for byte in request.message { try await $0.write([byte]) } @@ -43,9 +43,9 @@ struct BinaryEcho: RegistrableRPCService { } func update( - _ request: ServerRequest.Stream<[UInt8]> - ) async throws -> ServerResponse.Stream<[UInt8]> { - return ServerResponse.Stream(metadata: request.metadata) { + _ request: StreamingServerRequest<[UInt8]> + ) async throws -> StreamingServerResponse<[UInt8]> { + return StreamingServerResponse(metadata: request.metadata) { for try await message in request.messages { try await $0.write(message) } @@ -62,9 +62,9 @@ struct BinaryEcho: RegistrableRPCService { deserializer: deserializer, serializer: serializer ) { streamRequest, context in - let singleRequest = try await ServerRequest.Single(stream: streamRequest) + let singleRequest = try await ServerRequest(stream: streamRequest) let singleResponse = try await self.get(singleRequest) - return ServerResponse.Stream(single: singleResponse) + return StreamingServerResponse(single: singleResponse) } router.registerHandler( @@ -73,7 +73,7 @@ struct BinaryEcho: RegistrableRPCService { serializer: serializer ) { streamRequest, context in let singleResponse = try await self.collect(streamRequest) - return ServerResponse.Stream(single: singleResponse) + return StreamingServerResponse(single: singleResponse) } router.registerHandler( @@ -81,7 +81,7 @@ struct BinaryEcho: RegistrableRPCService { deserializer: deserializer, serializer: serializer ) { streamRequest, context in - let singleRequest = try await ServerRequest.Single(stream: streamRequest) + let singleRequest = try await ServerRequest(stream: streamRequest) let streamResponse = try await self.expand(singleRequest) return streamResponse } diff --git a/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift b/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift index a6bb1ee50..400ab3037 100644 --- a/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift +++ b/Tests/GRPCCoreTests/Test Utilities/XCTest+Utilities.swift @@ -97,7 +97,7 @@ func XCTAssertThrowsRPCErrorAsync( @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *) func XCTAssertRejected( - _ response: ClientResponse.Stream, + _ response: StreamingClientResponse, errorHandler: (RPCError) -> Void ) { switch response.accepted { @@ -109,7 +109,7 @@ func XCTAssertRejected( } func XCTAssertRejected( - _ response: ClientResponse.Single, + _ response: ClientResponse, errorHandler: (RPCError) -> Void ) { switch response.accepted {