From be41136e21e793bab1e499f7188a9898c51427b2 Mon Sep 17 00:00:00 2001 From: Rick Newton-Rogers Date: Tue, 7 Jan 2025 15:22:46 +0000 Subject: [PATCH] Generate code file for protos with no definitions (#27) This change is broken out of https://github.com/grpc/grpc-swift-protobuf/pull/26 ### Motivation To prepare for use in a SwiftPM build plugin which requires deterministic output files and to match the behavior of `proto-gen-swift` we should generate a source file even if no definitions are found. ### Modifications: * We no longer return early in the case of no definitions being found. * Add empty proto file test * Add a preamble to `foo-messages.proto` * Don't unconditionally add a dependency on `GRPCProtobuf` if there are no services * Add the new test case code generation to `dev/protos/generate.sh` * Depend on `grpc-swift` `main` to pick up empty file generation changes. ### Result: We will generate a Swift source file even if no definitions are found. --- Package.swift | 2 +- .../ProtobufCodeGenParser.swift | 5 +- .../protoc-gen-grpc-swift/GenerateGRPC.swift | 4 - .../Generated/foo-messages.pb | Bin 0 -> 156 bytes .../Generated/foo-service.pb | Bin 502 -> 521 bytes .../ProtobufCodeGeneratorTests.swift | 1667 +++++++++-------- dev/protos/generate.sh | 12 + dev/protos/local/foo-messages.proto | 1 + 8 files changed, 874 insertions(+), 817 deletions(-) create mode 100644 Tests/GRPCProtobufCodeGenTests/Generated/foo-messages.pb diff --git a/Package.swift b/Package.swift index f059a2e..5c2d938 100644 --- a/Package.swift +++ b/Package.swift @@ -31,7 +31,7 @@ let products: [Product] = [ let dependencies: [Package.Dependency] = [ .package( url: "https://github.com/grpc/grpc-swift.git", - exact: "2.0.0-beta.2" + branch: "main" ), .package( url: "https://github.com/apple/swift-protobuf.git", diff --git a/Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift b/Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift index a502b96..0024d0d 100644 --- a/Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift +++ b/Sources/GRPCProtobufCodeGen/ProtobufCodeGenParser.swift @@ -98,10 +98,13 @@ package struct ProtobufCodeGenParser { extension ProtobufCodeGenParser { fileprivate func codeDependencies(file: FileDescriptor) -> [Dependency] { + guard file.services.count > 0 else { + return [] + } + var codeDependencies: [Dependency] = [ Dependency(module: "GRPCProtobuf", accessLevel: .internal) ] - // If there's a dependency on a bundled proto then add the SwiftProtobuf import. // // Importing SwiftProtobuf unconditionally results in warnings in the generated diff --git a/Sources/protoc-gen-grpc-swift/GenerateGRPC.swift b/Sources/protoc-gen-grpc-swift/GenerateGRPC.swift index c38ec83..336e173 100644 --- a/Sources/protoc-gen-grpc-swift/GenerateGRPC.swift +++ b/Sources/protoc-gen-grpc-swift/GenerateGRPC.swift @@ -63,10 +63,6 @@ final class GenerateGRPC: CodeGenerator { ) } - if descriptor.services.isEmpty { - continue - } - try self.generateV2Stubs(descriptor, options: options, outputs: outputs) } } diff --git a/Tests/GRPCProtobufCodeGenTests/Generated/foo-messages.pb b/Tests/GRPCProtobufCodeGenTests/Generated/foo-messages.pb new file mode 100644 index 0000000000000000000000000000000000000000..bc3fe51f72efd44c9f62bfb63842f64f86f8af8d GIT binary patch literal 156 zcmW;GF%E)25QX6xcHJyb3K^-iA@tIC2NR8nC$PYXWD8jWi+Az1u5{o0$x8-bhP=E# zyxVDNx^}9E(FZRowhFK(@6Y`(hiZ*9`ZkAnT<$QUnM{E_I1|MryS%)%&C~T=8AkVU mO&! Source IDL Documentation: - /// > - /// > Service docs. - \(access) protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService { - /// Handle the "Unary" method. + extension Test_TestService { + /// Streaming variant of the service protocol for the "test.TestService" service. + /// + /// This protocol is the lowest-level of the service protocols generated for this service + /// giving you the most flexibility over the implementation of your service. This comes at + /// the cost of more verbose and less strict APIs. Each RPC requires you to implement it in + /// terms of a request stream and response stream. Where only a single request or response + /// message is expected, you are responsible for enforcing this invariant is maintained. + /// + /// Where possible, prefer using the stricter, less-verbose ``ServiceProtocol`` + /// or ``SimpleServiceProtocol`` instead. /// /// > Source IDL Documentation: /// > - /// > Unary docs. - /// - /// - Parameters: - /// - request: A streaming request of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A streaming response of `Test_TestOutput` messages. - func unary( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse + /// > Service docs. + \(access) protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService { + /// Handle the "Unary" method. + /// + /// > Source IDL Documentation: + /// > + /// > Unary docs. + /// + /// - Parameters: + /// - request: A streaming request of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `Test_TestOutput` messages. + func unary( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "ClientStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Client streaming docs. + /// + /// - Parameters: + /// - request: A streaming request of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `Test_TestOutput` messages. + func clientStreaming( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse - /// Handle the "ClientStreaming" method. + /// Handle the "ServerStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Server streaming docs. + /// + /// - Parameters: + /// - request: A streaming request of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `Test_TestOutput` messages. + func serverStreaming( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "BidirectionalStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Bidirectional streaming docs. + /// + /// - Parameters: + /// - request: A streaming request of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `Test_TestOutput` messages. + func bidirectionalStreaming( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + } + + /// Service protocol for the "test.TestService" service. + /// + /// This protocol is higher level than ``StreamingServiceProtocol`` but lower level than + /// the ``SimpleServiceProtocol``, it provides access to request and response metadata and + /// trailing response metadata. If you don't need these then consider using + /// the ``SimpleServiceProtocol``. If you need fine grained control over your RPCs then + /// use ``StreamingServiceProtocol``. /// /// > Source IDL Documentation: /// > - /// > Client streaming docs. - /// - /// - Parameters: - /// - request: A streaming request of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A streaming response of `Test_TestOutput` messages. - func clientStreaming( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse + /// > Service docs. + \(access) protocol ServiceProtocol: Test_TestService.StreamingServiceProtocol { + /// Handle the "Unary" method. + /// + /// > Source IDL Documentation: + /// > + /// > Unary docs. + /// + /// - Parameters: + /// - request: A request containing a single `Test_TestInput` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A response containing a single `Test_TestOutput` message. + func unary( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse + + /// Handle the "ClientStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Client streaming docs. + /// + /// - Parameters: + /// - request: A streaming request of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A response containing a single `Test_TestOutput` message. + func clientStreaming( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.ServerResponse + + /// Handle the "ServerStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Server streaming docs. + /// + /// - Parameters: + /// - request: A request containing a single `Test_TestInput` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `Test_TestOutput` messages. + func serverStreaming( + request: GRPCCore.ServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + + /// Handle the "BidirectionalStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Bidirectional streaming docs. + /// + /// - Parameters: + /// - request: A streaming request of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A streaming response of `Test_TestOutput` messages. + func bidirectionalStreaming( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse + } - /// Handle the "ServerStreaming" method. + /// Simple service protocol for the "test.TestService" service. + /// + /// This is the highest level protocol for the service. The API is the easiest to use but + /// doesn't provide access to request or response metadata. If you need access to these + /// then use ``ServiceProtocol`` instead. /// /// > Source IDL Documentation: /// > - /// > Server streaming docs. - /// - /// - Parameters: - /// - request: A streaming request of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A streaming response of `Test_TestOutput` messages. - func serverStreaming( + /// > Service docs. + \(access) protocol SimpleServiceProtocol: Test_TestService.ServiceProtocol { + /// Handle the "Unary" method. + /// + /// > Source IDL Documentation: + /// > + /// > Unary docs. + /// + /// - Parameters: + /// - request: A `Test_TestInput` message. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A `Test_TestOutput` to respond with. + func unary( + request: Test_TestInput, + context: GRPCCore.ServerContext + ) async throws -> Test_TestOutput + + /// Handle the "ClientStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Client streaming docs. + /// + /// - Parameters: + /// - request: A stream of `Test_TestInput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + /// - Returns: A `Test_TestOutput` to respond with. + func clientStreaming( + request: GRPCCore.RPCAsyncSequence, + context: GRPCCore.ServerContext + ) async throws -> Test_TestOutput + + /// Handle the "ServerStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Server streaming docs. + /// + /// - Parameters: + /// - request: A `Test_TestInput` message. + /// - response: A response stream of `Test_TestOutput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + func serverStreaming( + request: Test_TestInput, + response: GRPCCore.RPCWriter, + context: GRPCCore.ServerContext + ) async throws + + /// Handle the "BidirectionalStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Bidirectional streaming docs. + /// + /// - Parameters: + /// - request: A stream of `Test_TestInput` messages. + /// - response: A response stream of `Test_TestOutput` messages. + /// - context: Context providing information about the RPC. + /// - Throws: Any error which occurred during the processing of the request. Thrown errors + /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted + /// to an internal error. + func bidirectionalStreaming( + request: GRPCCore.RPCAsyncSequence, + response: GRPCCore.RPCWriter, + context: GRPCCore.ServerContext + ) async throws + } + } + + // Default implementation of 'registerMethods(with:)'. + extension Test_TestService.StreamingServiceProtocol { + \(access) func registerMethods(with router: inout GRPCCore.RPCRouter) { + router.registerHandler( + forMethod: Test_TestService.Method.Unary.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.unary( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: Test_TestService.Method.ClientStreaming.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.clientStreaming( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: Test_TestService.Method.ServerStreaming.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.serverStreaming( + request: request, + context: context + ) + } + ) + router.registerHandler( + forMethod: Test_TestService.Method.BidirectionalStreaming.descriptor, + deserializer: GRPCProtobuf.ProtobufDeserializer(), + serializer: GRPCProtobuf.ProtobufSerializer(), + handler: { request, context in + try await self.bidirectionalStreaming( + request: request, + context: context + ) + } + ) + } + } + + // Default implementation of streaming methods from 'StreamingServiceProtocol'. + extension Test_TestService.ServiceProtocol { + \(access) func unary( request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.unary( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return GRPCCore.StreamingServerResponse(single: response) + } - /// Handle the "BidirectionalStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Bidirectional streaming docs. - /// - /// - Parameters: - /// - request: A streaming request of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A streaming response of `Test_TestOutput` messages. - func bidirectionalStreaming( + \(access) func clientStreaming( + request: GRPCCore.StreamingServerRequest, + context: GRPCCore.ServerContext + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.clientStreaming( + request: request, + context: context + ) + return GRPCCore.StreamingServerResponse(single: response) + } + + \(access) func serverStreaming( request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse + ) async throws -> GRPCCore.StreamingServerResponse { + let response = try await self.serverStreaming( + request: GRPCCore.ServerRequest(stream: request), + context: context + ) + return response + } } - /// Service protocol for the "test.TestService" service. - /// - /// This protocol is higher level than ``StreamingServiceProtocol`` but lower level than - /// the ``SimpleServiceProtocol``, it provides access to request and response metadata and - /// trailing response metadata. If you don't need these then consider using - /// the ``SimpleServiceProtocol``. If you need fine grained control over your RPCs then - /// use ``StreamingServiceProtocol``. - /// - /// > Source IDL Documentation: - /// > - /// > Service docs. - \(access) protocol ServiceProtocol: Test_TestService.StreamingServiceProtocol { - /// Handle the "Unary" method. - /// - /// > Source IDL Documentation: - /// > - /// > Unary docs. - /// - /// - Parameters: - /// - request: A request containing a single `Test_TestInput` message. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A response containing a single `Test_TestOutput` message. - func unary( + // Default implementation of methods from 'ServiceProtocol'. + extension Test_TestService.SimpleServiceProtocol { + \(access) func unary( request: GRPCCore.ServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse + ) async throws -> GRPCCore.ServerResponse { + return GRPCCore.ServerResponse( + message: try await self.unary( + request: request.message, + context: context + ), + metadata: [:] + ) + } - /// Handle the "ClientStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Client streaming docs. - /// - /// - Parameters: - /// - request: A streaming request of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A response containing a single `Test_TestOutput` message. - func clientStreaming( + \(access) func clientStreaming( request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse + ) async throws -> GRPCCore.ServerResponse { + return GRPCCore.ServerResponse( + message: try await self.clientStreaming( + request: request.messages, + context: context + ), + metadata: [:] + ) + } - /// Handle the "ServerStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Server streaming docs. - /// - /// - Parameters: - /// - request: A request containing a single `Test_TestInput` message. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A streaming response of `Test_TestOutput` messages. - func serverStreaming( + \(access) func serverStreaming( request: GRPCCore.ServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse + ) async throws -> GRPCCore.StreamingServerResponse { + return GRPCCore.StreamingServerResponse( + metadata: [:], + producer: { writer in + try await self.serverStreaming( + request: request.message, + response: writer, + context: context + ) + return [:] + } + ) + } - /// Handle the "BidirectionalStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Bidirectional streaming docs. - /// - /// - Parameters: - /// - request: A streaming request of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A streaming response of `Test_TestOutput` messages. - func bidirectionalStreaming( + \(access) func bidirectionalStreaming( request: GRPCCore.StreamingServerRequest, context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse + ) async throws -> GRPCCore.StreamingServerResponse { + return GRPCCore.StreamingServerResponse( + metadata: [:], + producer: { writer in + try await self.bidirectionalStreaming( + request: request.messages, + response: writer, + context: context + ) + return [:] + } + ) + } } - /// Simple service protocol for the "test.TestService" service. - /// - /// This is the highest level protocol for the service. The API is the easiest to use but - /// doesn't provide access to request or response metadata. If you need access to these - /// then use ``ServiceProtocol`` instead. - /// - /// > Source IDL Documentation: - /// > - /// > Service docs. - \(access) protocol SimpleServiceProtocol: Test_TestService.ServiceProtocol { - /// Handle the "Unary" method. - /// - /// > Source IDL Documentation: - /// > - /// > Unary docs. - /// - /// - Parameters: - /// - request: A `Test_TestInput` message. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A `Test_TestOutput` to respond with. - func unary( - request: Test_TestInput, - context: GRPCCore.ServerContext - ) async throws -> Test_TestOutput + // MARK: test.TestService (client) - /// Handle the "ClientStreaming" method. + extension Test_TestService { + /// Generated client protocol for the "test.TestService" service. /// - /// > Source IDL Documentation: - /// > - /// > Client streaming docs. - /// - /// - Parameters: - /// - request: A stream of `Test_TestInput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - /// - Returns: A `Test_TestOutput` to respond with. - func clientStreaming( - request: GRPCCore.RPCAsyncSequence, - context: GRPCCore.ServerContext - ) async throws -> Test_TestOutput - - /// Handle the "ServerStreaming" method. + /// You don't need to implement this protocol directly, use the generated + /// implementation, ``Client``. /// /// > Source IDL Documentation: /// > - /// > Server streaming docs. - /// - /// - Parameters: - /// - request: A `Test_TestInput` message. - /// - response: A response stream of `Test_TestOutput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - func serverStreaming( - request: Test_TestInput, - response: GRPCCore.RPCWriter, - context: GRPCCore.ServerContext - ) async throws + /// > Service docs. + \(access) protocol ClientProtocol: Sendable { + /// Call the "Unary" method. + /// + /// > Source IDL Documentation: + /// > + /// > Unary docs. + /// + /// - Parameters: + /// - request: A request containing a single `Test_TestInput` message. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func unary( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "ClientStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Client streaming docs. + /// + /// - Parameters: + /// - request: A streaming request producing `Test_TestInput` messages. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func clientStreaming( + request: GRPCCore.StreamingClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "ServerStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Server streaming docs. + /// + /// - Parameters: + /// - request: A request containing a single `Test_TestInput` message. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func serverStreaming( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable - /// Handle the "BidirectionalStreaming" method. + /// Call the "BidirectionalStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Bidirectional streaming docs. + /// + /// - Parameters: + /// - request: A streaming request producing `Test_TestInput` messages. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func bidirectionalStreaming( + request: GRPCCore.StreamingClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + } + + /// Generated client for the "test.TestService" service. + /// + /// The ``Client`` provides an implementation of ``ClientProtocol`` which wraps + /// a `GRPCCore.GRPCCClient`. The underlying `GRPCClient` provides the long-lived + /// means of communication with the remote peer. /// /// > Source IDL Documentation: /// > - /// > Bidirectional streaming docs. - /// - /// - Parameters: - /// - request: A stream of `Test_TestInput` messages. - /// - response: A response stream of `Test_TestOutput` messages. - /// - context: Context providing information about the RPC. - /// - Throws: Any error which occurred during the processing of the request. Thrown errors - /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted - /// to an internal error. - func bidirectionalStreaming( - request: GRPCCore.RPCAsyncSequence, - response: GRPCCore.RPCWriter, - context: GRPCCore.ServerContext - ) async throws - } - } + /// > Service docs. + \(access) struct Client: ClientProtocol { + private let client: GRPCCore.GRPCClient - // Default implementation of 'registerMethods(with:)'. - extension Test_TestService.StreamingServiceProtocol { - \(access) func registerMethods(with router: inout GRPCCore.RPCRouter) { - router.registerHandler( - forMethod: Test_TestService.Method.Unary.descriptor, - deserializer: GRPCProtobuf.ProtobufDeserializer(), - serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request, context in - try await self.unary( - request: request, - context: context - ) + /// Creates a new client wrapping the provided `GRPCCore.GRPCClient`. + /// + /// - Parameters: + /// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service. + \(access) init(wrapping client: GRPCCore.GRPCClient) { + self.client = client } - ) - router.registerHandler( - forMethod: Test_TestService.Method.ClientStreaming.descriptor, - deserializer: GRPCProtobuf.ProtobufDeserializer(), - serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request, context in - try await self.clientStreaming( - request: request, - context: context - ) - } - ) - router.registerHandler( - forMethod: Test_TestService.Method.ServerStreaming.descriptor, - deserializer: GRPCProtobuf.ProtobufDeserializer(), - serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request, context in - try await self.serverStreaming( + + /// Call the "Unary" method. + /// + /// > Source IDL Documentation: + /// > + /// > Unary docs. + /// + /// - Parameters: + /// - request: A request containing a single `Test_TestInput` message. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + \(access) func unary( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( request: request, - context: context + descriptor: Test_TestService.Method.Unary.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse ) } - ) - router.registerHandler( - forMethod: Test_TestService.Method.BidirectionalStreaming.descriptor, - deserializer: GRPCProtobuf.ProtobufDeserializer(), - serializer: GRPCProtobuf.ProtobufSerializer(), - handler: { request, context in - try await self.bidirectionalStreaming( + + /// Call the "ClientStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Client streaming docs. + /// + /// - Parameters: + /// - request: A streaming request producing `Test_TestInput` messages. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + \(access) func clientStreaming( + request: GRPCCore.StreamingClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.clientStreaming( request: request, - context: context + descriptor: Test_TestService.Method.ClientStreaming.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse ) } - ) - } - } - - // Default implementation of streaming methods from 'StreamingServiceProtocol'. - extension Test_TestService.ServiceProtocol { - \(access) func unary( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse { - let response = try await self.unary( - request: GRPCCore.ServerRequest(stream: request), - context: context - ) - return GRPCCore.StreamingServerResponse(single: response) - } - \(access) func clientStreaming( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse { - let response = try await self.clientStreaming( - request: request, - context: context - ) - return GRPCCore.StreamingServerResponse(single: response) - } - - \(access) func serverStreaming( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse { - let response = try await self.serverStreaming( - request: GRPCCore.ServerRequest(stream: request), - context: context - ) - return response - } - } - - // Default implementation of methods from 'ServiceProtocol'. - extension Test_TestService.SimpleServiceProtocol { - \(access) func unary( - request: GRPCCore.ServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse { - return GRPCCore.ServerResponse( - message: try await self.unary( - request: request.message, - context: context - ), - metadata: [:] - ) - } - - \(access) func clientStreaming( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.ServerResponse { - return GRPCCore.ServerResponse( - message: try await self.clientStreaming( - request: request.messages, - context: context - ), - metadata: [:] - ) - } - - \(access) func serverStreaming( - request: GRPCCore.ServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse { - return GRPCCore.StreamingServerResponse( - metadata: [:], - producer: { writer in - try await self.serverStreaming( - request: request.message, - response: writer, - context: context + /// Call the "ServerStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Server streaming docs. + /// + /// - Parameters: + /// - request: A request containing a single `Test_TestInput` message. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + \(access) func serverStreaming( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.client.serverStreaming( + request: request, + descriptor: Test_TestService.Method.ServerStreaming.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse ) - return [:] } - ) - } - \(access) func bidirectionalStreaming( - request: GRPCCore.StreamingServerRequest, - context: GRPCCore.ServerContext - ) async throws -> GRPCCore.StreamingServerResponse { - return GRPCCore.StreamingServerResponse( - metadata: [:], - producer: { writer in - try await self.bidirectionalStreaming( - request: request.messages, - response: writer, - context: context + /// Call the "BidirectionalStreaming" method. + /// + /// > Source IDL Documentation: + /// > + /// > Bidirectional streaming docs. + /// + /// - Parameters: + /// - request: A streaming request producing `Test_TestInput` messages. + /// - serializer: A serializer for `Test_TestInput` messages. + /// - deserializer: A deserializer for `Test_TestOutput` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + \(access) func bidirectionalStreaming( + request: GRPCCore.StreamingClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable { + try await self.client.bidirectionalStreaming( + request: request, + descriptor: Test_TestService.Method.BidirectionalStreaming.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse ) - return [:] } - ) + } } - } - // MARK: test.TestService (client) - - extension Test_TestService { - /// Generated client protocol for the "test.TestService" service. - /// - /// You don't need to implement this protocol directly, use the generated - /// implementation, ``Client``. - /// - /// > Source IDL Documentation: - /// > - /// > Service docs. - \(access) protocol ClientProtocol: Sendable { + // Helpers providing default arguments to 'ClientProtocol' methods. + extension Test_TestService.ClientProtocol { /// Call the "Unary" method. /// /// > Source IDL Documentation: @@ -570,20 +821,26 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// /// - Parameters: /// - request: A request containing a single `Test_TestInput` message. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. /// - options: Options to apply to this RPC. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. - func unary( + \(access) func unary( request: GRPCCore.ClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, - options: GRPCCore.CallOptions, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.unary( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } /// Call the "ClientStreaming" method. /// @@ -593,20 +850,26 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// /// - Parameters: /// - request: A streaming request producing `Test_TestInput` messages. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. /// - options: Options to apply to this RPC. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. - func clientStreaming( + \(access) func clientStreaming( request: GRPCCore.StreamingClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, - options: GRPCCore.CallOptions, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.clientStreaming( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } /// Call the "ServerStreaming" method. /// @@ -616,20 +879,24 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// /// - Parameters: /// - request: A request containing a single `Test_TestInput` message. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. /// - options: Options to apply to this RPC. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. - func serverStreaming( + \(access) func serverStreaming( request: GRPCCore.ClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, - options: GRPCCore.CallOptions, + options: GRPCCore.CallOptions = .defaults, onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable + ) async throws -> Result where Result: Sendable { + try await self.serverStreaming( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } /// Call the "BidirectionalStreaming" method. /// @@ -639,42 +906,28 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// /// - Parameters: /// - request: A streaming request producing `Test_TestInput` messages. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. /// - options: Options to apply to this RPC. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. - func bidirectionalStreaming( + \(access) func bidirectionalStreaming( request: GRPCCore.StreamingClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, - options: GRPCCore.CallOptions, + options: GRPCCore.CallOptions = .defaults, onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable - } - - /// Generated client for the "test.TestService" service. - /// - /// The ``Client`` provides an implementation of ``ClientProtocol`` which wraps - /// a `GRPCCore.GRPCCClient`. The underlying `GRPCClient` provides the long-lived - /// means of communication with the remote peer. - /// - /// > Source IDL Documentation: - /// > - /// > Service docs. - \(access) struct Client: ClientProtocol { - private let client: GRPCCore.GRPCClient - - /// Creates a new client wrapping the provided `GRPCCore.GRPCClient`. - /// - /// - Parameters: - /// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service. - \(access) init(wrapping client: GRPCCore.GRPCClient) { - self.client = client + ) async throws -> Result where Result: Sendable { + try await self.bidirectionalStreaming( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) } + } + // Helpers providing sugared APIs for 'ClientProtocol' methods. + extension Test_TestService.ClientProtocol { /// Call the "Unary" method. /// /// > Source IDL Documentation: @@ -682,28 +935,27 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// > Unary docs. /// /// - Parameters: - /// - request: A request containing a single `Test_TestInput` message. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. - /// - options: Options to apply to this RPC. + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. \(access) func unary( - request: GRPCCore.ClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, + _ message: Test_TestInput, + metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in try response.message } ) async throws -> Result where Result: Sendable { - try await self.client.unary( + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.unary( request: request, - descriptor: Test_TestService.Method.Unary.descriptor, - serializer: serializer, - deserializer: deserializer, options: options, onResponse: handleResponse ) @@ -716,28 +968,28 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// > Client streaming docs. /// /// - Parameters: - /// - request: A streaming request producing `Test_TestInput` messages. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. - /// - options: Options to apply to this RPC. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - producer: A closure producing request messages to send to the server. The request + /// stream is closed when the closure returns. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. \(access) func clientStreaming( - request: GRPCCore.StreamingClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, + metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, + requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in try response.message } ) async throws -> Result where Result: Sendable { - try await self.client.clientStreaming( + let request = GRPCCore.StreamingClientRequest( + metadata: metadata, + producer: producer + ) + return try await self.clientStreaming( request: request, - descriptor: Test_TestService.Method.ClientStreaming.descriptor, - serializer: serializer, - deserializer: deserializer, options: options, onResponse: handleResponse ) @@ -750,26 +1002,25 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// > Server streaming docs. /// /// - Parameters: - /// - request: A request containing a single `Test_TestInput` message. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. - /// - options: Options to apply to this RPC. + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. \(access) func serverStreaming( - request: GRPCCore.ClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, + _ message: Test_TestInput, + metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable { - try await self.client.serverStreaming( + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.serverStreaming( request: request, - descriptor: Test_TestService.Method.ServerStreaming.descriptor, - serializer: serializer, - deserializer: deserializer, options: options, onResponse: handleResponse ) @@ -782,282 +1033,76 @@ struct ProtobufCodeGeneratorTests: UsesDescriptorSet { /// > Bidirectional streaming docs. /// /// - Parameters: - /// - request: A streaming request producing `Test_TestInput` messages. - /// - serializer: A serializer for `Test_TestInput` messages. - /// - deserializer: A deserializer for `Test_TestOutput` messages. - /// - options: Options to apply to this RPC. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - producer: A closure producing request messages to send to the server. The request + /// stream is closed when the closure returns. /// - handleResponse: A closure which handles the response, the result of which is /// returned to the caller. Returning from the closure will cancel the RPC if it /// hasn't already finished. /// - Returns: The result of `handleResponse`. \(access) func bidirectionalStreaming( - request: GRPCCore.StreamingClientRequest, - serializer: some GRPCCore.MessageSerializer, - deserializer: some GRPCCore.MessageDeserializer, + metadata: GRPCCore.Metadata = [:], options: GRPCCore.CallOptions = .defaults, + requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable { - try await self.client.bidirectionalStreaming( + let request = GRPCCore.StreamingClientRequest( + metadata: metadata, + producer: producer + ) + return try await self.bidirectionalStreaming( request: request, - descriptor: Test_TestService.Method.BidirectionalStreaming.descriptor, - serializer: serializer, - deserializer: deserializer, options: options, onResponse: handleResponse ) } } - } - - // Helpers providing default arguments to 'ClientProtocol' methods. - extension Test_TestService.ClientProtocol { - /// Call the "Unary" method. - /// - /// > Source IDL Documentation: - /// > - /// > Unary docs. - /// - /// - Parameters: - /// - request: A request containing a single `Test_TestInput` message. - /// - options: Options to apply to this RPC. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func unary( - request: GRPCCore.ClientRequest, - options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in - try response.message - } - ) async throws -> Result where Result: Sendable { - try await self.unary( - request: request, - serializer: GRPCProtobuf.ProtobufSerializer(), - deserializer: GRPCProtobuf.ProtobufDeserializer(), - options: options, - onResponse: handleResponse - ) - } + """ - /// Call the "ClientStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Client streaming docs. - /// - /// - Parameters: - /// - request: A streaming request producing `Test_TestInput` messages. - /// - options: Options to apply to this RPC. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func clientStreaming( - request: GRPCCore.StreamingClientRequest, - options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in - try response.message - } - ) async throws -> Result where Result: Sendable { - try await self.clientStreaming( - request: request, - serializer: GRPCProtobuf.ProtobufSerializer(), - deserializer: GRPCProtobuf.ProtobufDeserializer(), - options: options, - onResponse: handleResponse - ) - } + #expect(generated == expected) + } + } - /// Call the "ServerStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Server streaming docs. - /// - /// - Parameters: - /// - request: A request containing a single `Test_TestInput` message. - /// - options: Options to apply to this RPC. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func serverStreaming( - request: GRPCCore.ClientRequest, - options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable { - try await self.serverStreaming( - request: request, - serializer: GRPCProtobuf.ProtobufSerializer(), - deserializer: GRPCProtobuf.ProtobufDeserializer(), - options: options, - onResponse: handleResponse - ) - } + @Suite("File-without-services (foo-messages.proto)") + struct NoServices: UsesDescriptorSet { + static let descriptorSetName = "foo-messages" + static let fileDescriptorName = "foo-messages" - /// Call the "BidirectionalStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Bidirectional streaming docs. - /// - /// - Parameters: - /// - request: A streaming request producing `Test_TestInput` messages. - /// - options: Options to apply to this RPC. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func bidirectionalStreaming( - request: GRPCCore.StreamingClientRequest, - options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable { - try await self.bidirectionalStreaming( - request: request, - serializer: GRPCProtobuf.ProtobufSerializer(), - deserializer: GRPCProtobuf.ProtobufDeserializer(), - options: options, - onResponse: handleResponse - ) - } - } + @Test("Generate") + func generate() throws { + let generator = ProtobufCodeGenerator( + config: SourceGenerator.Config( + accessLevel: .public, + accessLevelOnImports: false, + client: true, + server: true, + indentation: 2 + ) + ) - // Helpers providing sugared APIs for 'ClientProtocol' methods. - extension Test_TestService.ClientProtocol { - /// Call the "Unary" method. - /// - /// > Source IDL Documentation: - /// > - /// > Unary docs. - /// - /// - Parameters: - /// - message: request message to send. - /// - metadata: Additional metadata to send, defaults to empty. - /// - options: Options to apply to this RPC, defaults to `.defaults`. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func unary( - _ message: Test_TestInput, - metadata: GRPCCore.Metadata = [:], - options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in - try response.message - } - ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest( - message: message, - metadata: metadata - ) - return try await self.unary( - request: request, - options: options, - onResponse: handleResponse - ) - } + let generated = try generator.generateCode( + fileDescriptor: Self.fileDescriptor, + protoFileModuleMappings: ProtoFileToModuleMappings(), + extraModuleImports: [] + ) - /// Call the "ClientStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Client streaming docs. - /// - /// - Parameters: - /// - metadata: Additional metadata to send, defaults to empty. - /// - options: Options to apply to this RPC, defaults to `.defaults`. - /// - producer: A closure producing request messages to send to the server. The request - /// stream is closed when the closure returns. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func clientStreaming( - metadata: GRPCCore.Metadata = [:], - options: GRPCCore.CallOptions = .defaults, - requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, - onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in - try response.message - } - ) async throws -> Result where Result: Sendable { - let request = GRPCCore.StreamingClientRequest( - metadata: metadata, - producer: producer - ) - return try await self.clientStreaming( - request: request, - options: options, - onResponse: handleResponse - ) - } + let expected = """ + /// Leading trivia. - /// Call the "ServerStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Server streaming docs. - /// - /// - Parameters: - /// - message: request message to send. - /// - metadata: Additional metadata to send, defaults to empty. - /// - options: Options to apply to this RPC, defaults to `.defaults`. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func serverStreaming( - _ message: Test_TestInput, - metadata: GRPCCore.Metadata = [:], - options: GRPCCore.CallOptions = .defaults, - onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable { - let request = GRPCCore.ClientRequest( - message: message, - metadata: metadata - ) - return try await self.serverStreaming( - request: request, - options: options, - onResponse: handleResponse - ) - } + // DO NOT EDIT. + // swift-format-ignore-file + // + // Generated by the gRPC Swift generator plugin for the protocol buffer compiler. + // Source: foo-messages.proto + // + // For information on using the generated types, please see the documentation: + // https://github.com/grpc/grpc-swift - /// Call the "BidirectionalStreaming" method. - /// - /// > Source IDL Documentation: - /// > - /// > Bidirectional streaming docs. - /// - /// - Parameters: - /// - metadata: Additional metadata to send, defaults to empty. - /// - options: Options to apply to this RPC, defaults to `.defaults`. - /// - producer: A closure producing request messages to send to the server. The request - /// stream is closed when the closure returns. - /// - handleResponse: A closure which handles the response, the result of which is - /// returned to the caller. Returning from the closure will cancel the RPC if it - /// hasn't already finished. - /// - Returns: The result of `handleResponse`. - \(access) func bidirectionalStreaming( - metadata: GRPCCore.Metadata = [:], - options: GRPCCore.CallOptions = .defaults, - requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter) async throws -> Void, - onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse) async throws -> Result - ) async throws -> Result where Result: Sendable { - let request = GRPCCore.StreamingClientRequest( - metadata: metadata, - producer: producer - ) - return try await self.bidirectionalStreaming( - request: request, - options: options, - onResponse: handleResponse - ) - } - } - """ + // This file contained no services. + """ - #expect(generated == expected) + #expect(generated == expected) + } } } diff --git a/dev/protos/generate.sh b/dev/protos/generate.sh index 37473a8..d108251 100755 --- a/dev/protos/generate.sh +++ b/dev/protos/generate.sh @@ -119,6 +119,17 @@ function generate_foo_service_descriptor_set { --include_imports } +function generate_foo_messages_descriptor_set { + local proto proto_path output + proto="$here/local/foo-messages.proto" + proto_path="$(dirname "$proto")" + output="$root/Tests/GRPCProtobufCodeGenTests/Generated/foo-messages.pb" + + invoke_protoc --descriptor_set_out="$output" "$proto" -I "$proto_path" \ + --include_source_info \ + --include_imports +} + function generate_bar_service_descriptor_set { local proto proto_path output proto="$here/local/bar-service.proto" @@ -152,5 +163,6 @@ generate_error_service # Descriptor sets for tests generate_test_service_descriptor_set generate_foo_service_descriptor_set +generate_foo_messages_descriptor_set generate_bar_service_descriptor_set generate_wkt_service_descriptor_set diff --git a/dev/protos/local/foo-messages.proto b/dev/protos/local/foo-messages.proto index 7b9beca..bc79d13 100644 --- a/dev/protos/local/foo-messages.proto +++ b/dev/protos/local/foo-messages.proto @@ -1,3 +1,4 @@ +// Leading trivia. syntax = "proto3"; package foo;