diff options
author | Alexei Frolov <frolv@google.com> | 2020-08-04 10:33:26 -0700 |
---|---|---|
committer | CQ Bot Account <commit-bot@chromium.org> | 2020-08-04 21:50:45 +0000 |
commit | 9a4d6bf6d93f4fdc5690546948a229de4c8d51b6 (patch) | |
tree | 87e9b22fa297fbf6de00a1f66dedf94d2c2a1593 /pw_rpc | |
parent | 67368878c411332b9a5b3c77982a11d9be1f156a (diff) | |
download | pigweed-9a4d6bf6d93f4fdc5690546948a229de4c8d51b6.tar.gz |
pw_rpc: Expose Service class
This change moves the base Service class to pw_rpc's public API and adds
a source_set that provides service.h separately to the rest of RPC. This
is done to allow creating APIs to globally register services without
having to pull in the entirety of pw_rpc (and potentially creating
dependency cycles).
Change-Id: I80eb34ed35b74caffb71444a59ee05eff5bc8fba
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/15360
Commit-Queue: Alexei Frolov <frolv@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
Diffstat (limited to 'pw_rpc')
-rw-r--r-- | pw_rpc/BUILD | 2 | ||||
-rw-r--r-- | pw_rpc/BUILD.gn | 12 | ||||
-rw-r--r-- | pw_rpc/base_server_writer_test.cc | 4 | ||||
-rw-r--r-- | pw_rpc/docs.rst | 2 | ||||
-rw-r--r-- | pw_rpc/nanopb/method_test.cc | 2 | ||||
-rw-r--r-- | pw_rpc/public/pw_rpc/internal/base_server_writer.h | 2 | ||||
-rw-r--r-- | pw_rpc/public/pw_rpc/internal/call.h | 2 | ||||
-rw-r--r-- | pw_rpc/public/pw_rpc/server.h | 11 | ||||
-rw-r--r-- | pw_rpc/public/pw_rpc/service.h (renamed from pw_rpc/public/pw_rpc/internal/service.h) | 17 | ||||
-rw-r--r-- | pw_rpc/py/codegen_test.py | 85 | ||||
-rw-r--r-- | pw_rpc/py/pw_rpc/codegen_nanopb.py | 4 | ||||
-rw-r--r-- | pw_rpc/server_test.cc | 6 | ||||
-rw-r--r-- | pw_rpc/service.cc | 10 |
13 files changed, 105 insertions, 54 deletions
diff --git a/pw_rpc/BUILD b/pw_rpc/BUILD index b3670665f..1d5a7dbc1 100644 --- a/pw_rpc/BUILD +++ b/pw_rpc/BUILD @@ -27,13 +27,13 @@ pw_cc_library( srcs = [ "base_server_writer.cc", "public/pw_rpc/internal/base_server_writer.h", - "public/pw_rpc/internal/service.h", "server.cc", "service.cc", ], hdrs = [ "public/pw_rpc/server.h", "public/pw_rpc/server_context.h", + "public/pw_rpc/service.h", "public/pw_rpc/internal/channel.h", "public/pw_rpc/internal/server.h", "public/pw_rpc/internal/hash.h", diff --git a/pw_rpc/BUILD.gn b/pw_rpc/BUILD.gn index 0067ecc0e..233464297 100644 --- a/pw_rpc/BUILD.gn +++ b/pw_rpc/BUILD.gn @@ -56,7 +56,6 @@ template("_pw_rpc_server_library") { "base_server_writer.cc", "public/pw_rpc/internal/base_server_writer.h", "public/pw_rpc/internal/server.h", - "public/pw_rpc/internal/service.h", "server.cc", "service.cc", ] @@ -77,13 +76,22 @@ template("_pw_rpc_server_library") { } } +# Provides the public RPC service definition (but not implementation). Can be +# used to expose global service registration without depending on the complete +# RPC library. +pw_source_set("service") { + public_configs = [ ":default_config" ] + public_deps = [ "$dir_pw_containers:intrusive_list" ] + public = [ "public/pw_rpc/service.h" ] +} + # Put these dependencies into a group since they need to be shared by the server # library and its implementation library. group("server_library_deps") { public_configs = [ ":default_config" ] public_deps = [ ":common", - "$dir_pw_containers:intrusive_list", + ":service", dir_pw_span, dir_pw_status, ] diff --git a/pw_rpc/base_server_writer_test.cc b/pw_rpc/base_server_writer_test.cc index 2100d5a90..e8999dc52 100644 --- a/pw_rpc/base_server_writer_test.cc +++ b/pw_rpc/base_server_writer_test.cc @@ -19,13 +19,13 @@ #include <cstring> #include "gtest/gtest.h" -#include "pw_rpc/internal/service.h" #include "pw_rpc/server_context.h" +#include "pw_rpc/service.h" #include "pw_rpc_private/internal_test_utils.h" namespace pw::rpc { -class TestService : public internal::Service { +class TestService : public Service { public: constexpr TestService(uint32_t id) : Service(id, std::span(&method, 1)), method(8) {} diff --git a/pw_rpc/docs.rst b/pw_rpc/docs.rst index 62835ba1a..09351b70e 100644 --- a/pw_rpc/docs.rst +++ b/pw_rpc/docs.rst @@ -437,7 +437,7 @@ Requests label = "pw_rpc library"; server [label = "Server"]; - service [label = "internal::Service"]; + service [label = "Service"]; method [label = "internal::Method"]; } diff --git a/pw_rpc/nanopb/method_test.cc b/pw_rpc/nanopb/method_test.cc index bbdf7538a..a408b673e 100644 --- a/pw_rpc/nanopb/method_test.cc +++ b/pw_rpc/nanopb/method_test.cc @@ -18,8 +18,8 @@ #include "gtest/gtest.h" #include "pb_encode.h" -#include "pw_rpc/internal/service.h" #include "pw_rpc/server_context.h" +#include "pw_rpc/service.h" #include "pw_rpc_private/internal_test_utils.h" #include "pw_rpc_test_protos/test.pb.h" diff --git a/pw_rpc/public/pw_rpc/internal/base_server_writer.h b/pw_rpc/public/pw_rpc/internal/base_server_writer.h index 2b4b0faa2..9d2254baa 100644 --- a/pw_rpc/public/pw_rpc/internal/base_server_writer.h +++ b/pw_rpc/public/pw_rpc/internal/base_server_writer.h @@ -20,7 +20,7 @@ #include "pw_containers/intrusive_list.h" #include "pw_rpc/internal/call.h" #include "pw_rpc/internal/channel.h" -#include "pw_rpc/internal/service.h" +#include "pw_rpc/service.h" #include "pw_status/status.h" namespace pw::rpc::internal { diff --git a/pw_rpc/public/pw_rpc/internal/call.h b/pw_rpc/public/pw_rpc/internal/call.h index d8813aed2..bdfa56ca1 100644 --- a/pw_rpc/public/pw_rpc/internal/call.h +++ b/pw_rpc/public/pw_rpc/internal/call.h @@ -22,12 +22,12 @@ namespace pw::rpc { class ServerContext; +class Service; namespace internal { class Method; class Server; -class Service; // Collects information for an ongoing RPC being processed by the server. // The Server creates a ServerCall object to represent a method invocation. The diff --git a/pw_rpc/public/pw_rpc/server.h b/pw_rpc/public/pw_rpc/server.h index 5fa5f6a3d..c0ca50048 100644 --- a/pw_rpc/public/pw_rpc/server.h +++ b/pw_rpc/public/pw_rpc/server.h @@ -20,7 +20,7 @@ #include "pw_rpc/channel.h" #include "pw_rpc/internal/base_server_writer.h" #include "pw_rpc/internal/channel.h" -#include "pw_rpc/internal/service.h" +#include "pw_rpc/service.h" namespace pw::rpc { @@ -33,11 +33,8 @@ class Server { ~Server(); // Registers a service with the server. This should not be called directly - // with an internal::Service; instead, use a generated class which inherits - // from it. - void RegisterService(internal::Service& service) { - services_.push_front(service); - } + // with a Service; instead, use a generated class which inherits from it. + void RegisterService(Service& service) { services_.push_front(service); } void ProcessPacket(std::span<const std::byte> packet, ChannelOutput& interface); @@ -55,7 +52,7 @@ class Server { internal::Channel* AssignChannel(uint32_t id, ChannelOutput& interface); std::span<internal::Channel> channels_; - IntrusiveList<internal::Service> services_; + IntrusiveList<Service> services_; IntrusiveList<internal::BaseServerWriter> writers_; }; diff --git a/pw_rpc/public/pw_rpc/internal/service.h b/pw_rpc/public/pw_rpc/service.h index 957de33a9..2076896b7 100644 --- a/pw_rpc/public/pw_rpc/internal/service.h +++ b/pw_rpc/public/pw_rpc/service.h @@ -19,29 +19,32 @@ #include "pw_containers/intrusive_list.h" -namespace pw::rpc::internal { +namespace pw::rpc { +namespace internal { class Method; +} // namespace internal + // Base class for all RPC services. This cannot be instantiated directly; use a // generated subclass instead. class Service : public IntrusiveList<Service>::Item { public: uint32_t id() const { return id_; } - // Finds the method with the provided method_id. Returns nullptr if no match. - const Method* FindMethod(uint32_t method_id) const; - protected: template <typename T> constexpr Service(uint32_t id, T&& methods) : id_(id), methods_(std::forward<T>(methods)) {} private: - friend class ServiceRegistry; + friend class Server; + + // Finds the method with the provided method_id. Returns nullptr if no match. + const internal::Method* FindMethod(uint32_t method_id) const; uint32_t id_; - std::span<const Method> methods_; + std::span<const internal::Method> methods_; }; -} // namespace pw::rpc::internal +} // namespace pw::rpc diff --git a/pw_rpc/py/codegen_test.py b/pw_rpc/py/codegen_test.py index d72b6e5da..ee96a8c72 100644 --- a/pw_rpc/py/codegen_test.py +++ b/pw_rpc/py/codegen_test.py @@ -48,52 +48,95 @@ service TestService { EXPECTED_NANOPB_CODE = """\ #pragma once +#include <array> #include <cstddef> #include <cstdint> +#include <type_traits> -#include "pw_rpc/internal/service.h" +#include "pw_rpc/internal/method.h" +#include "pw_rpc/server_context.h" +#include "pw_rpc/service.h" #include "test.pb.h" +namespace pw::rpc::internal { + +template <auto> +class ServiceMethodTraits; + +} // namespace pw::rpc::internal namespace pw::rpc::test { +namespace generated { -class TestService : public ::pw::rpc::internal::Service { +template <typename Implementation> +class TestService : public ::pw::rpc::Service { public: using ServerContext = ::pw::rpc::ServerContext; - template <typename T> using ServerWriter = ::pw::rpc::ServerWriter<T>; + template <typename T> + using ServerWriter = ::pw::rpc::ServerWriter<T>; - constexpr TestService() : ::pw::rpc::internal::Service(kServiceId, kMethods) {} + constexpr TestService() + : ::pw::rpc::Service(kServiceId, kMethods) {} TestService(const TestService&) = delete; TestService& operator=(const TestService&) = delete; - static ::pw::Status TestRpc( - ServerContext& ctx, - const pw_rpc_test_TestRequest& request, - pw_rpc_test_TestResponse& response); + static constexpr const char* name() { return "TestService"; } - static ::pw::Status TestStreamRpc( - ServerContext& ctx, - const pw_rpc_test_Empty& request, - ServerWriter<pw_rpc_test_TestStreamResponse>& writer); + // Used by ServiceMethodTraits to identify a base service. + constexpr void _PwRpcInternalGeneratedBase() const {} private: - // 65599 hash of "TestService". - static constexpr uint32_t kServiceId = 0x105b6ac8; - static constexpr char* kServiceName = "TestService"; + // Hash of "pw.rpc.test.TestService". + static constexpr uint32_t kServiceId = 0xcc0f6de0; + + static ::pw::Status Invoke_TestRpc( + ::pw::rpc::internal::ServerCall& call, + const pw_rpc_test_TestRequest& request, + pw_rpc_test_TestResponse& response) { + return static_cast<Implementation&>(call.service()) + .TestRpc(call.context(), request, response); + } + + static void Invoke_TestStreamRpc( + ::pw::rpc::internal::ServerCall& call, + const pw_rpc_test_TestRequest& request, + ServerWriter<pw_rpc_test_TestStreamResponse>& writer) { + static_cast<Implementation&>(call.service()) + .TestStreamRpc(call.context(), request, writer); + } static constexpr std::array<::pw::rpc::internal::Method, 2> kMethods = { - ::pw::rpc::internal::Method::Unary<TestRpc>( - 0xbc924054, // 65599 hash of "TestRpc" + ::pw::rpc::internal::Method::Unary<Invoke_TestRpc>( + 0xbc924054, // Hash of "TestRpc" pw_rpc_test_TestRequest_fields, pw_rpc_test_TestResponse_fields), - ::pw::rpc::internal::Method::ServerStreaming<TestStreamRpc>( - 0xd97a28fa, // 65599 hash of "TestStreamRpc" - pw_rpc_test_Empty_fields, + ::pw::rpc::internal::Method::ServerStreaming<Invoke_TestStreamRpc>( + 0xd97a28fa, // Hash of "TestStreamRpc" + pw_rpc_test_TestRequest_fields, pw_rpc_test_TestStreamResponse_fields), }; + + template <auto impl_method> + static constexpr const ::pw::rpc::internal::Method* MethodFor() { + if constexpr (std::is_same_v<decltype(impl_method), decltype(&Implementation::TestRpc)>) { + if constexpr (impl_method == &Implementation::TestRpc) { + return &std::get<0>(kMethods); + } + } + if constexpr (std::is_same_v<decltype(impl_method), decltype(&Implementation::TestStreamRpc)>) { + if constexpr (impl_method == &Implementation::TestStreamRpc) { + return &std::get<1>(kMethods); + } + } + return nullptr; + } + + template <auto> + friend class ::pw::rpc::internal::ServiceMethodTraits; }; +} // namespace generated } // namespace pw::rpc::test """ @@ -128,7 +171,7 @@ class TestNanopbCodegen(unittest.TestCase): generated_files = os.listdir(self._output_dir.name) self.assertEqual(len(generated_files), 1) - self.assertEqual(generated_files[0], 'test_rpc.pb.h') + self.assertEqual(generated_files[0], 'test.rpc.pb.h') # Read the generated file, ignoring its preamble. generated_code = Path(self._output_dir.name, diff --git a/pw_rpc/py/pw_rpc/codegen_nanopb.py b/pw_rpc/py/pw_rpc/codegen_nanopb.py index 9432fa921..5aa21b86e 100644 --- a/pw_rpc/py/pw_rpc/codegen_nanopb.py +++ b/pw_rpc/py/pw_rpc/codegen_nanopb.py @@ -145,7 +145,7 @@ def _generate_code_for_service(service: ProtoNode, root: ProtoNode, output: OutputFile) -> None: """Generates a C++ derived class for a nanopb RPC service.""" - base_class = f'{RPC_NAMESPACE}::internal::Service' + base_class = f'{RPC_NAMESPACE}::Service' output.write_line('\ntemplate <typename Implementation>') output.write_line( f'class {service.cpp_namespace(root)} : public {base_class} {{') @@ -229,8 +229,8 @@ def generate_code_for_package(file_descriptor_proto, package: ProtoNode, output.write_line('#include <cstdint>') output.write_line('#include <type_traits>\n') output.write_line('#include "pw_rpc/internal/method.h"') - output.write_line('#include "pw_rpc/internal/service.h"') output.write_line('#include "pw_rpc/server_context.h"') + output.write_line('#include "pw_rpc/service.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 diff --git a/pw_rpc/server_test.cc b/pw_rpc/server_test.cc index 7f559d756..e2042ac75 100644 --- a/pw_rpc/server_test.cc +++ b/pw_rpc/server_test.cc @@ -20,7 +20,7 @@ #include "gtest/gtest.h" #include "pw_assert/assert.h" #include "pw_rpc/internal/packet.h" -#include "pw_rpc/internal/service.h" +#include "pw_rpc/service.h" #include "pw_rpc_private/internal_test_utils.h" namespace pw::rpc { @@ -32,10 +32,10 @@ using internal::Method; using internal::Packet; using internal::PacketType; -class TestService : public internal::Service { +class TestService : public Service { public: TestService(uint32_t service_id) - : internal::Service(service_id, methods_), + : Service(service_id, methods_), methods_{ Method(100), Method(200), diff --git a/pw_rpc/service.cc b/pw_rpc/service.cc index 3107c926a..50e0447bf 100644 --- a/pw_rpc/service.cc +++ b/pw_rpc/service.cc @@ -12,16 +12,16 @@ // License for the specific language governing permissions and limitations under // the License. -#include "pw_rpc/internal/service.h" +#include "pw_rpc/service.h" #include <type_traits> #include "pw_rpc/internal/method.h" -namespace pw::rpc::internal { +namespace pw::rpc { -const Method* Service::FindMethod(uint32_t method_id) const { - for (const Method& method : methods_) { +const internal::Method* Service::FindMethod(uint32_t method_id) const { + for (const internal::Method& method : methods_) { if (method.id() == method_id) { return &method; } @@ -30,4 +30,4 @@ const Method* Service::FindMethod(uint32_t method_id) const { return nullptr; } -} // namespace pw::rpc::internal +} // namespace pw::rpc |