xref: /aosp_15_r20/external/pigweed/pw_rpc/pwpb/public/pw_rpc/pwpb/client_reader_writer.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // This file defines the ClientReaderWriter, ClientReader, ClientWriter,
16 // and UnaryReceiver classes for the pw_protobuf RPC interface. These classes
17 // are used for bidirectional, client, and server streaming, and unary RPCs.
18 #pragma once
19 
20 #include "pw_bytes/span.h"
21 #include "pw_function/function.h"
22 #include "pw_rpc/channel.h"
23 #include "pw_rpc/internal/client_call.h"
24 #include "pw_rpc/internal/config.h"
25 #include "pw_rpc/pwpb/internal/common.h"
26 
27 #if PW_RPC_DYNAMIC_ALLOCATION
28 #include PW_RPC_MAKE_UNIQUE_PTR_INCLUDE
29 #endif  // PW_RPC_DYNAMIC_ALLOCATION
30 
31 namespace pw::rpc {
32 namespace internal {
33 
34 // internal::PwpbUnaryResponseClientCall extends
35 // internal::UnaryResponseClientCall by adding a method serializer/deserializer
36 // passed in to Start(), typed request messages to the Start() call, and an
37 // on_completed callback templated on the response type.
38 template <typename Response>
39 class PwpbUnaryResponseClientCall : public UnaryResponseClientCall {
40  public:
41   // Start() can be called with zero or one request objects.
42   template <typename CallType, typename... Request>
Start(Endpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde,Function<void (const Response &,Status)> && on_completed,Function<void (Status)> && on_error,const Request &...request)43   static CallType Start(Endpoint& client,
44                         uint32_t channel_id,
45                         uint32_t service_id,
46                         uint32_t method_id,
47                         const PwpbMethodSerde& serde,
48                         Function<void(const Response&, Status)>&& on_completed,
49                         Function<void(Status)>&& on_error,
50                         const Request&... request)
51       PW_LOCKS_EXCLUDED(rpc_lock()) {
52     rpc_lock().lock();
53     CallType call(
54         client.ClaimLocked(), channel_id, service_id, method_id, serde);
55     SetCallbacksAndSendRequest(call,
56                                client,
57                                serde,
58                                std::move(on_completed),
59                                std::move(on_error),
60                                request...);
61     return call;
62   }
63 
64   template <typename CallType, typename... Request>
StartDynamic(Endpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde,Function<void (const Response &,Status)> && on_completed,Function<void (Status)> && on_error,const Request &...request)65   static auto StartDynamic(
66       Endpoint& client,
67       uint32_t channel_id,
68       uint32_t service_id,
69       uint32_t method_id,
70       const PwpbMethodSerde& serde,
71       Function<void(const Response&, Status)>&& on_completed,
72       Function<void(Status)>&& on_error,
73       const Request&... request) PW_LOCKS_EXCLUDED(rpc_lock()) {
74     rpc_lock().lock();
75     auto call = PW_RPC_MAKE_UNIQUE_PTR(CallType,
76                                        client.ClaimLocked(),
77                                        channel_id,
78                                        service_id,
79                                        method_id,
80                                        serde);
81     SetCallbacksAndSendRequest(*call,
82                                client,
83                                serde,
84                                std::move(on_completed),
85                                std::move(on_error),
86                                request...);
87     return call;
88   }
89 
90  protected:
91   // Derived classes allow default construction so that users can declare a
92   // variable into which to move client reader/writers from RPC calls.
PwpbUnaryResponseClientCall()93   constexpr PwpbUnaryResponseClientCall() : serde_(nullptr) {}
94 
PwpbUnaryResponseClientCall(LockedEndpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,MethodType type,const PwpbMethodSerde & serde)95   PwpbUnaryResponseClientCall(LockedEndpoint& client,
96                               uint32_t channel_id,
97                               uint32_t service_id,
98                               uint32_t method_id,
99                               MethodType type,
100                               const PwpbMethodSerde& serde)
101       PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock())
102       : UnaryResponseClientCall(
103             client, channel_id, service_id, method_id, StructCallProps(type)),
104         serde_(&serde) {}
105 
106   // Allow derived classes to be constructed moving another instance.
107   PwpbUnaryResponseClientCall(PwpbUnaryResponseClientCall&& other)
PW_LOCKS_EXCLUDED(rpc_lock ())108       PW_LOCKS_EXCLUDED(rpc_lock()) {
109     *this = std::move(other);
110   }
111 
112   // Allow derived classes to use move assignment from another instance.
113   PwpbUnaryResponseClientCall& operator=(PwpbUnaryResponseClientCall&& other)
PW_LOCKS_EXCLUDED(rpc_lock ())114       PW_LOCKS_EXCLUDED(rpc_lock()) {
115     RpcLockGuard lock;
116     MovePwpbUnaryResponseClientCallFrom(other);
117     return *this;
118   }
119 
~PwpbUnaryResponseClientCall()120   ~PwpbUnaryResponseClientCall() { DestroyClientCall(); }
121 
122   // Implement moving by copying the serde pointer and on_completed function.
MovePwpbUnaryResponseClientCallFrom(PwpbUnaryResponseClientCall & other)123   void MovePwpbUnaryResponseClientCallFrom(PwpbUnaryResponseClientCall& other)
124       PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) {
125     MoveUnaryResponseClientCallFrom(other);
126     serde_ = other.serde_;
127     set_pwpb_on_completed_locked(std::move(other.pwpb_on_completed_));
128   }
129 
set_on_completed(Function<void (const Response & response,Status)> && on_completed)130   void set_on_completed(
131       Function<void(const Response& response, Status)>&& on_completed)
132       PW_LOCKS_EXCLUDED(rpc_lock()) {
133     RpcLockGuard lock;
134     set_pwpb_on_completed_locked(std::move(on_completed));
135   }
136 
137   // Sends a streamed request.
138   // Returns the following Status codes:
139   //
140   //   OK - the request was successfully sent
141   //   FAILED_PRECONDITION - the writer is closed
142   //   INTERNAL - pw_rpc was unable to encode the pw_protobuf protobuf
143   //   other errors - the ChannelOutput failed to send the packet; the error
144   //       codes are determined by the ChannelOutput implementation
145   //
146   template <typename Request>
SendStreamRequest(const Request & request)147   Status SendStreamRequest(const Request& request)
148       PW_LOCKS_EXCLUDED(rpc_lock()) {
149     RpcLockGuard lock;
150     return PwpbSendStream(*this, request, serde_);
151   }
152 
153  private:
154   template <typename CallType, typename... Request>
SetCallbacksAndSendRequest(CallType & call,Endpoint & client,const PwpbMethodSerde & serde,Function<void (const Response &,Status)> && on_completed,Function<void (Status)> && on_error,const Request &...request)155   static void SetCallbacksAndSendRequest(
156       CallType& call,
157       Endpoint& client,
158       const PwpbMethodSerde& serde,
159       Function<void(const Response&, Status)>&& on_completed,
160       Function<void(Status)>&& on_error,
161       const Request&... request) PW_UNLOCK_FUNCTION(rpc_lock()) {
162     call.set_pwpb_on_completed_locked(std::move(on_completed));
163     call.set_on_error_locked(std::move(on_error));
164 
165     if constexpr (sizeof...(Request) == 0u) {
166       call.SendInitialClientRequest({});
167     } else {
168       PwpbSendInitialRequest(call, serde.request(), request...);
169     }
170 
171     client.CleanUpCalls();
172   }
173 
set_pwpb_on_completed_locked(Function<void (const Response & response,Status)> && on_completed)174   void set_pwpb_on_completed_locked(
175       Function<void(const Response& response, Status)>&& on_completed)
176       PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) {
177     pwpb_on_completed_ = std::move(on_completed);
178 
179     UnaryResponseClientCall::set_on_completed_locked(
180         [this](ConstByteSpan payload, Status status)
181             PW_NO_LOCK_SAFETY_ANALYSIS {
182               DecodeToStructAndInvokeOnCompleted(
183                   payload, serde_->response(), pwpb_on_completed_, status);
184             });
185   }
186 
187   const PwpbMethodSerde* serde_ PW_GUARDED_BY(rpc_lock());
188   Function<void(const Response&, Status)> pwpb_on_completed_
189       PW_GUARDED_BY(rpc_lock());
190 };
191 
192 // internal::PwpbStreamResponseClientCall extends
193 // internal::StreamResponseClientCall by adding a method serializer/deserializer
194 // passed in to Start(), typed request messages to the Start() call, and an
195 // on_next callback templated on the response type.
196 template <typename Response>
197 class PwpbStreamResponseClientCall : public StreamResponseClientCall {
198  public:
199   // Start() can be called with zero or one request objects.
200   template <typename CallType, typename... Request>
Start(Endpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde,Function<void (const Response &)> && on_next,Function<void (Status)> && on_completed,Function<void (Status)> && on_error,const Request &...request)201   static CallType Start(Endpoint& client,
202                         uint32_t channel_id,
203                         uint32_t service_id,
204                         uint32_t method_id,
205                         const PwpbMethodSerde& serde,
206                         Function<void(const Response&)>&& on_next,
207                         Function<void(Status)>&& on_completed,
208                         Function<void(Status)>&& on_error,
209                         const Request&... request)
210       PW_LOCKS_EXCLUDED(rpc_lock()) {
211     rpc_lock().lock();
212     CallType call(
213         client.ClaimLocked(), channel_id, service_id, method_id, serde);
214     SetCallbacksAndSendRequest(call,
215                                client,
216                                serde,
217                                std::move(on_next),
218                                std::move(on_completed),
219                                std::move(on_error),
220                                request...);
221     return call;
222   }
223 
224   template <typename CallType, typename... Request>
StartDynamic(Endpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde,Function<void (const Response &)> && on_next,Function<void (Status)> && on_completed,Function<void (Status)> && on_error,const Request &...request)225   static auto StartDynamic(Endpoint& client,
226                            uint32_t channel_id,
227                            uint32_t service_id,
228                            uint32_t method_id,
229                            const PwpbMethodSerde& serde,
230                            Function<void(const Response&)>&& on_next,
231                            Function<void(Status)>&& on_completed,
232                            Function<void(Status)>&& on_error,
233                            const Request&... request)
234       PW_LOCKS_EXCLUDED(rpc_lock()) {
235     rpc_lock().lock();
236     auto call = PW_RPC_MAKE_UNIQUE_PTR(CallType,
237                                        client.ClaimLocked(),
238                                        channel_id,
239                                        service_id,
240                                        method_id,
241                                        serde);
242     SetCallbacksAndSendRequest(*call,
243                                client,
244                                serde,
245                                std::move(on_next),
246                                std::move(on_completed),
247                                std::move(on_error),
248                                request...);
249     return call;
250   }
251 
252  protected:
253   // Derived classes allow default construction so that users can declare a
254   // variable into which to move client reader/writers from RPC calls.
PwpbStreamResponseClientCall()255   constexpr PwpbStreamResponseClientCall() : serde_(nullptr) {}
256 
PwpbStreamResponseClientCall(LockedEndpoint & client,uint32_t channel_id,uint32_t service_id,uint32_t method_id,MethodType type,const PwpbMethodSerde & serde)257   PwpbStreamResponseClientCall(LockedEndpoint& client,
258                                uint32_t channel_id,
259                                uint32_t service_id,
260                                uint32_t method_id,
261                                MethodType type,
262                                const PwpbMethodSerde& serde)
263       PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock())
264       : StreamResponseClientCall(
265             client, channel_id, service_id, method_id, StructCallProps(type)),
266         serde_(&serde) {}
267 
268   // Allow derived classes to be constructed moving another instance.
269   PwpbStreamResponseClientCall(PwpbStreamResponseClientCall&& other)
PW_LOCKS_EXCLUDED(rpc_lock ())270       PW_LOCKS_EXCLUDED(rpc_lock()) {
271     *this = std::move(other);
272   }
273 
274   // Allow derived classes to use move assignment from another instance.
275   PwpbStreamResponseClientCall& operator=(PwpbStreamResponseClientCall&& other)
PW_LOCKS_EXCLUDED(rpc_lock ())276       PW_LOCKS_EXCLUDED(rpc_lock()) {
277     RpcLockGuard lock;
278     MovePwpbStreamResponseClientCallFrom(other);
279     return *this;
280   }
281 
~PwpbStreamResponseClientCall()282   ~PwpbStreamResponseClientCall() { DestroyClientCall(); }
283 
284   // Implement moving by copying the serde pointer and on_next function.
MovePwpbStreamResponseClientCallFrom(PwpbStreamResponseClientCall & other)285   void MovePwpbStreamResponseClientCallFrom(PwpbStreamResponseClientCall& other)
286       PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) {
287     MoveStreamResponseClientCallFrom(other);
288     serde_ = other.serde_;
289     set_pwpb_on_next_locked(std::move(other.pwpb_on_next_));
290   }
291 
set_on_next(Function<void (const Response & response)> && on_next)292   void set_on_next(Function<void(const Response& response)>&& on_next)
293       PW_LOCKS_EXCLUDED(rpc_lock()) {
294     RpcLockGuard lock;
295     set_pwpb_on_next_locked(std::move(on_next));
296   }
297 
298   // Sends a streamed request.
299   // Returns the following Status codes:
300   //
301   //   OK - the request was successfully sent
302   //   FAILED_PRECONDITION - the writer is closed
303   //   INTERNAL - pw_rpc was unable to encode the pw_protobuf protobuf
304   //   other errors - the ChannelOutput failed to send the packet; the error
305   //       codes are determined by the ChannelOutput implementation
306   //
307   template <typename Request>
SendStreamRequest(const Request & request)308   Status SendStreamRequest(const Request& request)
309       PW_LOCKS_EXCLUDED(rpc_lock()) {
310     RpcLockGuard lock;
311     return PwpbSendStream(*this, request, serde_);
312   }
313 
314  private:
315   template <typename CallType, typename... Request>
SetCallbacksAndSendRequest(CallType & call,Endpoint & client,const PwpbMethodSerde & serde,Function<void (const Response &)> && on_next,Function<void (Status)> && on_completed,Function<void (Status)> && on_error,const Request &...request)316   static void SetCallbacksAndSendRequest(
317       CallType& call,
318       Endpoint& client,
319       const PwpbMethodSerde& serde,
320       Function<void(const Response&)>&& on_next,
321       Function<void(Status)>&& on_completed,
322       Function<void(Status)>&& on_error,
323       const Request&... request) PW_UNLOCK_FUNCTION(rpc_lock()) {
324     call.set_pwpb_on_next_locked(std::move(on_next));
325     call.set_on_completed_locked(std::move(on_completed));
326     call.set_on_error_locked(std::move(on_error));
327 
328     if constexpr (sizeof...(Request) == 0u) {
329       call.SendInitialClientRequest({});
330     } else {
331       PwpbSendInitialRequest(call, serde.request(), request...);
332     }
333     client.CleanUpCalls();
334   }
335 
set_pwpb_on_next_locked(Function<void (const Response & response)> && on_next)336   void set_pwpb_on_next_locked(
337       Function<void(const Response& response)>&& on_next)
338       PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock()) {
339     pwpb_on_next_ = std::move(on_next);
340 
341     Call::set_on_next_locked(
342         [this](ConstByteSpan payload) PW_NO_LOCK_SAFETY_ANALYSIS {
343           DecodeToStructAndInvokeOnNext(
344               payload, serde_->response(), pwpb_on_next_);
345         });
346   }
347 
348   const PwpbMethodSerde* serde_ PW_GUARDED_BY(rpc_lock());
349   Function<void(const Response&)> pwpb_on_next_ PW_GUARDED_BY(rpc_lock());
350 };
351 
352 }  // namespace internal
353 
354 // The PwpbClientReaderWriter is used to send and receive typed messages in a
355 // pw_protobuf bidirectional streaming RPC.
356 //
357 // These classes use private inheritance to hide the internal::Call API while
358 // allow direct use of its public and protected functions.
359 template <typename Request, typename Response>
360 class PwpbClientReaderWriter
361     : private internal::PwpbStreamResponseClientCall<Response> {
362  public:
363   // Allow default construction so that users can declare a variable into
364   // which to move client reader/writers from RPC calls.
365   constexpr PwpbClientReaderWriter() = default;
366 
367   PwpbClientReaderWriter(PwpbClientReaderWriter&&) = default;
368   PwpbClientReaderWriter& operator=(PwpbClientReaderWriter&&) = default;
369 
370   using internal::Call::active;
371   using internal::Call::channel_id;
372 
373   // Writes a request. Returns the following Status codes:
374   //
375   //   OK - the request was successfully sent
376   //   FAILED_PRECONDITION - the writer is closed
377   //   INTERNAL - pw_rpc was unable to encode the pw_protobuf message
378   //   other errors - the ChannelOutput failed to send the packet; the error
379   //       codes are determined by the ChannelOutput implementation
380   //
Write(const Request & request)381   Status Write(const Request& request) {
382     return internal::PwpbStreamResponseClientCall<Response>::SendStreamRequest(
383         request);
384   }
385 
386   // Notifies the server that the client has requested to stop communication by
387   // sending CLIENT_REQUEST_COMPLETION.
388   using internal::ClientCall::RequestCompletion;
389 
390   // Cancels this RPC. Closes the call locally and sends a CANCELLED error to
391   // the server.
392   using internal::Call::Cancel;
393 
394   // Closes this RPC locally. Sends a CLIENT_REQUEST_COMPLETION, but no
395   // cancellation packet. Future packets for this RPC are dropped, and the
396   // client sends a FAILED_PRECONDITION error in response because the call is
397   // not active.
398   using internal::ClientCall::Abandon;
399 
400   // Closes this RPC locally and waits for any running callbacks to complete.
401   // Sends a CLIENT_REQUEST_COMPLETION, but no cancellation packet. Future
402   // packets for this RPC are dropped, and the client sends a
403   // FAILED_PRECONDITION error in response because the call is not active.
404   using internal::ClientCall::CloseAndWaitForCallbacks;
405 
406   // Functions for setting RPC event callbacks.
407   using internal::PwpbStreamResponseClientCall<Response>::set_on_next;
408   using internal::StreamResponseClientCall::set_on_completed;
409   using internal::StreamResponseClientCall::set_on_error;
410 
411  protected:
412   friend class internal::PwpbStreamResponseClientCall<Response>;
413 
PwpbClientReaderWriter(internal::LockedEndpoint & client,uint32_t channel_id_v,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde)414   PwpbClientReaderWriter(internal::LockedEndpoint& client,
415                          uint32_t channel_id_v,
416                          uint32_t service_id,
417                          uint32_t method_id,
418                          const PwpbMethodSerde& serde)
419       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
420       : internal::PwpbStreamResponseClientCall<Response>(
421             client,
422             channel_id_v,
423             service_id,
424             method_id,
425             MethodType::kBidirectionalStreaming,
426             serde) {}
427 };
428 
429 // The PwpbClientReader is used to receive typed messages and send a typed
430 // response in a pw_protobuf client streaming RPC.
431 //
432 // These classes use private inheritance to hide the internal::Call API while
433 // allow direct use of its public and protected functions.
434 template <typename Response>
435 class PwpbClientReader
436     : private internal::PwpbStreamResponseClientCall<Response> {
437  public:
438   // Allow default construction so that users can declare a variable into
439   // which to move client reader/writers from RPC calls.
440   constexpr PwpbClientReader() = default;
441 
442   PwpbClientReader(PwpbClientReader&&) = default;
443   PwpbClientReader& operator=(PwpbClientReader&&) = default;
444 
445   using internal::StreamResponseClientCall::active;
446   using internal::StreamResponseClientCall::channel_id;
447 
448   using internal::Call::Cancel;
449   using internal::Call::RequestCompletion;
450   using internal::ClientCall::Abandon;
451   using internal::ClientCall::CloseAndWaitForCallbacks;
452 
453   // Functions for setting RPC event callbacks.
454   using internal::PwpbStreamResponseClientCall<Response>::set_on_next;
455   using internal::StreamResponseClientCall::set_on_completed;
456   using internal::StreamResponseClientCall::set_on_error;
457 
458  private:
459   friend class internal::PwpbStreamResponseClientCall<Response>;
460 
PwpbClientReader(internal::LockedEndpoint & client,uint32_t channel_id_v,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde)461   PwpbClientReader(internal::LockedEndpoint& client,
462                    uint32_t channel_id_v,
463                    uint32_t service_id,
464                    uint32_t method_id,
465                    const PwpbMethodSerde& serde)
466       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
467       : internal::PwpbStreamResponseClientCall<Response>(
468             client,
469             channel_id_v,
470             service_id,
471             method_id,
472             MethodType::kServerStreaming,
473             serde) {}
474 };
475 
476 // The PwpbClientWriter is used to send typed responses in a pw_protobuf server
477 // streaming RPC.
478 //
479 // These classes use private inheritance to hide the internal::Call API while
480 // allow direct use of its public and protected functions.
481 template <typename Request, typename Response>
482 class PwpbClientWriter
483     : private internal::PwpbUnaryResponseClientCall<Response> {
484  public:
485   // Allow default construction so that users can declare a variable into
486   // which to move client reader/writers from RPC calls.
487   constexpr PwpbClientWriter() = default;
488 
489   PwpbClientWriter(PwpbClientWriter&&) = default;
490   PwpbClientWriter& operator=(PwpbClientWriter&&) = default;
491 
492   using internal::UnaryResponseClientCall::active;
493   using internal::UnaryResponseClientCall::channel_id;
494 
495   // Writes a request. Returns the following Status codes:
496   //
497   //   OK - the request was successfully sent
498   //   FAILED_PRECONDITION - the writer is closed
499   //   INTERNAL - pw_rpc was unable to encode the pw_protobuf message
500   //   other errors - the ChannelOutput failed to send the packet; the error
501   //       codes are determined by the ChannelOutput implementation
502   //
Write(const Request & request)503   Status Write(const Request& request) {
504     return internal::PwpbUnaryResponseClientCall<Response>::SendStreamRequest(
505         request);
506   }
507 
508   using internal::Call::Cancel;
509   using internal::Call::RequestCompletion;
510   using internal::ClientCall::Abandon;
511   using internal::ClientCall::CloseAndWaitForCallbacks;
512 
513   // Functions for setting RPC event callbacks.
514   using internal::PwpbUnaryResponseClientCall<Response>::set_on_completed;
515   using internal::UnaryResponseClientCall::set_on_error;
516 
517  private:
518   friend class internal::PwpbUnaryResponseClientCall<Response>;
519 
PwpbClientWriter(internal::LockedEndpoint & client,uint32_t channel_id_v,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde)520   PwpbClientWriter(internal::LockedEndpoint& client,
521                    uint32_t channel_id_v,
522                    uint32_t service_id,
523                    uint32_t method_id,
524                    const PwpbMethodSerde& serde)
525       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
526 
527       : internal::PwpbUnaryResponseClientCall<Response>(
528             client,
529             channel_id_v,
530             service_id,
531             method_id,
532             MethodType::kClientStreaming,
533             serde) {}
534 };
535 
536 // The PwpbUnaryReceiver is used to handle a typed response to a pw_protobuf
537 // unary RPC.
538 //
539 // These classes use private inheritance to hide the internal::Call API while
540 // allow direct use of its public and protected functions.
541 template <typename Response>
542 class PwpbUnaryReceiver
543     : private internal::PwpbUnaryResponseClientCall<Response> {
544  public:
545   // Allow default construction so that users can declare a variable into
546   // which to move client reader/writers from RPC calls.
547   constexpr PwpbUnaryReceiver() = default;
548 
549   PwpbUnaryReceiver(PwpbUnaryReceiver&&) = default;
550   PwpbUnaryReceiver& operator=(PwpbUnaryReceiver&&) = default;
551 
552   using internal::Call::active;
553   using internal::Call::channel_id;
554 
555   // Functions for setting RPC event callbacks.
556   using internal::Call::set_on_error;
557   using internal::PwpbUnaryResponseClientCall<Response>::set_on_completed;
558 
559   using internal::Call::Cancel;
560   using internal::ClientCall::Abandon;
561   using internal::ClientCall::CloseAndWaitForCallbacks;
562 
563  private:
564   friend class internal::PwpbUnaryResponseClientCall<Response>;
565 
PwpbUnaryReceiver(internal::LockedEndpoint & client,uint32_t channel_id_v,uint32_t service_id,uint32_t method_id,const PwpbMethodSerde & serde)566   PwpbUnaryReceiver(internal::LockedEndpoint& client,
567                     uint32_t channel_id_v,
568                     uint32_t service_id,
569                     uint32_t method_id,
570                     const PwpbMethodSerde& serde)
571       PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock())
572       : internal::PwpbUnaryResponseClientCall<Response>(client,
573                                                         channel_id_v,
574                                                         service_id,
575                                                         method_id,
576                                                         MethodType::kUnary,
577                                                         serde) {}
578 };
579 
580 }  // namespace pw::rpc
581