pw_rpc: Reorganize Nanopb implementation
As with raw, replace "nanopb_" file prefixes with a directory path.
Change-Id: Id7e21069850fbfe61bcc3d644881d5f0411830e6
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/52863
Commit-Queue: Wyatt Hepler <hepler@google.com>
Pigweed-Auto-Submit: Wyatt Hepler <hepler@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
diff --git a/pw_metric/metric_service_nanopb_test.cc b/pw_metric/metric_service_nanopb_test.cc
index 5810982..bbb1e2d 100644
--- a/pw_metric/metric_service_nanopb_test.cc
+++ b/pw_metric/metric_service_nanopb_test.cc
@@ -16,7 +16,7 @@
#include "gtest/gtest.h"
#include "pw_log/log.h"
-#include "pw_rpc/nanopb_test_method_context.h"
+#include "pw_rpc/nanopb/test_method_context.h"
namespace pw::metric {
namespace {
diff --git a/pw_rpc/BUILD.bazel b/pw_rpc/BUILD.bazel
index 14677b7..b346123 100644
--- a/pw_rpc/BUILD.bazel
+++ b/pw_rpc/BUILD.bazel
@@ -144,21 +144,22 @@
filegroup(
name = "nanopb",
srcs = [
+ "nanopb/client_call.cc",
+ "nanopb/client_call_test.cc",
"nanopb/codegen_test.cc",
+ "nanopb/common.cc",
"nanopb/echo_service_test.cc",
+ "nanopb/method.cc",
"nanopb/method_lookup_test.cc",
- "nanopb/nanopb_client_call.cc",
- "nanopb/nanopb_client_call_test.cc",
- "nanopb/nanopb_common.cc",
- "nanopb/nanopb_method.cc",
- "nanopb/nanopb_method_test.cc",
- "nanopb/nanopb_method_union_test.cc",
+ "nanopb/method_test.cc",
+ "nanopb/method_union_test.cc",
"nanopb/public/pw_rpc/echo_service_nanopb.h",
- "nanopb/public/pw_rpc/internal/nanopb_common.h",
- "nanopb/public/pw_rpc/internal/nanopb_method.h",
- "nanopb/public/pw_rpc/internal/nanopb_method_union.h",
+ "nanopb/public/pw_rpc/nanopb/client_call.h",
+ "nanopb/public/pw_rpc/nanopb/internal/common.h",
+ "nanopb/public/pw_rpc/nanopb/internal/method.h",
+ "nanopb/public/pw_rpc/nanopb/internal/method_union.h",
"nanopb/public/pw_rpc/nanopb/server_reader_writer.h",
- "nanopb/public/pw_rpc/nanopb_client_call.h",
+ "nanopb/public/pw_rpc/nanopb/test_method_context.h",
"nanopb/public/pw_rpc/nanopb_test_method_context.h",
"nanopb/pw_rpc_nanopb_private/internal_test_utils.h",
"nanopb/server_reader_writer.cc",
diff --git a/pw_rpc/nanopb/BUILD.gn b/pw_rpc/nanopb/BUILD.gn
index 8d4be43..6f72c77 100644
--- a/pw_rpc/nanopb/BUILD.gn
+++ b/pw_rpc/nanopb/BUILD.gn
@@ -27,11 +27,11 @@
pw_source_set("method") {
public_configs = [ ":public" ]
public = [
- "public/pw_rpc/internal/nanopb_method.h",
+ "public/pw_rpc/nanopb/internal/method.h",
"public/pw_rpc/nanopb/server_reader_writer.h",
]
sources = [
- "nanopb_method.cc",
+ "method.cc",
"server_reader_writer.cc",
]
public_deps = [
@@ -45,7 +45,7 @@
pw_source_set("method_union") {
public_configs = [ ":public" ]
- public = [ "public/pw_rpc/internal/nanopb_method_union.h" ]
+ public = [ "public/pw_rpc/nanopb/internal/method_union.h" ]
public_deps = [
":method",
"$dir_pw_rpc/raw:method_union",
@@ -59,15 +59,15 @@
"..:client",
dir_pw_function,
]
- public = [ "public/pw_rpc/nanopb_client_call.h" ]
- sources = [ "nanopb_client_call.cc" ]
+ public = [ "public/pw_rpc/nanopb/client_call.h" ]
+ sources = [ "client_call.cc" ]
}
pw_source_set("common") {
public_deps = [ dir_pw_bytes ]
public_configs = [ ":public" ]
- public = [ "public/pw_rpc/internal/nanopb_common.h" ]
- sources = [ "nanopb_common.cc" ]
+ public = [ "public/pw_rpc/nanopb/internal/common.h" ]
+ sources = [ "common.cc" ]
if (dir_pw_third_party_nanopb != "") {
public_deps += [ "$dir_pw_third_party/nanopb" ]
@@ -76,7 +76,10 @@
pw_source_set("test_method_context") {
public_configs = [ ":public" ]
- public = [ "public/pw_rpc/nanopb_test_method_context.h" ]
+ public = [
+ "public/pw_rpc/nanopb/test_method_context.h",
+ "public/pw_rpc/nanopb_test_method_context.h",
+ ]
public_deps = [
":method",
"..:test_utils",
@@ -109,8 +112,8 @@
":codegen_test",
":echo_service_test",
":method_lookup_test",
- ":nanopb_method_test",
- ":nanopb_method_union_test",
+ ":method_test",
+ ":method_union_test",
":stub_generation_test",
]
}
@@ -122,7 +125,7 @@
"..:test_protos.nanopb",
"..:test_utils",
]
- sources = [ "nanopb_client_call_test.cc" ]
+ sources = [ "client_call_test.cc" ]
enable_if = dir_pw_third_party_nanopb != ""
}
@@ -139,7 +142,7 @@
enable_if = dir_pw_third_party_nanopb != ""
}
-pw_test("nanopb_method_test") {
+pw_test("method_test") {
deps = [
":internal_test_utils",
":method_union",
@@ -147,7 +150,7 @@
"..:test_protos.nanopb",
"..:test_utils",
]
- sources = [ "nanopb_method_test.cc" ]
+ sources = [ "method_test.cc" ]
enable_if = dir_pw_third_party_nanopb != ""
}
@@ -163,14 +166,14 @@
enable_if = dir_pw_third_party_nanopb != ""
}
-pw_test("nanopb_method_union_test") {
+pw_test("method_union_test") {
deps = [
":internal_test_utils",
":method_union",
"..:test_protos.nanopb",
"..:test_utils",
]
- sources = [ "nanopb_method_union_test.cc" ]
+ sources = [ "method_union_test.cc" ]
enable_if = dir_pw_third_party_nanopb != ""
}
diff --git a/pw_rpc/nanopb/CMakeLists.txt b/pw_rpc/nanopb/CMakeLists.txt
index 66547f9..6f879f7 100644
--- a/pw_rpc/nanopb/CMakeLists.txt
+++ b/pw_rpc/nanopb/CMakeLists.txt
@@ -16,7 +16,7 @@
pw_add_module_library(pw_rpc.nanopb.method
SOURCES
- nanopb_method.cc
+ method.cc
PUBLIC_DEPS
pw_rpc.nanopb.common
pw_rpc.server
@@ -35,7 +35,7 @@
pw_add_module_library(pw_rpc.nanopb.client
SOURCES
- nanopb_client_call.cc
+ client_call.cc
PUBLIC_DEPS
pw_function
pw_rpc.nanopb.common
@@ -44,7 +44,7 @@
pw_add_module_library(pw_rpc.nanopb.common
SOURCES
- nanopb_common.cc
+ common.cc
PUBLIC_DEPS
pw_bytes
pw_rpc.common
diff --git a/pw_rpc/nanopb/nanopb_client_call.cc b/pw_rpc/nanopb/client_call.cc
similarity index 96%
rename from pw_rpc/nanopb/nanopb_client_call.cc
rename to pw_rpc/nanopb/client_call.cc
index 89440a6..e7b4939 100644
--- a/pw_rpc/nanopb/nanopb_client_call.cc
+++ b/pw_rpc/nanopb/client_call.cc
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_rpc/nanopb_client_call.h"
+#include "pw_rpc/nanopb/client_call.h"
namespace pw::rpc {
namespace internal {
diff --git a/pw_rpc/nanopb/nanopb_client_call_test.cc b/pw_rpc/nanopb/client_call_test.cc
similarity index 99%
rename from pw_rpc/nanopb/nanopb_client_call_test.cc
rename to pw_rpc/nanopb/client_call_test.cc
index c9d87d2..ae24fd7 100644
--- a/pw_rpc/nanopb/nanopb_client_call_test.cc
+++ b/pw_rpc/nanopb/client_call_test.cc
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_rpc/nanopb_client_call.h"
+#include "pw_rpc/nanopb/client_call.h"
#include "gtest/gtest.h"
#include "pw_rpc_nanopb_private/internal_test_utils.h"
diff --git a/pw_rpc/nanopb/codegen_test.cc b/pw_rpc/nanopb/codegen_test.cc
index cbc2619..5c9fbe8 100644
--- a/pw_rpc/nanopb/codegen_test.cc
+++ b/pw_rpc/nanopb/codegen_test.cc
@@ -14,7 +14,7 @@
#include "gtest/gtest.h"
#include "pw_rpc/internal/hash.h"
-#include "pw_rpc/nanopb_test_method_context.h"
+#include "pw_rpc/nanopb/test_method_context.h"
#include "pw_rpc_nanopb_private/internal_test_utils.h"
#include "pw_rpc_private/internal_test_utils.h"
#include "pw_rpc_test_protos/test.rpc.pb.h"
diff --git a/pw_rpc/nanopb/nanopb_common.cc b/pw_rpc/nanopb/common.cc
similarity index 97%
rename from pw_rpc/nanopb/nanopb_common.cc
rename to pw_rpc/nanopb/common.cc
index 6e6e611..9f959e5 100644
--- a/pw_rpc/nanopb/nanopb_common.cc
+++ b/pw_rpc/nanopb/common.cc
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_rpc/internal/nanopb_common.h"
+#include "pw_rpc/nanopb/internal/common.h"
#include "pb_decode.h"
#include "pb_encode.h"
diff --git a/pw_rpc/nanopb/echo_service_test.cc b/pw_rpc/nanopb/echo_service_test.cc
index 11a0608..4d134c2 100644
--- a/pw_rpc/nanopb/echo_service_test.cc
+++ b/pw_rpc/nanopb/echo_service_test.cc
@@ -14,7 +14,7 @@
#include "gtest/gtest.h"
#include "pw_rpc/echo_service_nanopb.h"
-#include "pw_rpc/nanopb_test_method_context.h"
+#include "pw_rpc/nanopb/test_method_context.h"
namespace pw::rpc {
namespace {
diff --git a/pw_rpc/nanopb/nanopb_method.cc b/pw_rpc/nanopb/method.cc
similarity index 98%
rename from pw_rpc/nanopb/nanopb_method.cc
rename to pw_rpc/nanopb/method.cc
index 6ae45be..03ec30e 100644
--- a/pw_rpc/nanopb/nanopb_method.cc
+++ b/pw_rpc/nanopb/method.cc
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_rpc/internal/nanopb_method.h"
+#include "pw_rpc/nanopb/internal/method.h"
#include "pb_decode.h"
#include "pb_encode.h"
diff --git a/pw_rpc/nanopb/method_lookup_test.cc b/pw_rpc/nanopb/method_lookup_test.cc
index bfb0da8..cc28a35 100644
--- a/pw_rpc/nanopb/method_lookup_test.cc
+++ b/pw_rpc/nanopb/method_lookup_test.cc
@@ -13,7 +13,7 @@
// the License.
#include "gtest/gtest.h"
-#include "pw_rpc/nanopb_test_method_context.h"
+#include "pw_rpc/nanopb/test_method_context.h"
#include "pw_rpc/raw/test_method_context.h"
#include "pw_rpc_test_protos/test.rpc.pb.h"
diff --git a/pw_rpc/nanopb/nanopb_method_test.cc b/pw_rpc/nanopb/method_test.cc
similarity index 99%
rename from pw_rpc/nanopb/nanopb_method_test.cc
rename to pw_rpc/nanopb/method_test.cc
index 8964ac4..5eb2e78 100644
--- a/pw_rpc/nanopb/nanopb_method_test.cc
+++ b/pw_rpc/nanopb/method_test.cc
@@ -12,12 +12,12 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_rpc/internal/nanopb_method.h"
+#include "pw_rpc/nanopb/internal/method.h"
#include <array>
#include "gtest/gtest.h"
-#include "pw_rpc/internal/nanopb_method_union.h"
+#include "pw_rpc/nanopb/internal/method_union.h"
#include "pw_rpc/server_context.h"
#include "pw_rpc/service.h"
#include "pw_rpc_nanopb_private/internal_test_utils.h"
diff --git a/pw_rpc/nanopb/nanopb_method_union_test.cc b/pw_rpc/nanopb/method_union_test.cc
similarity index 99%
rename from pw_rpc/nanopb/nanopb_method_union_test.cc
rename to pw_rpc/nanopb/method_union_test.cc
index cb3ef71..5710087 100644
--- a/pw_rpc/nanopb/nanopb_method_union_test.cc
+++ b/pw_rpc/nanopb/method_union_test.cc
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_rpc/internal/nanopb_method_union.h"
+#include "pw_rpc/nanopb/internal/method_union.h"
#include <array>
diff --git a/pw_rpc/nanopb/public/pw_rpc/nanopb_client_call.h b/pw_rpc/nanopb/public/pw_rpc/nanopb/client_call.h
similarity index 98%
rename from pw_rpc/nanopb/public/pw_rpc/nanopb_client_call.h
rename to pw_rpc/nanopb/public/pw_rpc/nanopb/client_call.h
index 1f4d285..c1e6c95 100644
--- a/pw_rpc/nanopb/public/pw_rpc/nanopb_client_call.h
+++ b/pw_rpc/nanopb/public/pw_rpc/nanopb/client_call.h
@@ -19,7 +19,7 @@
#include "pw_function/function.h"
#include "pw_rpc/internal/base_client_call.h"
#include "pw_rpc/internal/method_type.h"
-#include "pw_rpc/internal/nanopb_common.h"
+#include "pw_rpc/nanopb/internal/common.h"
#include "pw_status/status.h"
namespace pw::rpc {
diff --git a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_common.h b/pw_rpc/nanopb/public/pw_rpc/nanopb/internal/common.h
similarity index 100%
rename from pw_rpc/nanopb/public/pw_rpc/internal/nanopb_common.h
rename to pw_rpc/nanopb/public/pw_rpc/nanopb/internal/common.h
diff --git a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h b/pw_rpc/nanopb/public/pw_rpc/nanopb/internal/method.h
similarity index 99%
rename from pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h
rename to pw_rpc/nanopb/public/pw_rpc/nanopb/internal/method.h
index e7cedb5..415ba75 100644
--- a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method.h
+++ b/pw_rpc/nanopb/public/pw_rpc/nanopb/internal/method.h
@@ -23,8 +23,8 @@
#include "pw_rpc/internal/config.h"
#include "pw_rpc/internal/method.h"
#include "pw_rpc/internal/method_type.h"
-#include "pw_rpc/internal/nanopb_common.h"
#include "pw_rpc/internal/responder.h"
+#include "pw_rpc/nanopb/internal/common.h"
#include "pw_rpc/nanopb/server_reader_writer.h"
#include "pw_rpc/server_context.h"
#include "pw_status/status.h"
diff --git a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method_union.h b/pw_rpc/nanopb/public/pw_rpc/nanopb/internal/method_union.h
similarity index 97%
rename from pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method_union.h
rename to pw_rpc/nanopb/public/pw_rpc/nanopb/internal/method_union.h
index 3914397..12bfe1d 100644
--- a/pw_rpc/nanopb/public/pw_rpc/internal/nanopb_method_union.h
+++ b/pw_rpc/nanopb/public/pw_rpc/nanopb/internal/method_union.h
@@ -15,7 +15,7 @@
#include "pw_bytes/span.h"
#include "pw_rpc/internal/method_union.h"
-#include "pw_rpc/internal/nanopb_method.h"
+#include "pw_rpc/nanopb/internal/method.h"
#include "pw_rpc/raw/internal/method_union.h"
namespace pw::rpc::internal {
diff --git a/pw_rpc/nanopb/public/pw_rpc/nanopb/test_method_context.h b/pw_rpc/nanopb/public/pw_rpc/nanopb/test_method_context.h
new file mode 100644
index 0000000..cc36b3d
--- /dev/null
+++ b/pw_rpc/nanopb/public/pw_rpc/nanopb/test_method_context.h
@@ -0,0 +1,272 @@
+// 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 <tuple>
+#include <utility>
+
+#include "pw_assert/assert.h"
+#include "pw_bytes/span.h"
+#include "pw_containers/vector.h"
+#include "pw_preprocessor/arguments.h"
+#include "pw_rpc/internal/hash.h"
+#include "pw_rpc/internal/method_lookup.h"
+#include "pw_rpc/internal/test_method_context.h"
+#include "pw_rpc/nanopb/internal/method.h"
+#include "pw_rpc_private/fake_channel_output.h"
+
+namespace pw::rpc {
+
+// Declares a context object that may be used to invoke an RPC. The context is
+// declared with the name of the implemented service and the method to invoke.
+// The RPC can then be invoked with the call method.
+//
+// For a unary RPC, context.call(request) returns the status, and the response
+// struct can be accessed via context.response().
+//
+// PW_NANOPB_TEST_METHOD_CONTEXT(my::CoolService, TheMethod) context;
+// EXPECT_EQ(OkStatus(), context.call({.some_arg = 123}));
+// EXPECT_EQ(500, context.response().some_response_value);
+//
+// For a server streaming RPC, context.call(request) invokes the method. As in a
+// normal RPC, the method completes when the ServerWriter's Finish method is
+// called (or it goes out of scope).
+//
+// PW_NANOPB_TEST_METHOD_CONTEXT(my::CoolService, TheStreamingMethod) context;
+// context.call({.some_arg = 123});
+//
+// EXPECT_TRUE(context.done()); // Check that the RPC completed
+// EXPECT_EQ(OkStatus(), context.status()); // Check the status
+//
+// EXPECT_EQ(3u, context.responses().size());
+// EXPECT_EQ(123, context.responses()[0].value); // check individual responses
+//
+// for (const MyResponse& response : context.responses()) {
+// // iterate over the responses
+// }
+//
+// PW_NANOPB_TEST_METHOD_CONTEXT forwards its constructor arguments to the
+// underlying serivce. For example:
+//
+// PW_NANOPB_TEST_METHOD_CONTEXT(MyService, Go) context(service, args);
+//
+// PW_NANOPB_TEST_METHOD_CONTEXT takes two optional arguments:
+//
+// size_t kMaxResponses: maximum responses to store; ignored unless streaming
+// size_t kOutputSizeBytes: buffer size; must be large enough for a packet
+//
+// Example:
+//
+// PW_NANOPB_TEST_METHOD_CONTEXT(MyService, BestMethod, 3, 256) context;
+// ASSERT_EQ(3u, context.responses().max_size());
+//
+#define PW_NANOPB_TEST_METHOD_CONTEXT(service, method, ...) \
+ ::pw::rpc::NanopbTestMethodContext<service, \
+ &service::method, \
+ ::pw::rpc::internal::Hash(#method), \
+ ##__VA_ARGS__>
+template <typename Service,
+ auto kMethod,
+ uint32_t kMethodId,
+ size_t kMaxResponses = 4,
+ size_t kOutputSizeBytes = 128>
+class NanopbTestMethodContext;
+
+// Internal classes that implement NanopbTestMethodContext.
+namespace internal::test::nanopb {
+
+// A ChannelOutput implementation that stores the outgoing payloads and status.
+template <typename Response, size_t kMaxResponses, size_t kOutputSize>
+class MessageOutput final : public FakeChannelOutput {
+ public:
+ MessageOutput(const internal::NanopbMethod& kMethod, bool server_streaming)
+ : FakeChannelOutput(packet_buffer_, server_streaming), method_(kMethod) {}
+
+ const Vector<Response>& responses() const { return responses_; }
+
+ Response& AllocateResponse() {
+ // If we run out of space, the back message is always the most recent.
+ responses_.emplace_back();
+ responses_.back() = {};
+ return responses_.back();
+ }
+
+ private:
+ void AppendResponse(ConstByteSpan response) override {
+ Response& response_struct = AllocateResponse();
+ PW_ASSERT(method_.serde().DecodeResponse(response, &response_struct));
+ }
+
+ void ClearResponses() override { responses_.clear(); }
+
+ const internal::NanopbMethod& method_;
+ Vector<Response, kMaxResponses> responses_;
+ std::array<std::byte, kOutputSize> packet_buffer_;
+};
+
+// Collects everything needed to invoke a particular RPC.
+template <typename Service,
+ auto kMethod,
+ uint32_t kMethodId,
+ size_t kMaxResponses,
+ size_t kOutputSize>
+struct NanopbInvocationContext : public InvocationContext<Service, kMethodId> {
+ public:
+ using Request = internal::Request<kMethod>;
+ using Response = internal::Response<kMethod>;
+
+ // Returns the responses that have been recorded. The maximum number of
+ // responses is responses().max_size(). responses().back() is always the most
+ // recent response, even if total_responses() > responses().max_size().
+ const Vector<Response>& responses() const { return output_.responses(); }
+
+ // Gives access to the RPC's response.
+ const Response& response() const {
+ PW_ASSERT(!responses().empty());
+ return responses().back();
+ }
+
+ protected:
+ template <typename... Args>
+ NanopbInvocationContext(Args&&... args)
+ : InvocationContext<Service, kMethodId>(
+ MethodLookup::GetNanopbMethod<Service, kMethodId>(),
+ output_,
+ std::forward<Args>(args)...),
+ output_(MethodLookup::GetNanopbMethod<Service, kMethodId>(),
+ MethodTraits<decltype(kMethod)>::kServerStreaming) {}
+
+ MessageOutput<Response, kMaxResponses, kOutputSize>& output() {
+ return output_;
+ }
+
+ private:
+ MessageOutput<Response, kMaxResponses, kOutputSize> output_;
+};
+
+// Method invocation context for a unary RPC. Returns the status in
+// server_call() and provides the response through the response() method.
+template <typename Service,
+ auto kMethod,
+ uint32_t kMethodId,
+ size_t kOutputSize>
+class UnaryContext : public NanopbInvocationContext<Service,
+ kMethod,
+ kMethodId,
+ 1,
+ kOutputSize> {
+ using Base =
+ NanopbInvocationContext<Service, kMethod, kMethodId, 1, kOutputSize>;
+
+ public:
+ using Request = typename Base::Request;
+ using Response = typename Base::Response;
+
+ template <typename... Args>
+ UnaryContext(Args&&... args) : Base(std::forward<Args>(args)...) {}
+
+ // Invokes the RPC with the provided request. Returns the status.
+ Status call(const Request& request) {
+ Base::output().clear();
+ Response& response = Base::output().AllocateResponse();
+ return CallMethodImplFunction<kMethod>(
+ Base::server_call(), request, response);
+ }
+};
+
+// Method invocation context for a server streaming RPC.
+template <typename Service,
+ auto kMethod,
+ uint32_t kMethodId,
+ size_t kMaxResponses,
+ size_t kOutputSize>
+class ServerStreamingContext : public NanopbInvocationContext<Service,
+ kMethod,
+ kMethodId,
+ kMaxResponses,
+ kOutputSize> {
+ private:
+ using Base = NanopbInvocationContext<Service,
+ kMethod,
+ kMethodId,
+ kMaxResponses,
+ kOutputSize>;
+
+ public:
+ using Request = typename Base::Request;
+ using Response = typename Base::Response;
+
+ template <typename... Args>
+ ServerStreamingContext(Args&&... args) : Base(std::forward<Args>(args)...) {}
+
+ // Invokes the RPC with the provided request.
+ void call(const Request& request) {
+ Base::output().clear();
+ NanopbServerWriter<Response> writer(Base::server_call());
+ return CallMethodImplFunction<kMethod>(
+ Base::server_call(), request, writer);
+ }
+
+ // Returns a server writer which writes responses into the context's buffer.
+ // This should not be called alongside call(); use one or the other.
+ NanopbServerWriter<Response> writer() {
+ Base::output().clear();
+ return NanopbServerWriter<Response>(Base::server_call());
+ }
+};
+
+// Alias to select the type of the context object to use based on which type of
+// RPC it is for.
+template <typename Service,
+ auto kMethod,
+ uint32_t kMethodId,
+ size_t kMaxResponses,
+ size_t kOutputSize>
+using Context = std::tuple_element_t<
+ static_cast<size_t>(internal::MethodTraits<decltype(kMethod)>::kType),
+ std::tuple<UnaryContext<Service, kMethod, kMethodId, kOutputSize>,
+ ServerStreamingContext<Service,
+ kMethod,
+ kMethodId,
+ kMaxResponses,
+ kOutputSize>
+ // TODO(hepler): Support client and bidi streaming
+ >>;
+
+} // namespace internal::test::nanopb
+
+template <typename Service,
+ auto kMethod,
+ uint32_t kMethodId,
+ size_t kMaxResponses,
+ size_t kOutputSizeBytes>
+class NanopbTestMethodContext
+ : public internal::test::nanopb::Context<Service,
+ kMethod,
+ kMethodId,
+ kMaxResponses,
+ kOutputSizeBytes> {
+ public:
+ // Forwards constructor arguments to the service class.
+ template <typename... ServiceArgs>
+ NanopbTestMethodContext(ServiceArgs&&... service_args)
+ : internal::test::nanopb::Context<Service,
+ kMethod,
+ kMethodId,
+ kMaxResponses,
+ kOutputSizeBytes>(
+ std::forward<ServiceArgs>(service_args)...) {}
+};
+
+} // namespace pw::rpc
diff --git a/pw_rpc/nanopb/public/pw_rpc/nanopb_test_method_context.h b/pw_rpc/nanopb/public/pw_rpc/nanopb_test_method_context.h
index 0214b6a..0502c1f 100644
--- a/pw_rpc/nanopb/public/pw_rpc/nanopb_test_method_context.h
+++ b/pw_rpc/nanopb/public/pw_rpc/nanopb_test_method_context.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Pigweed Authors
+// Copyright 2021 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
@@ -13,260 +13,7 @@
// the License.
#pragma once
-#include <tuple>
-#include <utility>
-
-#include "pw_assert/assert.h"
-#include "pw_bytes/span.h"
-#include "pw_containers/vector.h"
-#include "pw_preprocessor/arguments.h"
-#include "pw_rpc/internal/hash.h"
-#include "pw_rpc/internal/method_lookup.h"
-#include "pw_rpc/internal/nanopb_method.h"
-#include "pw_rpc/internal/test_method_context.h"
-#include "pw_rpc_private/fake_channel_output.h"
-
-namespace pw::rpc {
-
-// Declares a context object that may be used to invoke an RPC. The context is
-// declared with the name of the implemented service and the method to invoke.
-// The RPC can then be invoked with the call method.
-//
-// For a unary RPC, context.call(request) returns the status, and the response
-// struct can be accessed via context.response().
-//
-// PW_NANOPB_TEST_METHOD_CONTEXT(my::CoolService, TheMethod) context;
-// EXPECT_EQ(OkStatus(), context.call({.some_arg = 123}));
-// EXPECT_EQ(500, context.response().some_response_value);
-//
-// For a server streaming RPC, context.call(request) invokes the method. As in a
-// normal RPC, the method completes when the ServerWriter's Finish method is
-// called (or it goes out of scope).
-//
-// PW_NANOPB_TEST_METHOD_CONTEXT(my::CoolService, TheStreamingMethod) context;
-// context.call({.some_arg = 123});
-//
-// EXPECT_TRUE(context.done()); // Check that the RPC completed
-// EXPECT_EQ(OkStatus(), context.status()); // Check the status
-//
-// EXPECT_EQ(3u, context.responses().size());
-// EXPECT_EQ(123, context.responses()[0].value); // check individual responses
-//
-// for (const MyResponse& response : context.responses()) {
-// // iterate over the responses
-// }
-//
-// PW_NANOPB_TEST_METHOD_CONTEXT forwards its constructor arguments to the
-// underlying serivce. For example:
-//
-// PW_NANOPB_TEST_METHOD_CONTEXT(MyService, Go) context(service, args);
-//
-// PW_NANOPB_TEST_METHOD_CONTEXT takes two optional arguments:
-//
-// size_t kMaxResponses: maximum responses to store; ignored unless streaming
-// size_t kOutputSizeBytes: buffer size; must be large enough for a packet
-//
-// Example:
-//
-// PW_NANOPB_TEST_METHOD_CONTEXT(MyService, BestMethod, 3, 256) context;
-// ASSERT_EQ(3u, context.responses().max_size());
-//
-#define PW_NANOPB_TEST_METHOD_CONTEXT(service, method, ...) \
- ::pw::rpc::NanopbTestMethodContext<service, \
- &service::method, \
- ::pw::rpc::internal::Hash(#method), \
- ##__VA_ARGS__>
-template <typename Service,
- auto kMethod,
- uint32_t kMethodId,
- size_t kMaxResponses = 4,
- size_t kOutputSizeBytes = 128>
-class NanopbTestMethodContext;
-
-// Internal classes that implement NanopbTestMethodContext.
-namespace internal::test::nanopb {
-
-// A ChannelOutput implementation that stores the outgoing payloads and status.
-template <typename Response, size_t kMaxResponses, size_t kOutputSize>
-class MessageOutput final : public FakeChannelOutput {
- public:
- MessageOutput(const internal::NanopbMethod& kMethod, bool server_streaming)
- : FakeChannelOutput(packet_buffer_, server_streaming), method_(kMethod) {}
-
- const Vector<Response>& responses() const { return responses_; }
-
- Response& AllocateResponse() {
- // If we run out of space, the back message is always the most recent.
- responses_.emplace_back();
- responses_.back() = {};
- return responses_.back();
- }
-
- private:
- void AppendResponse(ConstByteSpan response) override {
- Response& response_struct = AllocateResponse();
- PW_ASSERT(method_.serde().DecodeResponse(response, &response_struct));
- }
-
- void ClearResponses() override { responses_.clear(); }
-
- const internal::NanopbMethod& method_;
- Vector<Response, kMaxResponses> responses_;
- std::array<std::byte, kOutputSize> packet_buffer_;
-};
-
-// Collects everything needed to invoke a particular RPC.
-template <typename Service,
- auto kMethod,
- uint32_t kMethodId,
- size_t kMaxResponses,
- size_t kOutputSize>
-struct NanopbInvocationContext : public InvocationContext<Service, kMethodId> {
- public:
- using Request = internal::Request<kMethod>;
- using Response = internal::Response<kMethod>;
-
- // Returns the responses that have been recorded. The maximum number of
- // responses is responses().max_size(). responses().back() is always the most
- // recent response, even if total_responses() > responses().max_size().
- const Vector<Response>& responses() const { return output_.responses(); }
-
- // Gives access to the RPC's response.
- const Response& response() const {
- PW_ASSERT(!responses().empty());
- return responses().back();
- }
-
- protected:
- template <typename... Args>
- NanopbInvocationContext(Args&&... args)
- : InvocationContext<Service, kMethodId>(
- MethodLookup::GetNanopbMethod<Service, kMethodId>(),
- output_,
- std::forward<Args>(args)...),
- output_(MethodLookup::GetNanopbMethod<Service, kMethodId>(),
- MethodTraits<decltype(kMethod)>::kServerStreaming) {}
-
- MessageOutput<Response, kMaxResponses, kOutputSize>& output() {
- return output_;
- }
-
- private:
- MessageOutput<Response, kMaxResponses, kOutputSize> output_;
-};
-
-// Method invocation context for a unary RPC. Returns the status in
-// server_call() and provides the response through the response() method.
-template <typename Service,
- auto kMethod,
- uint32_t kMethodId,
- size_t kOutputSize>
-class UnaryContext : public NanopbInvocationContext<Service,
- kMethod,
- kMethodId,
- 1,
- kOutputSize> {
- using Base =
- NanopbInvocationContext<Service, kMethod, kMethodId, 1, kOutputSize>;
-
- public:
- using Request = typename Base::Request;
- using Response = typename Base::Response;
-
- template <typename... Args>
- UnaryContext(Args&&... args) : Base(std::forward<Args>(args)...) {}
-
- // Invokes the RPC with the provided request. Returns the status.
- Status call(const Request& request) {
- Base::output().clear();
- Response& response = Base::output().AllocateResponse();
- return CallMethodImplFunction<kMethod>(
- Base::server_call(), request, response);
- }
-};
-
-// Method invocation context for a server streaming RPC.
-template <typename Service,
- auto kMethod,
- uint32_t kMethodId,
- size_t kMaxResponses,
- size_t kOutputSize>
-class ServerStreamingContext : public NanopbInvocationContext<Service,
- kMethod,
- kMethodId,
- kMaxResponses,
- kOutputSize> {
- private:
- using Base = NanopbInvocationContext<Service,
- kMethod,
- kMethodId,
- kMaxResponses,
- kOutputSize>;
-
- public:
- using Request = typename Base::Request;
- using Response = typename Base::Response;
-
- template <typename... Args>
- ServerStreamingContext(Args&&... args) : Base(std::forward<Args>(args)...) {}
-
- // Invokes the RPC with the provided request.
- void call(const Request& request) {
- Base::output().clear();
- NanopbServerWriter<Response> writer(Base::server_call());
- return CallMethodImplFunction<kMethod>(
- Base::server_call(), request, writer);
- }
-
- // Returns a server writer which writes responses into the context's buffer.
- // This should not be called alongside call(); use one or the other.
- NanopbServerWriter<Response> writer() {
- Base::output().clear();
- return NanopbServerWriter<Response>(Base::server_call());
- }
-};
-
-// Alias to select the type of the context object to use based on which type of
-// RPC it is for.
-template <typename Service,
- auto kMethod,
- uint32_t kMethodId,
- size_t kMaxResponses,
- size_t kOutputSize>
-using Context = std::tuple_element_t<
- static_cast<size_t>(internal::MethodTraits<decltype(kMethod)>::kType),
- std::tuple<UnaryContext<Service, kMethod, kMethodId, kOutputSize>,
- ServerStreamingContext<Service,
- kMethod,
- kMethodId,
- kMaxResponses,
- kOutputSize>
- // TODO(hepler): Support client and bidi streaming
- >>;
-
-} // namespace internal::test::nanopb
-
-template <typename Service,
- auto kMethod,
- uint32_t kMethodId,
- size_t kMaxResponses,
- size_t kOutputSizeBytes>
-class NanopbTestMethodContext
- : public internal::test::nanopb::Context<Service,
- kMethod,
- kMethodId,
- kMaxResponses,
- kOutputSizeBytes> {
- public:
- // Forwards constructor arguments to the service class.
- template <typename... ServiceArgs>
- NanopbTestMethodContext(ServiceArgs&&... service_args)
- : internal::test::nanopb::Context<Service,
- kMethod,
- kMethodId,
- kMaxResponses,
- kOutputSizeBytes>(
- std::forward<ServiceArgs>(service_args)...) {}
-};
-
-} // namespace pw::rpc
+// pw_rpc/nanopb/test_method_context.h is now
+// pw_rpc/nanopb/test_method_context.h.
+// TODO(hepler): Remove this wrapper when users have migrated.
+#include "pw_rpc/nanopb/test_method_context.h"
diff --git a/pw_rpc/nanopb/server_reader_writer.cc b/pw_rpc/nanopb/server_reader_writer.cc
index f43063d..58efbc8 100644
--- a/pw_rpc/nanopb/server_reader_writer.cc
+++ b/pw_rpc/nanopb/server_reader_writer.cc
@@ -14,7 +14,7 @@
#include "pw_rpc/nanopb/server_reader_writer.h"
-#include "pw_rpc/internal/nanopb_method.h"
+#include "pw_rpc/nanopb/internal/method.h"
namespace pw::rpc::internal {
diff --git a/pw_rpc/py/pw_rpc/codegen_nanopb.py b/pw_rpc/py/pw_rpc/codegen_nanopb.py
index cf7dc73..7630293 100644
--- a/pw_rpc/py/pw_rpc/codegen_nanopb.py
+++ b/pw_rpc/py/pw_rpc/codegen_nanopb.py
@@ -200,8 +200,8 @@
def includes(proto_file, unused_package: ProtoNode) -> Iterator[str]:
- yield '#include "pw_rpc/internal/nanopb_method_union.h"'
- yield '#include "pw_rpc/nanopb_client_call.h"'
+ yield '#include "pw_rpc/nanopb/internal/method_union.h"'
+ yield '#include "pw_rpc/nanopb/client_call.h"'
# Include the corresponding nanopb header file for this proto file, in which
# the file's messages and enums are generated. All other files imported from