• 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 "pw_bytes/span.h"
17 #include "pw_rpc/internal/method.h"
18 #include "pw_rpc/method_type.h"
19 #include "pw_rpc/raw/server_reader_writer.h"
20 #include "pw_rpc/service.h"
21 #include "pw_status/status_with_size.h"
22 
23 namespace pw::rpc::internal {
24 
25 // A RawMethod is a method invoker which does not perform any automatic protobuf
26 // serialization or deserialization. The implementer is given the raw binary
27 // payload of incoming requests, and is responsible for encoding responses to a
28 // provided buffer. This is intended for use in methods which would have large
29 // protobuf data structure overhead to lower stack usage, or in methods packing
30 // responses up to a channel's MTU.
31 class RawMethod : public Method {
32  public:
33   template <auto kMethod>
matches()34   static constexpr bool matches() {
35     return std::is_same_v<MethodImplementation<kMethod>, RawMethod>;
36   }
37 
38   template <auto kMethod>
SynchronousUnary(uint32_t id)39   static constexpr RawMethod SynchronousUnary(uint32_t id) {
40     static_assert(sizeof(kMethod) != sizeof(kMethod),
41                   "Raw synchronous unary methods are not supported. "
42                   "Use an asynchronous unary method instead: "
43                   "void MethodName(pw::ConstByteSpan request, "
44                   "pw::rpc::RawUnaryResponder& responder)");
45     return {id, InvalidInvoker, {}};
46   }
47 
48   template <auto kMethod>
AsynchronousUnary(uint32_t id)49   static constexpr RawMethod AsynchronousUnary(uint32_t id) {
50     constexpr AsynchronousUnaryFunction wrapper =
51         [](Service& service, ConstByteSpan req, RawUnaryResponder& responder) {
52           return CallMethodImplFunction<kMethod>(service, req, responder);
53         };
54     return RawMethod(
55         id, AsynchronousUnaryInvoker, Function{.asynchronous_unary = wrapper});
56   }
57 
58   template <auto kMethod>
ServerStreaming(uint32_t id)59   static constexpr RawMethod ServerStreaming(uint32_t id) {
60     constexpr ServerStreamingFunction wrapper =
61         [](Service& service, ConstByteSpan request, RawServerWriter& writer) {
62           return CallMethodImplFunction<kMethod>(service, request, writer);
63         };
64     return RawMethod(
65         id, ServerStreamingInvoker, Function{.server_streaming = wrapper});
66   }
67 
68   template <auto kMethod>
ClientStreaming(uint32_t id)69   static constexpr RawMethod ClientStreaming(uint32_t id) {
70     constexpr StreamRequestFunction wrapper =
71         [](Service& service, RawServerReaderWriter& reader) {
72           return CallMethodImplFunction<kMethod>(
73               service, static_cast<RawServerReader&>(reader));
74         };
75     return RawMethod(
76         id, ClientStreamingInvoker, Function{.stream_request = wrapper});
77   }
78 
79   template <auto kMethod>
BidirectionalStreaming(uint32_t id)80   static constexpr RawMethod BidirectionalStreaming(uint32_t id) {
81     constexpr StreamRequestFunction wrapper =
82         [](Service& service, RawServerReaderWriter& reader_writer) {
83           return CallMethodImplFunction<kMethod>(service, reader_writer);
84         };
85     return RawMethod(
86         id, BidirectionalStreamingInvoker, Function{.stream_request = wrapper});
87   }
88 
89   // Represents an invalid method. Used to reduce error message verbosity.
Invalid()90   static constexpr RawMethod Invalid() { return {0, InvalidInvoker, {}}; }
91 
92  private:
93   // Wraps the user-defined functions.
94   using SynchronousUnaryFunction = StatusWithSize (*)(Service&,
95                                                       ConstByteSpan,
96                                                       ByteSpan);
97 
98   using AsynchronousUnaryFunction = void (*)(Service&,
99                                              ConstByteSpan,
100                                              RawUnaryResponder&);
101 
102   using ServerStreamingFunction = void (*)(Service&,
103                                            ConstByteSpan,
104                                            RawServerWriter&);
105 
106   using StreamRequestFunction = void (*)(Service&, RawServerReaderWriter&);
107 
108   union Function {
109     SynchronousUnaryFunction synchronous_unary;
110     AsynchronousUnaryFunction asynchronous_unary;
111     ServerStreamingFunction server_streaming;
112     StreamRequestFunction stream_request;
113   };
114 
RawMethod(uint32_t id,Invoker invoker,Function function)115   constexpr RawMethod(uint32_t id, Invoker invoker, Function function)
116       : Method(id, invoker), function_(function) {}
117 
118   static void AsynchronousUnaryInvoker(const CallContext& context,
119                                        const Packet& request)
120       PW_UNLOCK_FUNCTION(rpc_lock());
121 
122   static void ServerStreamingInvoker(const CallContext& context,
123                                      const Packet& request)
124       PW_UNLOCK_FUNCTION(rpc_lock());
125 
126   static void ClientStreamingInvoker(const CallContext& context, const Packet&)
127       PW_UNLOCK_FUNCTION(rpc_lock());
128 
129   static void BidirectionalStreamingInvoker(const CallContext& context,
130                                             const Packet&)
131       PW_UNLOCK_FUNCTION(rpc_lock());
132 
133   // Stores the user-defined RPC.
134   Function function_;
135 };
136 
137 // Expected function signatures for user-implemented RPC functions.
138 using RawSynchronousUnary = StatusWithSize(ConstByteSpan, ByteSpan);
139 using RawAsynchronousUnary = void(ConstByteSpan, RawUnaryResponder&);
140 using RawServerStreaming = void(ConstByteSpan, RawServerWriter&);
141 using RawClientStreaming = void(RawServerReader&);
142 using RawBidirectionalStreaming = void(RawServerReaderWriter&);
143 
144 // MethodTraits specialization for a static synchronous raw unary method.
145 template <>
146 struct MethodTraits<RawSynchronousUnary*> {
147   using Implementation = RawMethod;
148 
149   static constexpr MethodType kType = MethodType::kUnary;
150   static constexpr bool kSynchronous = true;
151 
152   static constexpr bool kServerStreaming = false;
153   static constexpr bool kClientStreaming = false;
154 };
155 
156 // MethodTraits specialization for a synchronous raw unary method.
157 template <typename T>
158 struct MethodTraits<RawSynchronousUnary(T::*)>
159     : MethodTraits<RawSynchronousUnary*> {
160   using Service = T;
161 };
162 
163 // MethodTraits specialization for a static asynchronous raw unary method.
164 template <>
165 struct MethodTraits<RawAsynchronousUnary*>
166     : MethodTraits<RawSynchronousUnary*> {
167   static constexpr bool kSynchronous = false;
168 };
169 
170 // MethodTraits specialization for an asynchronous raw unary method.
171 template <typename T>
172 struct MethodTraits<RawAsynchronousUnary(T::*)>
173     : MethodTraits<RawSynchronousUnary(T::*)> {
174   static constexpr bool kSynchronous = false;
175 };
176 
177 // MethodTraits specialization for a static raw server streaming method.
178 template <>
179 struct MethodTraits<RawServerStreaming*> {
180   using Implementation = RawMethod;
181   static constexpr MethodType kType = MethodType::kServerStreaming;
182   static constexpr bool kServerStreaming = true;
183   static constexpr bool kClientStreaming = false;
184 };
185 
186 // MethodTraits specialization for a raw server streaming method.
187 template <typename T>
188 struct MethodTraits<RawServerStreaming(T::*)>
189     : MethodTraits<RawServerStreaming*> {
190   using Service = T;
191 };
192 
193 // MethodTraits specialization for a static raw client streaming method.
194 template <>
195 struct MethodTraits<RawClientStreaming*> {
196   using Implementation = RawMethod;
197   static constexpr MethodType kType = MethodType::kClientStreaming;
198   static constexpr bool kServerStreaming = false;
199   static constexpr bool kClientStreaming = true;
200 };
201 
202 // MethodTraits specialization for a raw client streaming method.
203 template <typename T>
204 struct MethodTraits<RawClientStreaming(T::*)>
205     : MethodTraits<RawClientStreaming*> {
206   using Service = T;
207 };
208 
209 // MethodTraits specialization for a static raw bidirectional streaming method.
210 template <>
211 struct MethodTraits<RawBidirectionalStreaming*> {
212   using Implementation = RawMethod;
213   static constexpr MethodType kType = MethodType::kBidirectionalStreaming;
214   static constexpr bool kServerStreaming = true;
215   static constexpr bool kClientStreaming = true;
216 };
217 
218 // MethodTraits specialization for a raw bidirectional streaming method.
219 template <typename T>
220 struct MethodTraits<RawBidirectionalStreaming(T::*)>
221     : MethodTraits<RawBidirectionalStreaming*> {
222   using Service = T;
223 };
224 
225 }  // namespace pw::rpc::internal
226