• 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_context.h"
21 #include "pw_rpc/internal/lock.h"
22 
23 namespace pw::rpc {
24 
25 class Service;
26 
27 namespace internal {
28 
29 class Packet;
30 
31 // Each supported protobuf implementation provides a class that derives from
32 // Method. The implementation classes provide the following public interface:
33 /*
34 class MethodImpl : public Method {
35   // True if the provided function signature is valid for this method impl.
36   template <auto kMethod>
37   static constexpr bool matches();
38 
39   // Creates a unary method instance.
40   template <auto kMethod>
41   static constexpr MethodImpl Unary(uint32_t id, [optional args]);
42 
43   // Creates a server streaming method instance.
44   template <auto kMethod>
45   static constexpr MethodImpl ServerStreaming(uint32_t id, [optional args]);
46 
47   // Creates a client streaming method instance.
48   static constexpr MethodImpl ClientStreaming(uint32_t id, [optional args]);
49 
50   // Creates a bidirectional streaming method instance.
51   static constexpr MethodImpl BidirectionalStreaming(uint32_t id,
52                                                      [optional args]);
53 
54   // Creates a method instance for when the method implementation function has
55   // an incorrect signature. Having this helps reduce error message verbosity.
56   static constexpr MethodImpl Invalid();
57 };
58 */
59 // Method implementations must pass a test that uses the MethodImplTester class
60 // in pw_rpc/internal/method_impl_tester.h.
61 class Method {
62  public:
id()63   constexpr uint32_t id() const { return id_; }
64 
65   // The pw::rpc::Server calls method.Invoke to call a user-defined RPC. Invoke
66   // calls the invoker function, which handles the RPC request and response
67   // according to the RPC type and protobuf implementation and calls the
68   // user-defined RPC function.
69   //
70   // The rpc_lock() must be held through creating the call object and released
71   // before calling into the RPC body.
Invoke(const CallContext & context,const Packet & request)72   void Invoke(const CallContext& context, const Packet& request) const
73       PW_UNLOCK_FUNCTION(rpc_lock()) PW_NO_LOCK_SAFETY_ANALYSIS {
74     return invoker_(context, request);  // The invoker must unlock rpc_lock().
75   }
76 
77  protected:
78   using Invoker = void (&)(const CallContext&, const Packet&);
79 
InvalidInvoker(const CallContext &,const Packet &)80   static constexpr void InvalidInvoker(const CallContext&, const Packet&) {}
81 
Method(uint32_t id,Invoker invoker)82   constexpr Method(uint32_t id, Invoker invoker) : id_(id), invoker_(invoker) {}
83 
84  private:
85   uint32_t id_;
86   Invoker invoker_;
87 };
88 
89 // MethodTraits inspects an RPC implementation function. It determines which
90 // Method API is in use and the type of the RPC based on the function signature.
91 // pw_rpc Method implementations specialize MethodTraits for each RPC type.
92 template <typename Method>
93 struct MethodTraits {
94   // Specializations must set Implementation as an alias for their method
95   // implementation class.
96   using Implementation = Method;
97 
98   // Specializations must set kType to the MethodType.
99   // static constexpr MethodType kType = (method type);
100 
101   // Specializations for member function types must set Service to an alias to
102   // for the implemented service class.
103   // using Service = (derived service class);
104 
105   // Specializations may provide the C++ types of the requests and responses if
106   // relevant.
107   using Request = void;
108   using Response = void;
109 };
110 
111 template <auto kMethod>
112 using MethodImplementation =
113     typename MethodTraits<decltype(kMethod)>::Implementation;
114 
115 template <auto kMethod>
116 using Request = typename MethodTraits<decltype(kMethod)>::Request;
117 
118 template <auto kMethod>
119 using Response = typename MethodTraits<decltype(kMethod)>::Response;
120 
121 // Function that calls a user-defined RPC function on the given Service.
122 template <auto kMethod, typename... Args>
CallMethodImplFunction(Service & service,Args &&...args)123 constexpr auto CallMethodImplFunction(Service& service, Args&&... args) {
124   // If the method impl is a member function, deduce the type of the
125   // user-defined service from it, then call the method on the service.
126   if constexpr (std::is_member_function_pointer_v<decltype(kMethod)>) {
127     return (static_cast<typename MethodTraits<decltype(kMethod)>::Service&>(
128                 service).*
129             kMethod)(std::forward<Args>(args)...);
130   } else {
131     return kMethod(std::forward<Args>(args)...);
132   }
133 }
134 
135 }  // namespace internal
136 }  // namespace pw::rpc
137