pw_rpc: Support Nanopb versions 3 or 4
The type of the fields parameter changed between versions. Store the
fields as const void* and deduce the type to cast them to from the
pb_decode function.
Change-Id: I31cf3ee2225b0c21a774031b34aa52bf7d8f3ea7
diff --git a/pw_rpc/nanopb/method.cc b/pw_rpc/nanopb/method.cc
index e17d7ee..366e53a 100644
--- a/pw_rpc/nanopb/method.cc
+++ b/pw_rpc/nanopb/method.cc
@@ -18,6 +18,22 @@
#include "pb_encode.h"
namespace pw::rpc::internal {
+namespace {
+
+// Nanopb 3 uses pb_field_s and Nanopb 4 uses pb_msgdesc_s for fields. The
+// Nanopb version macro is difficult to use, so deduce the correct type from the
+// pb_decode function.
+template <typename DecodeFunction>
+struct NanopbTraits;
+
+template <typename FieldsType>
+struct NanopbTraits<bool(pb_istream_t*, FieldsType, void*)> {
+ using Fields = FieldsType;
+};
+
+using Fields = typename NanopbTraits<decltype(pb_decode)>::Fields;
+
+} // namespace
using std::byte;
@@ -25,15 +41,16 @@
void* proto_struct) const {
auto input = pb_istream_from_buffer(
reinterpret_cast<const pb_byte_t*>(buffer.data()), buffer.size());
- return pb_decode(&input, request_fields_, proto_struct) ? Status::OK
- : Status::INTERNAL;
+ return pb_decode(&input, static_cast<Fields>(request_fields_), proto_struct)
+ ? Status::OK
+ : Status::INTERNAL;
}
StatusWithSize Method::EncodeResponse(const void* proto_struct,
span<byte> buffer) const {
auto output = pb_ostream_from_buffer(
reinterpret_cast<pb_byte_t*>(buffer.data()), buffer.size());
- if (pb_encode(&output, response_fields_, proto_struct)) {
+ if (pb_encode(&output, static_cast<Fields>(response_fields_), proto_struct)) {
return StatusWithSize(output.bytes_written);
}
return StatusWithSize::INTERNAL;
diff --git a/pw_rpc/nanopb/public_overrides/pw_rpc/internal/method.h b/pw_rpc/nanopb/public_overrides/pw_rpc/internal/method.h
index 330d97b..8dd7764 100644
--- a/pw_rpc/nanopb/public_overrides/pw_rpc/internal/method.h
+++ b/pw_rpc/nanopb/public_overrides/pw_rpc/internal/method.h
@@ -24,10 +24,6 @@
#include "pw_status/status.h"
#include "pw_status/status_with_size.h"
-// Forward declare Nanopb types to avoid exposing Nanopb headers.
-extern "C" struct pb_field_s;
-extern "C" struct pb_msgdesc_s;
-
namespace pw::rpc {
// Define the Nanopb version of the the ServerWriter class.
@@ -48,9 +44,8 @@
namespace internal {
-// TODO(hepler): Nanopb 4 uses pb_msgdesc_s instead of pb_field_s.
-// using NanopbMessageDescriptor = const pb_msgdesc_s*;
-using NanopbMessageDescriptor = const pb_field_s*;
+// Use a void* to cover both Nanopb 3's pb_field_s and Nanopb 4's pb_msgdesc_s.
+using NanopbMessageDescriptor = const void*;
// Extracts the request and response proto types from a method.
template <typename Method>