pw_rpc: Allow using enums for channel IDs
This adds a Channel::Create overload which accepts an enum ID value, to
allow cleaner organization of channel IDs.
Change-Id: Id29fba5c36133c1720a0f74e42e86770e8ad5366
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/40320
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Alexei Frolov <frolv@google.com>
diff --git a/pw_rpc/channel_test.cc b/pw_rpc/channel_test.cc
index 5e16ee6..7687a2d 100644
--- a/pw_rpc/channel_test.cc
+++ b/pw_rpc/channel_test.cc
@@ -42,6 +42,18 @@
5 /* method */ + 2 /* payload key */ +
2 /* status */;
+enum class ChannelId {
+ kOne = 1,
+ kTwo = 2,
+};
+
+TEST(Channel, Create_FromEnum) {
+ constexpr rpc::Channel one = Channel::Create<ChannelId::kOne>(nullptr);
+ constexpr rpc::Channel two = Channel::Create<ChannelId::kTwo>(nullptr);
+ static_assert(one.id() == 1);
+ static_assert(two.id() == 2);
+}
+
TEST(Channel, TestPacket_ReservedSizeMatchesMinEncodedSizeBytes) {
EXPECT_EQ(kReservedSize, kTestPacket.MinEncodedSizeBytes());
}
diff --git a/pw_rpc/docs.rst b/pw_rpc/docs.rst
index eca6870..fc04165 100644
--- a/pw_rpc/docs.rst
+++ b/pw_rpc/docs.rst
@@ -238,6 +238,33 @@
server, hdlc_channel_output, input_buffer);
}
+Channels
+========
+``pw_rpc`` sends all of its packets over channels. These are logical,
+application-layer routes used to tell the RPC system where a packet should go.
+
+Channels over a client-server connection must all have a unique ID, which can be
+assigned statically at compile time or dynamically.
+
+.. code-block:: cpp
+
+ // Creating a channel with the static ID 3.
+ pw::rpc::Channel static_channel = pw::rpc::Channel::Create<3>(&output);
+
+ // Grouping channel IDs within an enum can lead to clearer code.
+ enum ChannelId {
+ kUartChannel = 1,
+ kSpiChannel = 2,
+ };
+
+ // Creating a channel with a static ID defined within an enum.
+ pw::rpc::Channel another_static_channel =
+ pw::rpc::Channel::Create<ChannelId::kUartChannel>(&output);
+
+ // Creating a channel with a dynamic ID (note that no output is provided; it
+ // will be set when the channel is used.
+ pw::rpc::Channel dynamic_channel;
+
Services
========
A service is a logical grouping of RPCs defined within a .proto file. ``pw_rpc``
diff --git a/pw_rpc/public/pw_rpc/channel.h b/pw_rpc/public/pw_rpc/channel.h
index d17cd52..6d87020 100644
--- a/pw_rpc/public/pw_rpc/channel.h
+++ b/pw_rpc/public/pw_rpc/channel.h
@@ -15,6 +15,7 @@
#include <cstdint>
#include <span>
+#include <type_traits>
#include "pw_assert/assert.h"
#include "pw_status/status.h"
@@ -76,6 +77,19 @@
return Channel(kId, output);
}
+ // Creates a channel with a static ID from an enum value.
+ template <auto kId,
+ typename T = decltype(kId),
+ typename = std::enable_if_t<std::is_enum_v<T>>,
+ typename U = std::underlying_type_t<T>>
+ constexpr static Channel Create(ChannelOutput* output) {
+ constexpr U kIntId = static_cast<U>(kId);
+ static_assert(kIntId >= 0, "Channel ID cannot be negative");
+ static_assert(kIntId <= std::numeric_limits<uint32_t>::max(),
+ "Channel ID must fit in a uint32");
+ return Create<static_cast<uint32_t>(kIntId)>(output);
+ }
+
constexpr uint32_t id() const { return id_; }
constexpr bool assigned() const { return id_ != kUnassignedChannelId; }