StructuredSwift+Server.swift 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /*
  2. * Copyright 2024, 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. extension FunctionSignatureDescription {
  17. /// ```
  18. /// func <Method>(
  19. /// request: GRPCCore.ServerRequest<Input>,
  20. /// context: GRPCCore.ServerContext
  21. /// ) async throws -> GRPCCore.ServerResponse<Output>
  22. /// ```
  23. static func serverMethod(
  24. accessLevel: AccessModifier? = nil,
  25. name: String,
  26. input: String,
  27. output: String,
  28. streamingInput: Bool,
  29. streamingOutput: Bool,
  30. namer: Namer = Namer()
  31. ) -> Self {
  32. return FunctionSignatureDescription(
  33. accessModifier: accessLevel,
  34. kind: .function(name: name),
  35. parameters: [
  36. ParameterDescription(
  37. label: "request",
  38. type: namer.serverRequest(forType: input, isStreaming: streamingInput)
  39. ),
  40. ParameterDescription(label: "context", type: namer.serverContext),
  41. ],
  42. keywords: [.async, .throws],
  43. returnType: .identifierType(
  44. namer.serverResponse(forType: output, isStreaming: streamingOutput)
  45. )
  46. )
  47. }
  48. }
  49. extension ProtocolDescription {
  50. /// ```
  51. /// protocol <Name>: GRPCCore.RegistrableRPCService {
  52. /// ...
  53. /// }
  54. /// ```
  55. static func streamingService(
  56. accessLevel: AccessModifier? = nil,
  57. name: String,
  58. methods: [MethodDescriptor],
  59. namer: Namer = Namer()
  60. ) -> Self {
  61. func docs(for method: MethodDescriptor) -> String {
  62. let summary = """
  63. /// Handle the "\(method.name.identifyingName)" method.
  64. """
  65. let parameters = """
  66. /// - Parameters:
  67. /// - request: A streaming request of `\(method.inputType)` messages.
  68. /// - context: Context providing information about the RPC.
  69. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  70. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  71. /// to an internal error.
  72. /// - Returns: A streaming response of `\(method.outputType)` messages.
  73. """
  74. return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
  75. }
  76. return ProtocolDescription(
  77. accessModifier: accessLevel,
  78. name: name,
  79. conformances: [namer.literalNamespacedType("RegistrableRPCService")],
  80. members: methods.map { method in
  81. .commentable(
  82. .preFormatted(docs(for: method)),
  83. .function(
  84. signature: .serverMethod(
  85. name: method.name.functionName,
  86. input: method.inputType,
  87. output: method.outputType,
  88. streamingInput: true,
  89. streamingOutput: true,
  90. namer: namer
  91. )
  92. )
  93. )
  94. }
  95. )
  96. }
  97. }
  98. extension ExtensionDescription {
  99. /// ```
  100. /// extension <ExtensionName> {
  101. /// func registerMethods(with router: inout GRPCCore.RPCRouter) {
  102. /// // ...
  103. /// }
  104. /// }
  105. /// ```
  106. static func registrableRPCServiceDefaultImplementation(
  107. accessLevel: AccessModifier? = nil,
  108. on extensionName: String,
  109. serviceNamespace: String,
  110. methods: [MethodDescriptor],
  111. namer: Namer = Namer(),
  112. serializer: (String) -> String,
  113. deserializer: (String) -> String
  114. ) -> Self {
  115. return ExtensionDescription(
  116. onType: extensionName,
  117. declarations: [
  118. .function(
  119. .registerMethods(
  120. accessLevel: accessLevel,
  121. serviceNamespace: serviceNamespace,
  122. methods: methods,
  123. namer: namer,
  124. serializer: serializer,
  125. deserializer: deserializer
  126. )
  127. )
  128. ]
  129. )
  130. }
  131. }
  132. extension ProtocolDescription {
  133. /// ```
  134. /// protocol <Name>: <StreamingProtocol> {
  135. /// ...
  136. /// }
  137. /// ```
  138. static func service(
  139. accessLevel: AccessModifier? = nil,
  140. name: String,
  141. streamingProtocol: String,
  142. methods: [MethodDescriptor],
  143. namer: Namer = Namer()
  144. ) -> Self {
  145. func docs(for method: MethodDescriptor) -> String {
  146. let summary = """
  147. /// Handle the "\(method.name.identifyingName)" method.
  148. """
  149. let request: String
  150. if method.isInputStreaming {
  151. request = "A streaming request of `\(method.inputType)` messages."
  152. } else {
  153. request = "A request containing a single `\(method.inputType)` message."
  154. }
  155. let returns: String
  156. if method.isOutputStreaming {
  157. returns = "A streaming response of `\(method.outputType)` messages."
  158. } else {
  159. returns = "A response containing a single `\(method.outputType)` message."
  160. }
  161. let parameters = """
  162. /// - Parameters:
  163. /// - request: \(request)
  164. /// - context: Context providing information about the RPC.
  165. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  166. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  167. /// to an internal error.
  168. /// - Returns: \(returns)
  169. """
  170. return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
  171. }
  172. return ProtocolDescription(
  173. accessModifier: accessLevel,
  174. name: name,
  175. conformances: [streamingProtocol],
  176. members: methods.map { method in
  177. .commentable(
  178. .preFormatted(docs(for: method)),
  179. .function(
  180. signature: .serverMethod(
  181. name: method.name.functionName,
  182. input: method.inputType,
  183. output: method.outputType,
  184. streamingInput: method.isInputStreaming,
  185. streamingOutput: method.isOutputStreaming,
  186. namer: namer
  187. )
  188. )
  189. )
  190. }
  191. )
  192. }
  193. }
  194. extension FunctionCallDescription {
  195. /// ```
  196. /// self.<Name>(request: request, context: context)
  197. /// ```
  198. static func serverMethodCallOnSelf(
  199. name: String,
  200. requestArgument: Expression = .identifierPattern("request")
  201. ) -> Self {
  202. return FunctionCallDescription(
  203. calledExpression: .memberAccess(
  204. MemberAccessDescription(
  205. left: .identifierPattern("self"),
  206. right: name
  207. )
  208. ),
  209. arguments: [
  210. FunctionArgumentDescription(
  211. label: "request",
  212. expression: requestArgument
  213. ),
  214. FunctionArgumentDescription(
  215. label: "context",
  216. expression: .identifierPattern("context")
  217. ),
  218. ]
  219. )
  220. }
  221. }
  222. extension ClosureInvocationDescription {
  223. /// ```
  224. /// { router, context in
  225. /// try await self.<Method>(
  226. /// request: request,
  227. /// context: context
  228. /// )
  229. /// }
  230. /// ```
  231. static func routerHandlerInvokingRPC(method: String) -> Self {
  232. return ClosureInvocationDescription(
  233. argumentNames: ["request", "context"],
  234. body: [
  235. .expression(
  236. .unaryKeyword(
  237. kind: .try,
  238. expression: .unaryKeyword(
  239. kind: .await,
  240. expression: .functionCall(.serverMethodCallOnSelf(name: method))
  241. )
  242. )
  243. )
  244. ]
  245. )
  246. }
  247. }
  248. /// ```
  249. /// router.registerHandler(
  250. /// forMethod: ...,
  251. /// deserializer: ...
  252. /// serializer: ...
  253. /// handler: { request, context in
  254. /// // ...
  255. /// }
  256. /// )
  257. /// ```
  258. extension FunctionCallDescription {
  259. static func registerWithRouter(
  260. serviceNamespace: String,
  261. methodNamespace: String,
  262. methodName: String,
  263. inputDeserializer: String,
  264. outputSerializer: String
  265. ) -> Self {
  266. return FunctionCallDescription(
  267. calledExpression: .memberAccess(
  268. .init(left: .identifierPattern("router"), right: "registerHandler")
  269. ),
  270. arguments: [
  271. FunctionArgumentDescription(
  272. label: "forMethod",
  273. expression: .identifierPattern("\(serviceNamespace).Method.\(methodNamespace).descriptor")
  274. ),
  275. FunctionArgumentDescription(
  276. label: "deserializer",
  277. expression: .identifierPattern(inputDeserializer)
  278. ),
  279. FunctionArgumentDescription(
  280. label: "serializer",
  281. expression: .identifierPattern(outputSerializer)
  282. ),
  283. FunctionArgumentDescription(
  284. label: "handler",
  285. expression: .closureInvocation(.routerHandlerInvokingRPC(method: methodName))
  286. ),
  287. ]
  288. )
  289. }
  290. }
  291. extension FunctionDescription {
  292. /// ```
  293. /// func registerMethods(with router: inout GRPCCore.RPCRouter) {
  294. /// // ...
  295. /// }
  296. /// ```
  297. static func registerMethods(
  298. accessLevel: AccessModifier? = nil,
  299. serviceNamespace: String,
  300. methods: [MethodDescriptor],
  301. namer: Namer = Namer(),
  302. serializer: (String) -> String,
  303. deserializer: (String) -> String
  304. ) -> Self {
  305. return FunctionDescription(
  306. accessModifier: accessLevel,
  307. kind: .function(name: "registerMethods"),
  308. generics: [.member("Transport")],
  309. parameters: [
  310. ParameterDescription(
  311. label: "with",
  312. name: "router",
  313. type: namer.rpcRouter(genericOver: "Transport"),
  314. `inout`: true
  315. )
  316. ],
  317. whereClause: WhereClause(
  318. requirements: [
  319. .conformance("Transport", namer.literalNamespacedType("ServerTransport"))
  320. ]
  321. ),
  322. body: methods.map { method in
  323. .functionCall(
  324. .registerWithRouter(
  325. serviceNamespace: serviceNamespace,
  326. methodNamespace: method.name.typeName,
  327. methodName: method.name.functionName,
  328. inputDeserializer: deserializer(method.inputType),
  329. outputSerializer: serializer(method.outputType)
  330. )
  331. )
  332. }
  333. )
  334. }
  335. }
  336. extension FunctionDescription {
  337. /// ```
  338. /// func <Name>(
  339. /// request: GRPCCore.StreamingServerRequest<Input>
  340. /// context: GRPCCore.ServerContext
  341. /// ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  342. /// let response = try await self.<Name>(
  343. /// request: GRPCCore.ServerRequest(stream: request),
  344. /// context: context
  345. /// )
  346. /// return GRPCCore.StreamingServerResponse(single: response)
  347. /// }
  348. /// ```
  349. static func serverStreamingMethodsCallingMethod(
  350. accessLevel: AccessModifier? = nil,
  351. name: String,
  352. input: String,
  353. output: String,
  354. streamingInput: Bool,
  355. streamingOutput: Bool,
  356. namer: Namer = Namer()
  357. ) -> FunctionDescription {
  358. let signature: FunctionSignatureDescription = .serverMethod(
  359. accessLevel: accessLevel,
  360. name: name,
  361. input: input,
  362. output: output,
  363. // This method converts from the fully streamed version to the specified version.
  364. streamingInput: true,
  365. streamingOutput: true,
  366. namer: namer
  367. )
  368. // Call the underlying function.
  369. let functionCall: Expression = .functionCall(
  370. calledExpression: .memberAccess(
  371. MemberAccessDescription(
  372. left: .identifierPattern("self"),
  373. right: name
  374. )
  375. ),
  376. arguments: [
  377. FunctionArgumentDescription(
  378. label: "request",
  379. expression: streamingInput
  380. ? .identifierPattern("request")
  381. : .functionCall(
  382. calledExpression: .identifierType(
  383. namer.serverRequest(forType: nil, isStreaming: false)
  384. ),
  385. arguments: [
  386. FunctionArgumentDescription(
  387. label: "stream",
  388. expression: .identifierPattern("request")
  389. )
  390. ]
  391. )
  392. ),
  393. FunctionArgumentDescription(
  394. label: "context",
  395. expression: .identifierPattern("context")
  396. ),
  397. ]
  398. )
  399. // Call the function and assign to 'response'.
  400. let response: Declaration = .variable(
  401. kind: .let,
  402. left: "response",
  403. right: .unaryKeyword(
  404. kind: .try,
  405. expression: .unaryKeyword(
  406. kind: .await,
  407. expression: functionCall
  408. )
  409. )
  410. )
  411. // Build the return statement.
  412. let returnExpression: Expression = .unaryKeyword(
  413. kind: .return,
  414. expression: streamingOutput
  415. ? .identifierPattern("response")
  416. : .functionCall(
  417. calledExpression: .identifierType(namer.serverResponse(forType: nil, isStreaming: true)),
  418. arguments: [
  419. FunctionArgumentDescription(
  420. label: "single",
  421. expression: .identifierPattern("response")
  422. )
  423. ]
  424. )
  425. )
  426. return Self(
  427. signature: signature,
  428. body: [.declaration(response), .expression(returnExpression)]
  429. )
  430. }
  431. }
  432. extension ExtensionDescription {
  433. /// ```
  434. /// extension <ExtensionName> {
  435. /// func <Name>(
  436. /// request: GRPCCore.StreamingServerRequest<Input>
  437. /// context: GRPCCore.ServerContext
  438. /// ) async throws -> GRPCCore.StreamingServerResponse<Output> {
  439. /// let response = try await self.<Name>(
  440. /// request: GRPCCore.ServerRequest(stream: request),
  441. /// context: context
  442. /// )
  443. /// return GRPCCore.StreamingServerResponse(single: response)
  444. /// }
  445. /// ...
  446. /// }
  447. /// ```
  448. static func streamingServiceProtocolDefaultImplementation(
  449. accessModifier: AccessModifier? = nil,
  450. on extensionName: String,
  451. methods: [MethodDescriptor],
  452. namer: Namer = Namer()
  453. ) -> Self {
  454. return ExtensionDescription(
  455. onType: extensionName,
  456. declarations: methods.compactMap { method -> Declaration? in
  457. // Bidirectional streaming methods don't need a default implementation as their signatures
  458. // match across the two protocols.
  459. if method.isInputStreaming, method.isOutputStreaming { return nil }
  460. return .function(
  461. .serverStreamingMethodsCallingMethod(
  462. accessLevel: accessModifier,
  463. name: method.name.functionName,
  464. input: method.inputType,
  465. output: method.outputType,
  466. streamingInput: method.isInputStreaming,
  467. streamingOutput: method.isOutputStreaming,
  468. namer: namer
  469. )
  470. )
  471. }
  472. )
  473. }
  474. }
  475. extension FunctionSignatureDescription {
  476. /// ```
  477. /// func <Name>(
  478. /// request: <Input>,
  479. /// context: GRPCCore.ServerContext,
  480. /// ) async throws -> <Output>
  481. /// ```
  482. ///
  483. /// ```
  484. /// func <Name>(
  485. /// request: GRPCCore.RPCAsyncSequence<Input, any Error>,
  486. /// response: GRPCCore.RPCAsyncWriter<Output>
  487. /// context: GRPCCore.ServerContext,
  488. /// ) async throws
  489. /// ```
  490. static func simpleServerMethod(
  491. accessLevel: AccessModifier? = nil,
  492. name: String,
  493. input: String,
  494. output: String,
  495. streamingInput: Bool,
  496. streamingOutput: Bool,
  497. namer: Namer = Namer()
  498. ) -> Self {
  499. var parameters: [ParameterDescription] = [
  500. ParameterDescription(
  501. label: "request",
  502. type: streamingInput ? namer.rpcAsyncSequence(forType: input) : .member(input)
  503. )
  504. ]
  505. if streamingOutput {
  506. parameters.append(
  507. ParameterDescription(
  508. label: "response",
  509. type: namer.rpcWriter(forType: output)
  510. )
  511. )
  512. }
  513. parameters.append(ParameterDescription(label: "context", type: namer.serverContext))
  514. return FunctionSignatureDescription(
  515. accessModifier: accessLevel,
  516. kind: .function(name: name),
  517. parameters: parameters,
  518. keywords: [.async, .throws],
  519. returnType: streamingOutput ? nil : .identifier(.pattern(output))
  520. )
  521. }
  522. }
  523. extension ProtocolDescription {
  524. /// ```
  525. /// protocol SimpleServiceProtocol: <ServiceProtocol> {
  526. /// ...
  527. /// }
  528. /// ```
  529. static func simpleServiceProtocol(
  530. accessModifier: AccessModifier? = nil,
  531. name: String,
  532. serviceProtocol: String,
  533. methods: [MethodDescriptor],
  534. namer: Namer = Namer()
  535. ) -> Self {
  536. func docs(for method: MethodDescriptor) -> String {
  537. let summary = """
  538. /// Handle the "\(method.name.identifyingName)" method.
  539. """
  540. let requestText =
  541. method.isInputStreaming
  542. ? "A stream of `\(method.inputType)` messages."
  543. : "A `\(method.inputType)` message."
  544. var parameters = """
  545. /// - Parameters:
  546. /// - request: \(requestText)
  547. """
  548. if method.isOutputStreaming {
  549. parameters += "\n"
  550. parameters += """
  551. /// - response: A response stream of `\(method.outputType)` messages.
  552. """
  553. }
  554. parameters += "\n"
  555. parameters += """
  556. /// - context: Context providing information about the RPC.
  557. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  558. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  559. /// to an internal error.
  560. """
  561. if !method.isOutputStreaming {
  562. parameters += "\n"
  563. parameters += """
  564. /// - Returns: A `\(method.outputType)` to respond with.
  565. """
  566. }
  567. return Docs.interposeDocs(method.documentation, between: summary, and: parameters)
  568. }
  569. return ProtocolDescription(
  570. accessModifier: accessModifier,
  571. name: name,
  572. conformances: [serviceProtocol],
  573. members: methods.map { method in
  574. .commentable(
  575. .preFormatted(docs(for: method)),
  576. .function(
  577. signature: .simpleServerMethod(
  578. name: method.name.functionName,
  579. input: method.inputType,
  580. output: method.outputType,
  581. streamingInput: method.isInputStreaming,
  582. streamingOutput: method.isOutputStreaming,
  583. namer: namer
  584. )
  585. )
  586. )
  587. }
  588. )
  589. }
  590. }
  591. extension FunctionCallDescription {
  592. /// ```
  593. /// try await self.<Name>(
  594. /// request: request.message,
  595. /// response: writer,
  596. /// context: context
  597. /// )
  598. /// ```
  599. static func serviceMethodCallingSimpleMethod(
  600. name: String,
  601. input: String,
  602. output: String,
  603. streamingInput: Bool,
  604. streamingOutput: Bool
  605. ) -> Self {
  606. var arguments: [FunctionArgumentDescription] = [
  607. FunctionArgumentDescription(
  608. label: "request",
  609. expression: .identifierPattern("request").dot(streamingInput ? "messages" : "message")
  610. )
  611. ]
  612. if streamingOutput {
  613. arguments.append(
  614. FunctionArgumentDescription(
  615. label: "response",
  616. expression: .identifierPattern("writer")
  617. )
  618. )
  619. }
  620. arguments.append(
  621. FunctionArgumentDescription(
  622. label: "context",
  623. expression: .identifierPattern("context")
  624. )
  625. )
  626. return FunctionCallDescription(
  627. calledExpression: .try(.await(.identifierPattern("self").dot(name))),
  628. arguments: arguments
  629. )
  630. }
  631. }
  632. extension FunctionDescription {
  633. /// ```
  634. /// func <Name>(
  635. /// request: GRPCCore.ServerRequest<Input>,
  636. /// context: GRPCCore.ServerContext
  637. /// ) async throws -> GRPCCore.ServerResponse<Output> {
  638. /// return GRPCCore.ServerResponse<Output>(
  639. /// message: try await self.<Name>(
  640. /// request: request.message,
  641. /// context: context
  642. /// )
  643. /// metadata: [:]
  644. /// )
  645. /// }
  646. /// ```
  647. static func serviceProtocolDefaultImplementation(
  648. accessModifier: AccessModifier? = nil,
  649. name: String,
  650. input: String,
  651. output: String,
  652. streamingInput: Bool,
  653. streamingOutput: Bool,
  654. namer: Namer = Namer()
  655. ) -> Self {
  656. func makeUnaryOutputArguments() -> [FunctionArgumentDescription] {
  657. return [
  658. FunctionArgumentDescription(
  659. label: "message",
  660. expression: .functionCall(
  661. .serviceMethodCallingSimpleMethod(
  662. name: name,
  663. input: input,
  664. output: output,
  665. streamingInput: streamingInput,
  666. streamingOutput: streamingOutput
  667. )
  668. )
  669. ),
  670. FunctionArgumentDescription(label: "metadata", expression: .literal(.dictionary([]))),
  671. ]
  672. }
  673. func makeStreamingOutputArguments() -> [FunctionArgumentDescription] {
  674. return [
  675. FunctionArgumentDescription(label: "metadata", expression: .literal(.dictionary([]))),
  676. FunctionArgumentDescription(
  677. label: "producer",
  678. expression: .closureInvocation(
  679. argumentNames: ["writer"],
  680. body: [
  681. .expression(
  682. .functionCall(
  683. .serviceMethodCallingSimpleMethod(
  684. name: name,
  685. input: input,
  686. output: output,
  687. streamingInput: streamingInput,
  688. streamingOutput: streamingOutput
  689. )
  690. )
  691. ),
  692. .expression(.return(.literal(.dictionary([])))),
  693. ]
  694. )
  695. ),
  696. ]
  697. }
  698. return FunctionDescription(
  699. signature: .serverMethod(
  700. accessLevel: accessModifier,
  701. name: name,
  702. input: input,
  703. output: output,
  704. streamingInput: streamingInput,
  705. streamingOutput: streamingOutput,
  706. namer: namer
  707. ),
  708. body: [
  709. .expression(
  710. .functionCall(
  711. calledExpression: .return(
  712. .identifierType(
  713. namer.serverResponse(forType: output, isStreaming: streamingOutput)
  714. )
  715. ),
  716. arguments: streamingOutput ? makeStreamingOutputArguments() : makeUnaryOutputArguments()
  717. )
  718. )
  719. ]
  720. )
  721. }
  722. }
  723. extension ExtensionDescription {
  724. /// ```
  725. /// extension ServiceProtocol {
  726. /// ...
  727. /// }
  728. /// ```
  729. static func serviceProtocolDefaultImplementation(
  730. accessModifier: AccessModifier? = nil,
  731. on extensionName: String,
  732. methods: [MethodDescriptor],
  733. namer: Namer = Namer()
  734. ) -> Self {
  735. ExtensionDescription(
  736. onType: extensionName,
  737. declarations: methods.map { method in
  738. .function(
  739. .serviceProtocolDefaultImplementation(
  740. accessModifier: accessModifier,
  741. name: method.name.functionName,
  742. input: method.inputType,
  743. output: method.outputType,
  744. streamingInput: method.isInputStreaming,
  745. streamingOutput: method.isOutputStreaming,
  746. namer: namer
  747. )
  748. )
  749. }
  750. )
  751. }
  752. }