aboutsummaryrefslogtreecommitdiff
path: root/pw_rpc/nanopb/public/pw_rpc/nanopb/internal/common.h
blob: f20550ecad8ea820ba41a5ffec1514da66279944 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once

#include "pb_common.h"
#include "pw_bytes/span.h"
#include "pw_rpc/internal/lock.h"
#include "pw_status/status_with_size.h"

namespace pw::rpc::internal {

// Nanopb 0.3 uses pb_field_t, but Nanopb 4 uses pb_msgdesc_t. Determine which
// type to use by deducing it from the pb_field_iter_begin function.
template <typename PbFieldIterBeginFunction>
struct NanopbDescriptorTraits;

template <typename T>
struct NanopbDescriptorTraits<bool(pb_field_iter_t*, T, void*)> {
  using Type = T;
};

using NanopbMessageDescriptor =
    NanopbDescriptorTraits<decltype(pb_field_iter_begin)>::Type;

// Serializer/deserializer for a Nanopb protobuf message.
class NanopbSerde {
 public:
  explicit constexpr NanopbSerde(NanopbMessageDescriptor fields)
      : fields_(fields) {}

  NanopbSerde(const NanopbSerde&) = default;
  NanopbSerde& operator=(const NanopbSerde&) = default;

  // Encodes a Nanopb protobuf struct to the serialized wire format.
  StatusWithSize Encode(const void* proto_struct, ByteSpan buffer) const;

  // Calculates the encoded size of the provided protobuf struct without
  // actually encoding it.
  StatusWithSize EncodedSizeBytes(const void* proto_struct) const;

  // Decodes a serialized protobuf to a Nanopb struct.
  template <typename T>
  Status Decode(ConstByteSpan buffer, T& proto_struct) const {
    return Decode(buffer, static_cast<void*>(&proto_struct));
  }

  Status Decode(ConstByteSpan buffer, void* proto_struct) const;

 private:
  NanopbMessageDescriptor fields_;
};

// Serializer/deserializer for Nanopb message request and response structs in an
// RPC method.
class NanopbMethodSerde {
 public:
  constexpr NanopbMethodSerde(NanopbMessageDescriptor request_fields,
                              NanopbMessageDescriptor response_fields)
      : request_fields_(request_fields), response_fields_(response_fields) {}

  NanopbMethodSerde(const NanopbMethodSerde&) = delete;
  NanopbMethodSerde& operator=(const NanopbMethodSerde&) = delete;

  const NanopbSerde& request() const { return request_fields_; }
  const NanopbSerde& response() const { return response_fields_; }

 private:
  NanopbSerde request_fields_;
  NanopbSerde response_fields_;
};

template <NanopbMessageDescriptor kRequest, NanopbMessageDescriptor kResponse>
inline constexpr NanopbMethodSerde kNanopbMethodSerde(kRequest, kResponse);

class Call;
class ClientCall;
class NanopbServerCall;

// [Client] Encodes and sends the initial request message for the call.
// active() must be true.
void NanopbSendInitialRequest(ClientCall& call,
                              NanopbSerde serde,
                              const void* payload)
    PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());

// [Client/Server] Encodes and sends a client or server stream message.
// active() must be true.
Status NanopbSendStream(Call& call,
                        const void* payload,
                        const NanopbMethodSerde* serde)
    PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());

// [Server] Encodes and sends the final response message.
// Returns Status::FailedPrecondition if active() is false.
Status SendFinalResponse(NanopbServerCall& call,
                         const void* payload,
                         Status status) PW_LOCKS_EXCLUDED(rpc_lock());

}  // namespace pw::rpc::internal