ServerCodeTranslator.swift 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /// Creates a representation for the server code that will be generated based on the ``CodeGenerationRequest`` object
  17. /// specifications, using types from ``StructuredSwiftRepresentation``.
  18. ///
  19. /// For example, in the case of a service called "Bar", in the "foo" namespace which has
  20. /// one method "baz" with input type "Input" and output type "Output", the ``ServerCodeTranslator`` will create
  21. /// a representation for the following generated code:
  22. ///
  23. /// ```swift
  24. /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  25. /// public protocol Foo_BarStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  26. /// func baz(
  27. /// request: GRPCCore.StreamingServerRequest<Foo_Bar_Input>
  28. /// ) async throws -> GRPCCore.StreamingServerResponse<Foo_Bar_Output>
  29. /// }
  30. /// // Conformance to `GRPCCore.RegistrableRPCService`.
  31. /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  32. /// extension Foo_Bar.StreamingServiceProtocol {
  33. /// public func registerMethods(with router: inout GRPCCore.RPCRouter) {
  34. /// router.registerHandler(
  35. /// forMethod: Foo_Bar.Method.baz.descriptor,
  36. /// deserializer: GRPCProtobuf.ProtobufDeserializer<Foo_Bar_Input>(),
  37. /// serializer: GRPCProtobuf.ProtobufSerializer<Foo_Bar_Output>(),
  38. /// handler: { request in try await self.baz(request: request) }
  39. /// )
  40. /// }
  41. /// }
  42. /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  43. /// public protocol Foo_BarServiceProtocol: Foo_Bar.StreamingServiceProtocol {
  44. /// func baz(
  45. /// request: GRPCCore.ServerRequest<Foo_Bar_Input>
  46. /// ) async throws -> GRPCCore.ServerResponse<Foo_Bar_Output>
  47. /// }
  48. /// // Partial conformance to `Foo_BarStreamingServiceProtocol`.
  49. /// @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
  50. /// extension Foo_Bar.ServiceProtocol {
  51. /// public func baz(
  52. /// request: GRPCCore.StreamingServerRequest<Foo_Bar_Input>
  53. /// ) async throws -> GRPCCore.StreamingServerResponse<Foo_Bar_Output> {
  54. /// let response = try await self.baz(request: GRPCCore.ServerRequest(stream: request))
  55. /// return GRPCCore.StreamingServerResponse(single: response)
  56. /// }
  57. /// }
  58. ///```
  59. struct ServerCodeTranslator {
  60. init() {}
  61. func translate(
  62. accessModifier: AccessModifier,
  63. services: [ServiceDescriptor],
  64. serializer: (String) -> String,
  65. deserializer: (String) -> String
  66. ) -> [CodeBlock] {
  67. return services.flatMap { service in
  68. self.translate(
  69. accessModifier: accessModifier,
  70. service: service,
  71. serializer: serializer,
  72. deserializer: deserializer
  73. )
  74. }
  75. }
  76. private func translate(
  77. accessModifier: AccessModifier,
  78. service: ServiceDescriptor,
  79. serializer: (String) -> String,
  80. deserializer: (String) -> String
  81. ) -> [CodeBlock] {
  82. var blocks = [CodeBlock]()
  83. let serviceProtocolName = self.protocolName(service: service, streaming: false)
  84. let serviceTypealiasName = self.protocolName(
  85. service: service,
  86. streaming: false,
  87. joinedUsing: "."
  88. )
  89. let streamingServiceProtocolName = self.protocolName(service: service, streaming: true)
  90. let streamingServiceTypealiasName = self.protocolName(
  91. service: service,
  92. streaming: true,
  93. joinedUsing: "."
  94. )
  95. // protocol <Service>_StreamingServiceProtocol { ... }
  96. let streamingServiceProtocol: ProtocolDescription = .streamingService(
  97. accessLevel: accessModifier,
  98. name: streamingServiceProtocolName,
  99. methods: service.methods
  100. )
  101. blocks.append(
  102. CodeBlock(
  103. comment: .preFormatted(service.documentation),
  104. item: .declaration(.guarded(.grpc, .protocol(streamingServiceProtocol)))
  105. )
  106. )
  107. // extension <Service>_StreamingServiceProtocol> { ... }
  108. let registerExtension: ExtensionDescription = .registrableRPCServiceDefaultImplementation(
  109. accessLevel: accessModifier,
  110. on: streamingServiceTypealiasName,
  111. serviceNamespace: service.namespacedGeneratedName,
  112. methods: service.methods,
  113. serializer: serializer,
  114. deserializer: deserializer
  115. )
  116. blocks.append(
  117. CodeBlock(
  118. comment: .doc("Conformance to `GRPCCore.RegistrableRPCService`."),
  119. item: .declaration(.guarded(.grpc, .extension(registerExtension)))
  120. )
  121. )
  122. // protocol <Service>_ServiceProtocol { ... }
  123. let serviceProtocol: ProtocolDescription = .service(
  124. accessLevel: accessModifier,
  125. name: serviceProtocolName,
  126. streamingProtocol: streamingServiceTypealiasName,
  127. methods: service.methods
  128. )
  129. blocks.append(
  130. CodeBlock(
  131. comment: .preFormatted(service.documentation),
  132. item: .declaration(.guarded(.grpc, .protocol(serviceProtocol)))
  133. )
  134. )
  135. // extension <Service>_ServiceProtocol { ... }
  136. let streamingServiceDefaultImplExtension: ExtensionDescription =
  137. .streamingServiceProtocolDefaultImplementation(
  138. accessModifier: accessModifier,
  139. on: serviceTypealiasName,
  140. methods: service.methods
  141. )
  142. blocks.append(
  143. CodeBlock(
  144. comment: .doc("Partial conformance to `\(streamingServiceProtocolName)`."),
  145. item: .declaration(.guarded(.grpc, .extension(streamingServiceDefaultImplExtension)))
  146. )
  147. )
  148. return blocks
  149. }
  150. private func protocolName(
  151. service: ServiceDescriptor,
  152. streaming: Bool,
  153. joinedUsing join: String = "_"
  154. ) -> String {
  155. if streaming {
  156. return "\(service.namespacedGeneratedName)\(join)StreamingServiceProtocol"
  157. }
  158. return "\(service.namespacedGeneratedName)\(join)ServiceProtocol"
  159. }
  160. }