• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <utility>
19 
20 #include "pw_rpc/internal/call.h"
21 
22 namespace pw::rpc::internal {
23 
24 class Packet;
25 
26 // Each supported protobuf implementation provides a class that derives from
27 // Method. The implementation classes provide the following public interface:
28 /*
29 class MethodImpl : public Method {
30   // True if the provided function signature is valid for this method impl.
31   template <auto method>
32   static constexpr bool matches();
33 
34   // Creates a unary method instance.
35   template <auto method>
36   static constexpr MethodImpl Unary(uint32_t id, [optional args]);
37 
38   // Creates a server streaming method instance.
39   template <auto method>
40   static constexpr MethodImpl ServerStreaming(uint32_t id, [optional args]);
41 
42   // Creates a client streaming method instance.
43   static constexpr MethodImpl ClientStreaming(uint32_t id, [optional args]);
44 
45   // Creates a bidirectional streaming method instance.
46   static constexpr MethodImpl BidirectionalStreaming(uint32_t id,
47                                                      [optional args]);
48 
49   // Creates a method instance for when the method implementation function has
50   // an incorrect signature. Having this helps reduce error message verbosity.
51   static constexpr MethodImpl Invalid();
52 };
53 */
54 // Method implementations must pass a test that uses the MethodImplTester class
55 // in pw_rpc_private/method_impl_tester.h.
56 class Method {
57  public:
id()58   constexpr uint32_t id() const { return id_; }
59 
60   // The pw::rpc::Server calls method.Invoke to call a user-defined RPC. Invoke
61   // calls the invoker function, which handles the RPC request and response
62   // according to the RPC type and protobuf implementation and calls the
63   // user-defined RPC function.
Invoke(ServerCall & call,const Packet & request)64   void Invoke(ServerCall& call, const Packet& request) const {
65     return invoker_(*this, call, request);
66   }
67 
68  protected:
69   using Invoker = void (&)(const Method&, ServerCall&, const Packet&);
70 
InvalidInvoker(const Method &,ServerCall &,const Packet &)71   static constexpr void InvalidInvoker(const Method&,
72                                        ServerCall&,
73                                        const Packet&) {}
74 
Method(uint32_t id,Invoker invoker)75   constexpr Method(uint32_t id, Invoker invoker) : id_(id), invoker_(invoker) {}
76 
77  private:
78   uint32_t id_;
79   Invoker invoker_;
80 };
81 
82 // Traits struct that determines the type of an RPC service method from its
83 // signature. Derived Methods should provide specializations for their method
84 // types.
85 template <typename Method>
86 struct MethodTraits {
87   // Specializations must set Implementation as an alias for their method
88   // implementation class.
89   using Implementation = Method;
90 
91   // Specializations must set kType to the MethodType.
92   // static constexpr MethodType kType = (method type);
93 
94   // Specializations for member function types must set Service to an alias to
95   // for the implemented service class.
96   using Service = rpc::Service;
97 
98   // Specializations may provide the C++ types of the requests and responses if
99   // relevant.
100   using Request = void;
101   using Response = void;
102 };
103 
104 template <auto method>
105 using MethodImplementation =
106     typename MethodTraits<decltype(method)>::Implementation;
107 
108 // Function that calls a user-defined method implementation function from a
109 // ServerCall object.
110 template <auto method, typename... Args>
CallMethodImplFunction(ServerCall & call,Args &&...args)111 constexpr auto CallMethodImplFunction(ServerCall& call, Args&&... args) {
112   // If the method impl is a member function, deduce the type of the
113   // user-defined service from it, then call the method on the service.
114   if constexpr (std::is_member_function_pointer_v<decltype(method)>) {
115     return (static_cast<typename MethodTraits<decltype(method)>::Service&>(
116                 call.service()).*
117             method)(call.context(), std::forward<Args>(args)...);
118   } else {
119     return method(call.context(), std::forward<Args>(args)...);
120   }
121 }
122 
123 // Identifies a base class from a member function it defines. This should be
124 // used with decltype to retrieve the base service class.
125 template <typename T, typename U>
126 T BaseFromMember(U T::*);
127 
128 // The base generated service of an RPC service class.
129 template <typename Service>
130 using GeneratedService =
131     decltype(BaseFromMember(&Service::_PwRpcInternalGeneratedBase));
132 
133 }  // namespace pw::rpc::internal
134