/* * Copyright 2020 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * NOTE: The following implementation is a translation for the Swift-grpc * generator since flatbuffers doesnt allow plugins for now. if an issue arises * please open an issue in the flatbuffers repository. This file should always * be maintained according to the Swift-grpc repository */ #include "src/compiler/swift_generator.h" #include #include #include "flatbuffers/util.h" #include "src/compiler/schema_interface.h" namespace grpc_swift_generator { namespace { static std::string ServerResponse() { return "GRPCCore.ServerResponse"; } static std::string ServerRequest() { return "GRPCCore.ServerRequest"; } static std::string StreamingServerRequest() { return "GRPCCore.StreamingServerRequest"; } static std::string StreamingServerResponse() { return "GRPCCore.StreamingServerResponse"; } static std::string QualifiedName(const std::vector& components, const grpc::string& name, const std::string& separator = "_") { std::string qualified_name; for (auto it = components.begin(); it != components.end(); ++it) qualified_name += *it + separator; return qualified_name + name; } static std::string GenerateGRPCMessage(const std::string& name) { return "GRPCMessage<" + name + ">"; } static std::string GenerateType(const std::string& name, const std::string& wrapper) { return wrapper + "<" + GenerateGRPCMessage(name) + ">"; } static std::string GenerateInputMethodTypes( const grpc_generator::Method* method) { if (method->BidiStreaming()) { return StreamingServerRequest(); } else if (method->ClientStreaming()) { return StreamingServerRequest(); } else if (method->ServerStreaming()) { return ServerRequest(); } else { return ServerRequest(); } } static std::string GenerateOutputMethodTypes( const grpc_generator::Method* method) { if (method->BidiStreaming()) { return StreamingServerResponse(); } else if (method->ClientStreaming()) { return ServerResponse(); } else if (method->ServerStreaming()) { return StreamingServerResponse(); } else { return ServerResponse(); } } static std::string GenerateMethodTypes(const grpc_generator::Method* method) { if (method->BidiStreaming()) { return "bidirectionalStreaming"; } else if (method->ClientStreaming()) { return "clientStreaming"; } else if (method->ServerStreaming()) { return "serverStreaming"; } else { return "unary"; } } void EnforceOSVersion(grpc_generator::Printer* printer) { printer->Print( "@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, " "*)\n"); } void GenerateMethodDescriptor(grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; printer->Print(vars, "$ACCESS$ enum $MethodName$: Sendable {\n"); printer->Indent(); printer->Print(vars, "$ACCESS$ typealias Input = FlatBufferBuilder\n"); printer->Print(vars, "$ACCESS$ typealias Output = $Output$\n"); printer->Print( vars, "$ACCESS$ static let descriptor = GRPCCore.MethodDescriptor(\n"); printer->Indent(); printer->Print(vars, "service: GRPCCore.ServiceDescriptor(fullyQualifiedService: " "\"$ServiceQualifiedName$\"),\n"); printer->Print(vars, "method: \"$MethodName$\"\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print(vars, "}\n"); } void GenerateCoders(grpc_generator::Printer* printer) { EnforceOSVersion(printer); printer->Print( "extension FlatBuffersMessageSerializer: MessageSerializer {\n"); printer->Indent(); printer->Print( "public func serialize(_ message: Message) throws -> Bytes where " "Bytes : GRPCCore.GRPCContiguousBytes {\n"); printer->Indent(); printer->Print("do {\n"); printer->Indent(); printer->Print( "return try self.serialize(message: message) { GRPCNIOTransportBytes($0) " "} as! Bytes\n"); printer->Outdent(); printer->Print("} catch let error {\n"); printer->Indent(); printer->Print("throw RPCError(\n"); printer->Indent(); printer->Print("code: .invalidArgument,\n"); printer->Print("message: \"Can't serialize message\",\n"); printer->Print("cause: error\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); EnforceOSVersion(printer); printer->Print( "extension FlatBuffersMessageDeserializer: MessageDeserializer {\n"); printer->Indent(); printer->Print( "public func deserialize(_ serializedMessageBytes: Bytes) throws " "-> Message where Bytes : GRPCCore.GRPCContiguousBytes {\n"); printer->Indent(); printer->Print("do {\n"); printer->Indent(); printer->Print("return try serializedMessageBytes.withUnsafeBytes {\n"); printer->Indent(); printer->Print("try self.deserialize(pointer: $0)\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("} catch let error {\n"); printer->Indent(); printer->Print("throw RPCError(\n"); printer->Indent(); printer->Print("code: .invalidArgument,\n"); printer->Print( "message: \"Can't Decode message of type \\(Message.self)\",\n"); printer->Print("cause: error\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); } void GenerateSharedContent(const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "$ACCESS$ enum $SwiftServiceQualifiedName$: Sendable {\n"); printer->Indent(); printer->Print(vars, "$ACCESS$ static let descriptor = " "GRPCCore.ServiceDescriptor(fullyQualifiedService: " "\"$ServiceQualifiedName$\")\n"); printer->Print(vars, "$ACCESS$ enum Method: Sendable {\n"); printer->Indent(); std::vector descriptors; for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); vars["Input"] = QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()); vars["Output"] = QualifiedName(method->get_output_namespace_parts(), method->get_output_type_name()); auto name = method->name(); vars["MethodName"] = name; descriptors.push_back(name); GenerateMethodDescriptor(printer, &vars); } printer->Print( vars, "$ACCESS$ static let descriptors: [GRPCCore.MethodDescriptor] = [\n"); printer->Indent(); for (auto it = descriptors.begin(); it < descriptors.end(); it++) { vars["MethodName"] = *it; printer->Print(vars, "$MethodName$.descriptor,\n"); } printer->Outdent(); printer->Print("]\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); EnforceOSVersion(printer); printer->Print("extension GRPCCore.ServiceDescriptor {\n"); printer->Indent(); printer->Print(vars, "$ACCESS$ static let $SwiftServiceQualifiedName$ = " "GRPCCore.ServiceDescriptor(fullyQualifiedService: " "\"$ServiceQualifiedName$\")\n"); printer->Outdent(); printer->Print("}\n"); } // Service Generation void GenerateFunction(grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; printer->Print(vars, "func $MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $Input$,\n"); printer->Print("context: GRPCCore.ServerContext\n"); printer->Outdent(); printer->Print(vars, ") async throws -> $Output$\n\n"); } void GenerateServiceProtocols(const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "extension $SwiftServiceQualifiedName$ {\n"); printer->Indent(); // Base protocol printer->Print(vars, "$ACCESS$ protocol StreamingServiceProtocol: " "GRPCCore.RegistrableRPCService {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); vars["Input"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), StreamingServerRequest()); vars["Output"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), StreamingServerResponse()); auto name = method->name(); vars["MethodName"] = name; GenerateFunction(printer, &vars); } printer->Outdent(); printer->Print("}\n\n"); // Service printer->Print(vars, "$ACCESS$ protocol ServiceProtocol: " "$SwiftServiceQualifiedName$.StreamingServiceProtocol {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); vars["Input"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), GenerateInputMethodTypes(&*method)); vars["Output"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), GenerateOutputMethodTypes(&*method)); auto name = method->name(); vars["MethodName"] = name; GenerateFunction(printer, &vars); } printer->Outdent(); printer->Print("}\n\n"); // Simple service printer->Print(vars, "$ACCESS$ protocol SimpleServiceProtocol: " "$SwiftServiceQualifiedName$.ServiceProtocol {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); vars["Input"] = GenerateGRPCMessage(QualifiedName( method->get_input_namespace_parts(), method->get_output_type_name())); vars["Output"] = GenerateGRPCMessage(QualifiedName( method->get_input_namespace_parts(), method->get_output_type_name())); auto name = method->name(); vars["MethodName"] = name; printer->Print(vars, "func $MethodName$(\n"); printer->Indent(); if (method->ClientStreaming() || method->BidiStreaming()) { printer->Print( vars, "request: GRPCCore.RPCAsyncSequence<$Input$, any Swift.Error>,\n"); } else { printer->Print(vars, "request: $Input$,\n"); } if (method->BidiStreaming() || method->ServerStreaming()) { printer->Print(vars, "response: GRPCCore.RPCWriter<$Output$>,\n"); } printer->Print("context: GRPCCore.ServerContext\n"); printer->Outdent(); if (!method->BidiStreaming() && !method->ServerStreaming()) { printer->Print(vars, ") async throws -> $Output$\n\n"); } else { printer->Print(") async throws\n\n"); } } printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); EnforceOSVersion(printer); printer->Print( vars, "extension $SwiftServiceQualifiedName$.StreamingServiceProtocol {\n"); printer->Indent(); printer->Print( "public func registerMethods(with router: inout " "GRPCCore.RPCRouter) where Transport: " "GRPCCore.ServerTransport {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); vars["Input"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "FlatBuffersMessageSerializer"); vars["Output"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "FlatBuffersMessageDeserializer"); auto name = method->name(); vars["MethodName"] = name; printer->Print("router.registerHandler(\n"); printer->Indent(); printer->Print( vars, "forMethod: " "$SwiftServiceQualifiedName$.Method.$MethodName$.descriptor,\n"); printer->Print(vars, "deserializer: $Output$(),\n"); printer->Print(vars, "serializer: $Input$(),\n"); printer->Print("handler: { request, context in\n"); printer->Indent(); printer->Print(vars, "try await self.$MethodName$(\n"); printer->Indent(); printer->Print("request: request,\n"); printer->Print("context: context\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print(")\n"); } printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); } void CreateServiceProtocolFunctionsImplementations( grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; printer->Print(vars, "$ACCESS$ func $MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $Input$,\n"); printer->Print("context: GRPCCore.ServerContext\n"); printer->Outdent(); printer->Print(vars, ") async throws -> $Output$ {\n"); printer->Indent(); printer->Print(vars, "let response = try await self.$MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $InputRequest$,\n"); printer->Print("context: context\n"); printer->Outdent(); printer->Print(")\n"); printer->Print(vars, "return $OutputResponse$\n"); printer->Outdent(); printer->Print("}\n"); } std::string GenerateInputRequest(const grpc_generator::Method* method) { if (method->NoStreaming() || method->ServerStreaming()) return ServerRequest() + "(stream: request)"; return "request"; } std::string GenerateOutputResponse(const grpc_generator::Method* method) { if (method->NoStreaming() || method->ClientStreaming()) return StreamingServerResponse() + "(single: response)"; return "response"; } void GenerateServiceDefaultImplementation( const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "extension $SwiftServiceQualifiedName$.ServiceProtocol {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); if (method->BidiStreaming()) { continue; } vars["Input"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), StreamingServerRequest()); vars["Output"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), StreamingServerResponse()); auto name = method->name(); vars["MethodName"] = name; vars["InputRequest"] = GenerateInputRequest(&*method); vars["OutputResponse"] = GenerateOutputResponse(&*method); CreateServiceProtocolFunctionsImplementations(printer, &vars); } printer->Outdent(); printer->Print("}\n\n"); } void GenerateSimpleServiceImplemetation( const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print( vars, "extension $SwiftServiceQualifiedName$.SimpleServiceProtocol {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); vars["Input"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), GenerateInputMethodTypes(&*method)); vars["Output"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), GenerateOutputMethodTypes(&*method)); auto name = method->name(); vars["MethodName"] = name; printer->Print(vars, "$ACCESS$ func $MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $Input$,\n"); printer->Print("context: GRPCCore.ServerContext\n"); printer->Outdent(); printer->Print(vars, ") async throws -> $Output$ {\n"); printer->Indent(); printer->Print(vars, "return $Output$(\n"); printer->Indent(); if (method->NoStreaming() || method->ClientStreaming()) { vars["Message"] = method->ClientStreaming() ? "messages" : "message"; printer->Print(vars, "message: try await self.$MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: request.$Message$,\n"); printer->Print("context: context\n"); printer->Outdent(); printer->Print(vars, "),\n"); printer->Print(vars, "metadata: [:]\n"); } else { vars["Message"] = method->BidiStreaming() ? "messages" : "message"; printer->Print(vars, "metadata: [:],\n"); printer->Print(vars, "producer: { writer in\n"); printer->Indent(); printer->Print(vars, "try await self.$MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: request.$Message$,\n"); printer->Print("response: writer,\n"); printer->Print("context: context\n"); printer->Outdent(); printer->Print(")\n"); printer->Print("return [:]\n"); printer->Outdent(); printer->Print(vars, "}\n"); } printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n"); } printer->Outdent(); printer->Print("}\n\n"); } void GenerateService(const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { GenerateServiceProtocols(service, printer, dictionary); GenerateServiceDefaultImplementation(service, printer, dictionary); GenerateSimpleServiceImplemetation(service, printer, dictionary); } // Client Generation void GenerateClientProtocols(const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "extension $SwiftServiceQualifiedName$ {\n"); printer->Indent(); // Base protocol printer->Print(vars, "$ACCESS$ protocol ClientProtocol: Sendable {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); auto name = method->name(); vars["MethodName"] = name; vars["serializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.MessageSerializer"); vars["deserializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.MessageDeserializer"); if (method->ClientStreaming() || method->BidiStreaming()) { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientRequest"); } else { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientRequest"); } if (method->ServerStreaming() || method->BidiStreaming()) { vars["response"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientResponse"); } else { vars["response"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientResponse"); } printer->Print(vars, "func $MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $request$,\n"); printer->Print(vars, "serializer: some $serializer$,\n"); printer->Print(vars, "deserializer: some $deserializer$,\n"); printer->Print("options: GRPCCore.CallOptions,\n"); printer->Print(vars, "onResponse handleResponse: @Sendable @escaping " "($response$) async throws -> Result\n"); printer->Outdent(); printer->Print(") async throws -> Result where Result: Sendable\n\n"); } printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); } void GenerateClientStruct(const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "extension $SwiftServiceQualifiedName$ {\n"); printer->Indent(); // Base protocol printer->Print(vars, "$ACCESS$ struct Client: ClientProtocol where " "Transport: GRPCCore.ClientTransport {\n"); printer->Indent(); printer->Print("private let client: GRPCCore.GRPCClient\n\n"); printer->Print( vars, "$ACCESS$ init(wrapping client: GRPCCore.GRPCClient) {\n"); printer->Indent(); printer->Print("self.client = client\n"); printer->Outdent(); printer->Print("}\n\n"); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); auto name = method->name(); vars["MethodType"] = GenerateMethodTypes(&*method); vars["MethodName"] = name; vars["serializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.MessageSerializer"); vars["deserializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.MessageDeserializer"); if (method->ClientStreaming() || method->BidiStreaming()) { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientRequest"); } else { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientRequest"); } if (method->ServerStreaming() || method->BidiStreaming()) { vars["response"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientResponse"); vars["CompletionBlock"] = ""; } else { vars["response"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientResponse"); vars["CompletionBlock"] = " = { response in try response.message }"; } printer->Print(vars, "$ACCESS$ func $MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $request$,\n"); printer->Print(vars, "serializer: some $serializer$,\n"); printer->Print(vars, "deserializer: some $deserializer$,\n"); printer->Print("options: GRPCCore.CallOptions = .defaults,\n"); printer->Print(vars, "onResponse handleResponse: @Sendable @escaping " "($response$) async throws -> Result$CompletionBlock$\n"); printer->Outdent(); printer->Print(") async throws -> Result where Result: Sendable {\n"); printer->Indent(); printer->Print(vars, "try await self.client.$MethodType$(\n"); printer->Indent(); printer->Print("request: request,\n"); printer->Print( vars, "descriptor: " "$SwiftServiceQualifiedName$.Method.$MethodName$.descriptor,\n"); printer->Print("serializer: serializer,\n"); printer->Print("deserializer: deserializer,\n"); printer->Print("options: options,\n"); printer->Print("onResponse: handleResponse\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n\n"); } printer->Outdent(); printer->Print("}\n"); printer->Outdent(); printer->Print("}\n\n"); } void GenerateClientDefaultImplementation( const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "extension $SwiftServiceQualifiedName$.ClientProtocol {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); auto name = method->name(); vars["MethodName"] = name; vars["serializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "FlatBuffersMessageSerializer"); vars["deserializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "FlatBuffersMessageDeserializer"); if (method->ClientStreaming() || method->BidiStreaming()) { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientRequest"); } else { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientRequest"); } if (method->ServerStreaming() || method->BidiStreaming()) { vars["response"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientResponse"); vars["CompletionBlock"] = ""; } else { vars["response"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientResponse"); vars["CompletionBlock"] = " = { response in try response.message }"; } printer->Print(vars, "$ACCESS$ func $MethodName$(\n"); printer->Indent(); printer->Print(vars, "request: $request$,\n"); printer->Print("options: GRPCCore.CallOptions = .defaults,\n"); printer->Print(vars, "onResponse handleResponse: @Sendable @escaping " "($response$) async throws -> Result$CompletionBlock$\n"); printer->Outdent(); printer->Print(") async throws -> Result where Result: Sendable {\n"); printer->Indent(); printer->Print(vars, "try await self.$MethodName$(\n"); printer->Indent(); printer->Print("request: request,\n"); printer->Print(vars, "serializer: $serializer$(),\n"); printer->Print(vars, "deserializer: $deserializer$(),\n"); printer->Print("options: options,\n"); printer->Print("onResponse: handleResponse\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n\n"); } printer->Outdent(); printer->Print("}\n\n"); } void GenerateClientHelperMethods( const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { auto vars = *dictionary; EnforceOSVersion(printer); printer->Print(vars, "extension $SwiftServiceQualifiedName$.ClientProtocol {\n"); printer->Indent(); for (auto it = 0; it < service->method_count(); it++) { auto method = service->method(it); auto name = method->name(); vars["MethodName"] = name; vars["serializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "FlatBuffersMessageSerializer"); vars["deserializer"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "FlatBuffersMessageDeserializer"); printer->Print(vars, "$ACCESS$ func $MethodName$(\n"); printer->Indent(); if (method->NoStreaming() || method->ServerStreaming()) { vars["request"] = GenerateGRPCMessage(QualifiedName( method->get_input_namespace_parts(), method->get_output_type_name())); printer->Print(vars, "_ message: $request$,\n"); } printer->Print("metadata: GRPCCore.Metadata = [:],\n"); printer->Print("options: GRPCCore.CallOptions = .defaults,\n"); if (method->ClientStreaming() || method->BidiStreaming()) { vars["request"] = GenerateGRPCMessage(QualifiedName( method->get_input_namespace_parts(), method->get_output_type_name())); printer->Print(vars, "requestProducer producer: @Sendable @escaping " "(GRPCCore.RPCWriter<$request$>) async throws -> Void,\n"); } if (method->NoStreaming() || method->ClientStreaming()) { vars["response"] = GenerateGRPCMessage(QualifiedName( method->get_input_namespace_parts(), method->get_output_type_name())); printer->Print(vars, "onResponse handleResponse: @Sendable @escaping " "(GRPCCore.ClientResponse<$response$>) async throws -> " "Result = { try $0.message }\n"); } else { vars["response"] = GenerateGRPCMessage(QualifiedName( method->get_input_namespace_parts(), method->get_output_type_name())); printer->Print(vars, "onResponse handleResponse: @Sendable @escaping " "(GRPCCore.StreamingClientResponse<$response$>) async " "throws -> Result\n"); } printer->Outdent(); printer->Print(") async throws -> Result where Result: Sendable {\n"); printer->Indent(); if (method->ClientStreaming() || method->BidiStreaming()) { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.StreamingClientRequest"); } else { vars["request"] = GenerateType(QualifiedName(method->get_input_namespace_parts(), method->get_output_type_name()), "GRPCCore.ClientRequest"); } printer->Print(vars, "let request = $request$(\n"); printer->Indent(); if (method->NoStreaming() || method->ServerStreaming()) { printer->Print("message: message,\n"); printer->Print("metadata: metadata\n"); } else { printer->Print("metadata: metadata,\n"); printer->Print("producer: producer\n"); } printer->Outdent(); printer->Print(")\n"); printer->Print(vars, "return try await self.$MethodName$(\n"); printer->Indent(); printer->Print("request: request,\n"); printer->Print("options: options,\n"); printer->Print("onResponse: handleResponse\n"); printer->Outdent(); printer->Print(")\n"); printer->Outdent(); printer->Print("}\n\n"); } printer->Outdent(); printer->Print("}\n\n"); } void GenerateClient(const grpc_generator::Service* service, grpc_generator::Printer* printer, std::map* dictionary) { GenerateClientProtocols(service, printer, dictionary); GenerateClientStruct(service, printer, dictionary); GenerateClientDefaultImplementation(service, printer, dictionary); GenerateClientHelperMethods(service, printer, dictionary); } } // namespace grpc::string Generate(grpc_generator::File* file, const grpc_generator::Service* service) { grpc::string output; std::map vars; vars["PATH"] = file->package(); if (!file->package().empty()) { vars["PATH"].append("."); } vars["SwiftServiceQualifiedName"] = QualifiedName(service->namespace_parts(), service->name()); vars["ServiceQualifiedName"] = QualifiedName(service->namespace_parts(), service->name(), "."); vars["ServiceName"] = service->name(); vars["ACCESS"] = service->is_internal() ? "internal" : "public"; auto printer = file->CreatePrinter(&output); printer->Print( vars, "/// Usage: instantiate $ServiceQualifiedName$ServiceClient, then call " "methods of this protocol to make API calls.\n"); GenerateCoders(&*printer); GenerateSharedContent(service, &*printer, &vars); printer->Print("\n"); printer->Print(vars, "// MARK: $ServiceQualifiedName$ Server\n\n"); GenerateService(service, &*printer, &vars); printer->Print("\n"); printer->Print(vars, "// MARK: $ServiceQualifiedName$ Client\n\n"); GenerateClient(service, &*printer, &vars); printer->Print("#endif\n"); return output; } grpc::string GenerateHeader() { grpc::string code; code += "/// The following code is generated by the Flatbuffers library which " "might not be in sync with grpc-swift\n"; code += "/// in case of an issue please open github issue, though it would be " "maintained\n"; code += "\n"; code += "// swiftlint:disable all\n"; code += "// swiftformat:disable all\n"; code += "\n"; code += "#if !os(Windows) && compiler(>=6.0)\n"; code += "import FlatBuffers\n"; code += "import Foundation\n"; code += "import GRPCCore\n"; code += "import GRPCNIOTransportCore\n"; code += "\n"; return code; } } // namespace grpc_swift_generator