pw_rpc: Make Service independent of Method

Rather than depending on the concrete Method implementation, store a
BaseMethod* and the method implementation's size.

Change-Id: Ic52a9a7526f542ab872ed6a14be5c93e93dd95f1
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/18240
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
diff --git a/pw_rpc/public/pw_rpc/service.h b/pw_rpc/public/pw_rpc/service.h
index 2076896..dd05c0c 100644
--- a/pw_rpc/public/pw_rpc/service.h
+++ b/pw_rpc/public/pw_rpc/service.h
@@ -14,37 +14,50 @@
 #pragma once
 
 #include <cstdint>
+#include <limits>
 #include <span>
-#include <utility>
 
 #include "pw_containers/intrusive_list.h"
+#include "pw_rpc/internal/base_method.h"
 
 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.
+//
+// Services store a span of concrete method classes. To support different Method
+// implementations, Service stores as base Method* and the size of the concrete
+// method object.
 class Service : public IntrusiveList<Service>::Item {
  public:
   uint32_t id() const { return id_; }
 
  protected:
+  template <typename T, size_t method_count>
+  constexpr Service(uint32_t id, const std::array<T, method_count>& methods)
+      : id_(id),
+        methods_(methods.data()),
+        method_size_(sizeof(T)),
+        method_count_(static_cast<uint16_t>(method_count)) {
+    static_assert(method_count <= std::numeric_limits<uint16_t>::max());
+  }
+
+  // For use by tests with only one method.
   template <typename T>
-  constexpr Service(uint32_t id, T&& methods)
-      : id_(id), methods_(std::forward<T>(methods)) {}
+  constexpr Service(uint32_t id, const T& method)
+      : id_(id), methods_(&method), method_size_(sizeof(T)), method_count_(1) {}
 
  private:
   friend class Server;
+  friend class ServiceTestHelper;
 
   // Finds the method with the provided method_id. Returns nullptr if no match.
-  const internal::Method* FindMethod(uint32_t method_id) const;
+  const internal::BaseMethod* FindMethod(uint32_t method_id) const;
 
-  uint32_t id_;
-  std::span<const internal::Method> methods_;
+  const uint32_t id_;
+  const internal::BaseMethod* const methods_;
+  const uint16_t method_size_;
+  const uint16_t method_count_;
 };
 
 }  // namespace pw::rpc