StructuredSwift+ClientTests.swift 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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. import Testing
  17. @testable import GRPCCodeGen
  18. extension StructuredSwiftTests {
  19. @Suite("Client")
  20. struct Client {
  21. @Test(
  22. "func <Method>(request:serializer:deserializer:options:onResponse:)",
  23. arguments: AccessModifier.allCases,
  24. RPCKind.allCases
  25. )
  26. @available(gRPCSwift 2.0, *)
  27. func clientMethodSignature(access: AccessModifier, kind: RPCKind) {
  28. let decl: FunctionSignatureDescription = .clientMethod(
  29. accessLevel: access,
  30. name: "foo",
  31. input: "FooInput",
  32. output: "FooOutput",
  33. streamingInput: kind.streamsInput,
  34. streamingOutput: kind.streamsOutput,
  35. includeDefaults: false,
  36. includeSerializers: true
  37. )
  38. let requestType = kind.streamsInput ? "StreamingClientRequest" : "ClientRequest"
  39. let responseType = kind.streamsOutput ? "StreamingClientResponse" : "ClientResponse"
  40. let expected = """
  41. \(access) func foo<Result>(
  42. request: GRPCCore.\(requestType)<FooInput>,
  43. serializer: some GRPCCore.MessageSerializer<FooInput>,
  44. deserializer: some GRPCCore.MessageDeserializer<FooOutput>,
  45. options: GRPCCore.CallOptions,
  46. onResponse handleResponse: @Sendable @escaping (GRPCCore.\(responseType)<FooOutput>) async throws -> Result
  47. ) async throws -> Result where Result: Sendable
  48. """
  49. #expect(render(.function(signature: decl)) == expected)
  50. }
  51. @Test(
  52. "func <Method>(request:serializer:deserializer:options:onResponse:) (with defaults)",
  53. arguments: AccessModifier.allCases,
  54. [true, false]
  55. )
  56. @available(gRPCSwift 2.0, *)
  57. func clientMethodSignatureWithDefaults(access: AccessModifier, streamsOutput: Bool) {
  58. let decl: FunctionSignatureDescription = .clientMethod(
  59. accessLevel: access,
  60. name: "foo",
  61. input: "FooInput",
  62. output: "FooOutput",
  63. streamingInput: false,
  64. streamingOutput: streamsOutput,
  65. includeDefaults: true,
  66. includeSerializers: false
  67. )
  68. let expected: String
  69. if streamsOutput {
  70. expected = """
  71. \(access) func foo<Result>(
  72. request: GRPCCore.ClientRequest<FooInput>,
  73. options: GRPCCore.CallOptions = .defaults,
  74. onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<FooOutput>) async throws -> Result
  75. ) async throws -> Result where Result: Sendable
  76. """
  77. } else {
  78. expected = """
  79. \(access) func foo<Result>(
  80. request: GRPCCore.ClientRequest<FooInput>,
  81. options: GRPCCore.CallOptions = .defaults,
  82. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<FooOutput>) async throws -> Result = { response in
  83. try response.message
  84. }
  85. ) async throws -> Result where Result: Sendable
  86. """
  87. }
  88. #expect(render(.function(signature: decl)) == expected)
  89. }
  90. @Test("protocol Foo_ClientProtocol: Sendable { ... }", arguments: AccessModifier.allCases)
  91. @available(gRPCSwift 2.0, *)
  92. func clientProtocol(access: AccessModifier) {
  93. let decl: ProtocolDescription = .clientProtocol(
  94. accessLevel: access,
  95. name: "Foo_ClientProtocol",
  96. methods: [
  97. .init(
  98. documentation: "/// Some docs",
  99. name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"),
  100. isInputStreaming: false,
  101. isOutputStreaming: false,
  102. inputType: "BarInput",
  103. outputType: "BarOutput"
  104. )
  105. ]
  106. )
  107. let expected = """
  108. \(access) protocol Foo_ClientProtocol: Sendable {
  109. /// Call the "Bar" method.
  110. ///
  111. /// > Source IDL Documentation:
  112. /// >
  113. /// > Some docs
  114. ///
  115. /// - Parameters:
  116. /// - request: A request containing a single `BarInput` message.
  117. /// - serializer: A serializer for `BarInput` messages.
  118. /// - deserializer: A deserializer for `BarOutput` messages.
  119. /// - options: Options to apply to this RPC.
  120. /// - handleResponse: A closure which handles the response, the result of which is
  121. /// returned to the caller. Returning from the closure will cancel the RPC if it
  122. /// hasn't already finished.
  123. /// - Returns: The result of `handleResponse`.
  124. func bar<Result>(
  125. request: GRPCCore.ClientRequest<BarInput>,
  126. serializer: some GRPCCore.MessageSerializer<BarInput>,
  127. deserializer: some GRPCCore.MessageDeserializer<BarOutput>,
  128. options: GRPCCore.CallOptions,
  129. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<BarOutput>) async throws -> Result
  130. ) async throws -> Result where Result: Sendable
  131. }
  132. """
  133. #expect(render(.protocol(decl)) == expected)
  134. }
  135. @Test("func foo(...) { try await self.foo(...) }", arguments: AccessModifier.allCases)
  136. @available(gRPCSwift 2.0, *)
  137. func clientMethodFunctionWithDefaults(access: AccessModifier) {
  138. let decl: FunctionDescription = .clientMethodWithDefaults(
  139. accessLevel: access,
  140. name: "foo",
  141. input: "FooInput",
  142. output: "FooOutput",
  143. streamingInput: false,
  144. streamingOutput: false,
  145. serializer: .identifierPattern("Serialize<FooInput>()"),
  146. deserializer: .identifierPattern("Deserialize<FooOutput>()")
  147. )
  148. let expected = """
  149. \(access) func foo<Result>(
  150. request: GRPCCore.ClientRequest<FooInput>,
  151. options: GRPCCore.CallOptions = .defaults,
  152. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<FooOutput>) async throws -> Result = { response in
  153. try response.message
  154. }
  155. ) async throws -> Result where Result: Sendable {
  156. try await self.foo(
  157. request: request,
  158. serializer: Serialize<FooInput>(),
  159. deserializer: Deserialize<FooOutput>(),
  160. options: options,
  161. onResponse: handleResponse
  162. )
  163. }
  164. """
  165. #expect(render(.function(decl)) == expected)
  166. }
  167. @Test(
  168. "extension Foo_ClientProtocol { ... } (methods with defaults)",
  169. arguments: AccessModifier.allCases
  170. )
  171. @available(gRPCSwift 2.0, *)
  172. func extensionWithDefaultClientMethods(access: AccessModifier) {
  173. let decl: ExtensionDescription = .clientMethodSignatureWithDefaults(
  174. accessLevel: access,
  175. name: "Foo_ClientProtocol",
  176. methods: [
  177. MethodDescriptor(
  178. documentation: "",
  179. name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"),
  180. isInputStreaming: false,
  181. isOutputStreaming: false,
  182. inputType: "BarInput",
  183. outputType: "BarOutput"
  184. )
  185. ],
  186. serializer: { "Serialize<\($0)>()" },
  187. deserializer: { "Deserialize<\($0)>()" }
  188. )
  189. let expected = """
  190. extension Foo_ClientProtocol {
  191. /// Call the "Bar" method.
  192. ///
  193. /// - Parameters:
  194. /// - request: A request containing a single `BarInput` message.
  195. /// - options: Options to apply to this RPC.
  196. /// - handleResponse: A closure which handles the response, the result of which is
  197. /// returned to the caller. Returning from the closure will cancel the RPC if it
  198. /// hasn't already finished.
  199. /// - Returns: The result of `handleResponse`.
  200. \(access) func bar<Result>(
  201. request: GRPCCore.ClientRequest<BarInput>,
  202. options: GRPCCore.CallOptions = .defaults,
  203. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<BarOutput>) async throws -> Result = { response in
  204. try response.message
  205. }
  206. ) async throws -> Result where Result: Sendable {
  207. try await self.bar(
  208. request: request,
  209. serializer: Serialize<BarInput>(),
  210. deserializer: Deserialize<BarOutput>(),
  211. options: options,
  212. onResponse: handleResponse
  213. )
  214. }
  215. }
  216. """
  217. #expect(render(.extension(decl)) == expected)
  218. }
  219. @Test(
  220. "func foo<Result>(_:metadata:options:onResponse:) -> Result (exploded signature)",
  221. arguments: AccessModifier.allCases,
  222. RPCKind.allCases
  223. )
  224. @available(gRPCSwift 2.0, *)
  225. func explodedClientMethodSignature(access: AccessModifier, kind: RPCKind) {
  226. let decl: FunctionSignatureDescription = .clientMethodExploded(
  227. accessLevel: access,
  228. name: "foo",
  229. input: "Input",
  230. output: "Output",
  231. streamingInput: kind.streamsInput,
  232. streamingOutput: kind.streamsOutput
  233. )
  234. let expected: String
  235. switch kind {
  236. case .unary:
  237. expected = """
  238. \(access) func foo<Result>(
  239. _ message: Input,
  240. metadata: GRPCCore.Metadata = [:],
  241. options: GRPCCore.CallOptions = .defaults,
  242. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<Output>) async throws -> Result = { response in
  243. try response.message
  244. }
  245. ) async throws -> Result where Result: Sendable
  246. """
  247. case .clientStreaming:
  248. expected = """
  249. \(access) func foo<Result>(
  250. metadata: GRPCCore.Metadata = [:],
  251. options: GRPCCore.CallOptions = .defaults,
  252. requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter<Input>) async throws -> Void,
  253. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<Output>) async throws -> Result = { response in
  254. try response.message
  255. }
  256. ) async throws -> Result where Result: Sendable
  257. """
  258. case .serverStreaming:
  259. expected = """
  260. \(access) func foo<Result>(
  261. _ message: Input,
  262. metadata: GRPCCore.Metadata = [:],
  263. options: GRPCCore.CallOptions = .defaults,
  264. onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<Output>) async throws -> Result
  265. ) async throws -> Result where Result: Sendable
  266. """
  267. case .bidirectionalStreaming:
  268. expected = """
  269. \(access) func foo<Result>(
  270. metadata: GRPCCore.Metadata = [:],
  271. options: GRPCCore.CallOptions = .defaults,
  272. requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter<Input>) async throws -> Void,
  273. onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<Output>) async throws -> Result
  274. ) async throws -> Result where Result: Sendable
  275. """
  276. }
  277. #expect(render(.function(signature: decl)) == expected)
  278. }
  279. @Test(
  280. "func foo<Result>(_:metadata:options:onResponse:) -> Result (exploded body)",
  281. arguments: [true, false]
  282. )
  283. @available(gRPCSwift 2.0, *)
  284. func explodedClientMethodBody(streamingInput: Bool) {
  285. let blocks: [CodeBlock] = .clientMethodExploded(
  286. name: "foo",
  287. input: "Input",
  288. streamingInput: streamingInput
  289. )
  290. let expected: String
  291. if streamingInput {
  292. expected = """
  293. let request = GRPCCore.StreamingClientRequest<Input>(
  294. metadata: metadata,
  295. producer: producer
  296. )
  297. return try await self.foo(
  298. request: request,
  299. options: options,
  300. onResponse: handleResponse
  301. )
  302. """
  303. } else {
  304. expected = """
  305. let request = GRPCCore.ClientRequest<Input>(
  306. message: message,
  307. metadata: metadata
  308. )
  309. return try await self.foo(
  310. request: request,
  311. options: options,
  312. onResponse: handleResponse
  313. )
  314. """
  315. }
  316. #expect(render(blocks) == expected)
  317. }
  318. @Test("extension Foo_ClientProtocol { ... } (exploded)", arguments: AccessModifier.allCases)
  319. @available(gRPCSwift 2.0, *)
  320. func explodedClientMethodExtension(access: AccessModifier) {
  321. let decl: ExtensionDescription = .explodedClientMethods(
  322. accessLevel: access,
  323. on: "Foo_ClientProtocol",
  324. methods: [
  325. .init(
  326. documentation: "/// Some docs",
  327. name: MethodName(identifyingName: "Bar", typeName: "Bar", functionName: "bar"),
  328. isInputStreaming: false,
  329. isOutputStreaming: true,
  330. inputType: "Input",
  331. outputType: "Output"
  332. )
  333. ]
  334. )
  335. let expected = """
  336. extension Foo_ClientProtocol {
  337. /// Call the "Bar" method.
  338. ///
  339. /// > Source IDL Documentation:
  340. /// >
  341. /// > Some docs
  342. ///
  343. /// - Parameters:
  344. /// - message: request message to send.
  345. /// - metadata: Additional metadata to send, defaults to empty.
  346. /// - options: Options to apply to this RPC, defaults to `.defaults`.
  347. /// - handleResponse: A closure which handles the response, the result of which is
  348. /// returned to the caller. Returning from the closure will cancel the RPC if it
  349. /// hasn't already finished.
  350. /// - Returns: The result of `handleResponse`.
  351. \(access) func bar<Result>(
  352. _ message: Input,
  353. metadata: GRPCCore.Metadata = [:],
  354. options: GRPCCore.CallOptions = .defaults,
  355. onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<Output>) async throws -> Result
  356. ) async throws -> Result where Result: Sendable {
  357. let request = GRPCCore.ClientRequest<Input>(
  358. message: message,
  359. metadata: metadata
  360. )
  361. return try await self.bar(
  362. request: request,
  363. options: options,
  364. onResponse: handleResponse
  365. )
  366. }
  367. }
  368. """
  369. #expect(render(.extension(decl)) == expected)
  370. }
  371. @Test(
  372. "func foo(request:serializer:deserializer:options:onResponse:) (client method impl.)",
  373. arguments: AccessModifier.allCases
  374. )
  375. @available(gRPCSwift 2.0, *)
  376. func clientMethodImplementation(access: AccessModifier) {
  377. let decl: FunctionDescription = .clientMethod(
  378. accessLevel: access,
  379. name: "foo",
  380. input: "Input",
  381. output: "Output",
  382. serviceEnum: "BarService",
  383. methodEnum: "Foo",
  384. streamingInput: false,
  385. streamingOutput: false
  386. )
  387. let expected = """
  388. \(access) func foo<Result>(
  389. request: GRPCCore.ClientRequest<Input>,
  390. serializer: some GRPCCore.MessageSerializer<Input>,
  391. deserializer: some GRPCCore.MessageDeserializer<Output>,
  392. options: GRPCCore.CallOptions = .defaults,
  393. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<Output>) async throws -> Result = { response in
  394. try response.message
  395. }
  396. ) async throws -> Result where Result: Sendable {
  397. try await self.client.unary(
  398. request: request,
  399. descriptor: BarService.Method.Foo.descriptor,
  400. serializer: serializer,
  401. deserializer: deserializer,
  402. options: options,
  403. onResponse: handleResponse
  404. )
  405. }
  406. """
  407. #expect(render(.function(decl)) == expected)
  408. }
  409. @Test("struct FooClient: Foo_ClientProtocol { ... }", arguments: AccessModifier.allCases)
  410. @available(gRPCSwift 2.0, *)
  411. func client(access: AccessModifier) {
  412. let decl: StructDescription = .client(
  413. accessLevel: access,
  414. name: "FooClient",
  415. serviceEnum: "BarService",
  416. clientProtocol: "Foo_ClientProtocol",
  417. methods: [
  418. .init(
  419. documentation: "/// Unary docs",
  420. name: MethodName(
  421. identifyingName: "Unary",
  422. typeName: "Unary",
  423. functionName: "unary"
  424. ),
  425. isInputStreaming: false,
  426. isOutputStreaming: false,
  427. inputType: "Input",
  428. outputType: "Output"
  429. ),
  430. .init(
  431. documentation: "/// ClientStreaming docs",
  432. name: MethodName(
  433. identifyingName: "ClientStreaming",
  434. typeName: "ClientStreaming",
  435. functionName: "clientStreaming"
  436. ),
  437. isInputStreaming: true,
  438. isOutputStreaming: false,
  439. inputType: "Input",
  440. outputType: "Output"
  441. ),
  442. .init(
  443. documentation: "/// ServerStreaming docs",
  444. name: MethodName(
  445. identifyingName: "ServerStreaming",
  446. typeName: "ServerStreaming",
  447. functionName: "serverStreaming"
  448. ),
  449. isInputStreaming: false,
  450. isOutputStreaming: true,
  451. inputType: "Input",
  452. outputType: "Output"
  453. ),
  454. .init(
  455. documentation: "/// BidiStreaming docs",
  456. name: MethodName(
  457. identifyingName: "BidiStreaming",
  458. typeName: "BidiStreaming",
  459. functionName: "bidiStreaming"
  460. ),
  461. isInputStreaming: true,
  462. isOutputStreaming: true,
  463. inputType: "Input",
  464. outputType: "Output"
  465. ),
  466. ]
  467. )
  468. let expected = """
  469. \(access) struct FooClient<Transport>: Foo_ClientProtocol where Transport: GRPCCore.ClientTransport {
  470. private let client: GRPCCore.GRPCClient<Transport>
  471. /// Creates a new client wrapping the provided `GRPCCore.GRPCClient`.
  472. ///
  473. /// - Parameters:
  474. /// - client: A `GRPCCore.GRPCClient` providing a communication channel to the service.
  475. \(access) init(wrapping client: GRPCCore.GRPCClient<Transport>) {
  476. self.client = client
  477. }
  478. /// Call the "Unary" method.
  479. ///
  480. /// > Source IDL Documentation:
  481. /// >
  482. /// > Unary docs
  483. ///
  484. /// - Parameters:
  485. /// - request: A request containing a single `Input` message.
  486. /// - serializer: A serializer for `Input` messages.
  487. /// - deserializer: A deserializer for `Output` messages.
  488. /// - options: Options to apply to this RPC.
  489. /// - handleResponse: A closure which handles the response, the result of which is
  490. /// returned to the caller. Returning from the closure will cancel the RPC if it
  491. /// hasn't already finished.
  492. /// - Returns: The result of `handleResponse`.
  493. \(access) func unary<Result>(
  494. request: GRPCCore.ClientRequest<Input>,
  495. serializer: some GRPCCore.MessageSerializer<Input>,
  496. deserializer: some GRPCCore.MessageDeserializer<Output>,
  497. options: GRPCCore.CallOptions = .defaults,
  498. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<Output>) async throws -> Result = { response in
  499. try response.message
  500. }
  501. ) async throws -> Result where Result: Sendable {
  502. try await self.client.unary(
  503. request: request,
  504. descriptor: BarService.Method.Unary.descriptor,
  505. serializer: serializer,
  506. deserializer: deserializer,
  507. options: options,
  508. onResponse: handleResponse
  509. )
  510. }
  511. /// Call the "ClientStreaming" method.
  512. ///
  513. /// > Source IDL Documentation:
  514. /// >
  515. /// > ClientStreaming docs
  516. ///
  517. /// - Parameters:
  518. /// - request: A streaming request producing `Input` messages.
  519. /// - serializer: A serializer for `Input` messages.
  520. /// - deserializer: A deserializer for `Output` messages.
  521. /// - options: Options to apply to this RPC.
  522. /// - handleResponse: A closure which handles the response, the result of which is
  523. /// returned to the caller. Returning from the closure will cancel the RPC if it
  524. /// hasn't already finished.
  525. /// - Returns: The result of `handleResponse`.
  526. \(access) func clientStreaming<Result>(
  527. request: GRPCCore.StreamingClientRequest<Input>,
  528. serializer: some GRPCCore.MessageSerializer<Input>,
  529. deserializer: some GRPCCore.MessageDeserializer<Output>,
  530. options: GRPCCore.CallOptions = .defaults,
  531. onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<Output>) async throws -> Result = { response in
  532. try response.message
  533. }
  534. ) async throws -> Result where Result: Sendable {
  535. try await self.client.clientStreaming(
  536. request: request,
  537. descriptor: BarService.Method.ClientStreaming.descriptor,
  538. serializer: serializer,
  539. deserializer: deserializer,
  540. options: options,
  541. onResponse: handleResponse
  542. )
  543. }
  544. /// Call the "ServerStreaming" method.
  545. ///
  546. /// > Source IDL Documentation:
  547. /// >
  548. /// > ServerStreaming docs
  549. ///
  550. /// - Parameters:
  551. /// - request: A request containing a single `Input` message.
  552. /// - serializer: A serializer for `Input` messages.
  553. /// - deserializer: A deserializer for `Output` messages.
  554. /// - options: Options to apply to this RPC.
  555. /// - handleResponse: A closure which handles the response, the result of which is
  556. /// returned to the caller. Returning from the closure will cancel the RPC if it
  557. /// hasn't already finished.
  558. /// - Returns: The result of `handleResponse`.
  559. \(access) func serverStreaming<Result>(
  560. request: GRPCCore.ClientRequest<Input>,
  561. serializer: some GRPCCore.MessageSerializer<Input>,
  562. deserializer: some GRPCCore.MessageDeserializer<Output>,
  563. options: GRPCCore.CallOptions = .defaults,
  564. onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<Output>) async throws -> Result
  565. ) async throws -> Result where Result: Sendable {
  566. try await self.client.serverStreaming(
  567. request: request,
  568. descriptor: BarService.Method.ServerStreaming.descriptor,
  569. serializer: serializer,
  570. deserializer: deserializer,
  571. options: options,
  572. onResponse: handleResponse
  573. )
  574. }
  575. /// Call the "BidiStreaming" method.
  576. ///
  577. /// > Source IDL Documentation:
  578. /// >
  579. /// > BidiStreaming docs
  580. ///
  581. /// - Parameters:
  582. /// - request: A streaming request producing `Input` messages.
  583. /// - serializer: A serializer for `Input` messages.
  584. /// - deserializer: A deserializer for `Output` messages.
  585. /// - options: Options to apply to this RPC.
  586. /// - handleResponse: A closure which handles the response, the result of which is
  587. /// returned to the caller. Returning from the closure will cancel the RPC if it
  588. /// hasn't already finished.
  589. /// - Returns: The result of `handleResponse`.
  590. \(access) func bidiStreaming<Result>(
  591. request: GRPCCore.StreamingClientRequest<Input>,
  592. serializer: some GRPCCore.MessageSerializer<Input>,
  593. deserializer: some GRPCCore.MessageDeserializer<Output>,
  594. options: GRPCCore.CallOptions = .defaults,
  595. onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<Output>) async throws -> Result
  596. ) async throws -> Result where Result: Sendable {
  597. try await self.client.bidirectionalStreaming(
  598. request: request,
  599. descriptor: BarService.Method.BidiStreaming.descriptor,
  600. serializer: serializer,
  601. deserializer: deserializer,
  602. options: options,
  603. onResponse: handleResponse
  604. )
  605. }
  606. }
  607. """
  608. #expect(render(.struct(decl)) == expected)
  609. }
  610. }
  611. }