• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 #pragma once
15 
16 #include "pb_common.h"
17 #include "pw_bytes/span.h"
18 #include "pw_rpc/internal/lock.h"
19 #include "pw_status/status_with_size.h"
20 
21 namespace pw::rpc::internal {
22 
23 // Nanopb 0.3 uses pb_field_t, but Nanopb 4 uses pb_msgdesc_t. Determine which
24 // type to use by deducing it from the pb_field_iter_begin function.
25 template <typename PbFieldIterBeginFunction>
26 struct NanopbDescriptorTraits;
27 
28 template <typename T>
29 struct NanopbDescriptorTraits<bool(pb_field_iter_t*, T, void*)> {
30   using Type = T;
31 };
32 
33 using NanopbMessageDescriptor =
34     NanopbDescriptorTraits<decltype(pb_field_iter_begin)>::Type;
35 
36 // Serializer/deserializer for a Nanopb protobuf message.
37 class NanopbSerde {
38  public:
39   explicit constexpr NanopbSerde(NanopbMessageDescriptor fields)
40       : fields_(fields) {}
41 
42   NanopbSerde(const NanopbSerde&) = default;
43   NanopbSerde& operator=(const NanopbSerde&) = default;
44 
45   // Encodes a Nanopb protobuf struct to the serialized wire format.
46   StatusWithSize Encode(const void* proto_struct, ByteSpan buffer) const;
47 
48   // Calculates the encoded size of the provided protobuf struct without
49   // actually encoding it.
50   StatusWithSize EncodedSizeBytes(const void* proto_struct) const;
51 
52   // Decodes a serialized protobuf to a Nanopb struct.
53   template <typename T>
54   Status Decode(ConstByteSpan buffer, T& proto_struct) const {
55     return Decode(buffer, static_cast<void*>(&proto_struct));
56   }
57 
58   Status Decode(ConstByteSpan buffer, void* proto_struct) const;
59 
60  private:
61   NanopbMessageDescriptor fields_;
62 };
63 
64 // Serializer/deserializer for Nanopb message request and response structs in an
65 // RPC method.
66 class NanopbMethodSerde {
67  public:
68   constexpr NanopbMethodSerde(NanopbMessageDescriptor request_fields,
69                               NanopbMessageDescriptor response_fields)
70       : request_fields_(request_fields), response_fields_(response_fields) {}
71 
72   NanopbMethodSerde(const NanopbMethodSerde&) = delete;
73   NanopbMethodSerde& operator=(const NanopbMethodSerde&) = delete;
74 
75   const NanopbSerde& request() const { return request_fields_; }
76   const NanopbSerde& response() const { return response_fields_; }
77 
78  private:
79   NanopbSerde request_fields_;
80   NanopbSerde response_fields_;
81 };
82 
83 template <NanopbMessageDescriptor kRequest, NanopbMessageDescriptor kResponse>
84 inline constexpr NanopbMethodSerde kNanopbMethodSerde(kRequest, kResponse);
85 
86 class Call;
87 class ClientCall;
88 class NanopbServerCall;
89 
90 // [Client] Encodes and sends the initial request message for the call.
91 // active() must be true.
92 void NanopbSendInitialRequest(ClientCall& call,
93                               NanopbSerde serde,
94                               const void* payload)
95     PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());
96 
97 // [Client/Server] Encodes and sends a client or server stream message.
98 // active() must be true.
99 Status NanopbSendStream(Call& call,
100                         const void* payload,
101                         const NanopbMethodSerde* serde)
102     PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());
103 
104 // [Server] Encodes and sends the final response message.
105 // Returns Status::FailedPrecondition if active() is false.
106 Status SendFinalResponse(NanopbServerCall& call,
107                          const void* payload,
108                          Status status) PW_LOCKS_EXCLUDED(rpc_lock());
109 
110 }  // namespace pw::rpc::internal
111