• 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 SynchronousUnaryInvoker(const CallContext& context,
119                                       const Packet& request)
120       PW_UNLOCK_FUNCTION(rpc_lock());
121 
122   static void AsynchronousUnaryInvoker(const CallContext& context,
123                                        const Packet& request)
124       PW_UNLOCK_FUNCTION(rpc_lock());
125 
126   static void ServerStreamingInvoker(const CallContext& context,
127                                      const Packet& request)
128       PW_UNLOCK_FUNCTION(rpc_lock());
129 
130   static void ClientStreamingInvoker(const CallContext& context, const Packet&)
131       PW_UNLOCK_FUNCTION(rpc_lock());
132 
133   static void BidirectionalStreamingInvoker(const CallContext& context,
134                                             const Packet&)
135       PW_UNLOCK_FUNCTION(rpc_lock());
136 
137   // Stores the user-defined RPC.
138   Function function_;
139 };
140 
141 // Expected function signatures for user-implemented RPC functions.
142 using RawSynchronousUnary = StatusWithSize(ConstByteSpan, ByteSpan);
143 using RawAsynchronousUnary = void(ConstByteSpan, RawUnaryResponder&);
144 using RawServerStreaming = void(ConstByteSpan, RawServerWriter&);
145 using RawClientStreaming = void(RawServerReader&);
146 using RawBidirectionalStreaming = void(RawServerReaderWriter&);
147 
148 // MethodTraits specialization for a static synchronous raw unary method.
149 template <>
150 struct MethodTraits<RawSynchronousUnary*> {
151   using Implementation = RawMethod;
152 
153   static constexpr MethodType kType = MethodType::kUnary;
154   static constexpr bool kSynchronous = true;
155 
156   static constexpr bool kServerStreaming = false;
157   static constexpr bool kClientStreaming = false;
158 };
159 
160 // MethodTraits specialization for a synchronous raw unary method.
161 template <typename T>
162 struct MethodTraits<RawSynchronousUnary(T::*)>
163     : MethodTraits<RawSynchronousUnary*> {
164   using Service = T;
165 };
166 
167 // MethodTraits specialization for a static asynchronous raw unary method.
168 template <>
169 struct MethodTraits<RawAsynchronousUnary*>
170     : MethodTraits<RawSynchronousUnary*> {
171   static constexpr bool kSynchronous = false;
172 };
173 
174 // MethodTraits specialization for an asynchronous raw unary method.
175 template <typename T>
176 struct MethodTraits<RawAsynchronousUnary(T::*)>
177     : MethodTraits<RawSynchronousUnary(T::*)> {
178   static constexpr bool kSynchronous = false;
179 };
180 
181 // MethodTraits specialization for a static raw server streaming method.
182 template <>
183 struct MethodTraits<RawServerStreaming*> {
184   using Implementation = RawMethod;
185   static constexpr MethodType kType = MethodType::kServerStreaming;
186   static constexpr bool kServerStreaming = true;
187   static constexpr bool kClientStreaming = false;
188 };
189 
190 // MethodTraits specialization for a raw server streaming method.
191 template <typename T>
192 struct MethodTraits<RawServerStreaming(T::*)>
193     : MethodTraits<RawServerStreaming*> {
194   using Service = T;
195 };
196 
197 // MethodTraits specialization for a static raw client streaming method.
198 template <>
199 struct MethodTraits<RawClientStreaming*> {
200   using Implementation = RawMethod;
201   static constexpr MethodType kType = MethodType::kClientStreaming;
202   static constexpr bool kServerStreaming = false;
203   static constexpr bool kClientStreaming = true;
204 };
205 
206 // MethodTraits specialization for a raw client streaming method.
207 template <typename T>
208 struct MethodTraits<RawClientStreaming(T::*)>
209     : MethodTraits<RawClientStreaming*> {
210   using Service = T;
211 };
212 
213 // MethodTraits specialization for a static raw bidirectional streaming method.
214 template <>
215 struct MethodTraits<RawBidirectionalStreaming*> {
216   using Implementation = RawMethod;
217   static constexpr MethodType kType = MethodType::kBidirectionalStreaming;
218   static constexpr bool kServerStreaming = true;
219   static constexpr bool kClientStreaming = true;
220 };
221 
222 // MethodTraits specialization for a raw bidirectional streaming method.
223 template <typename T>
224 struct MethodTraits<RawBidirectionalStreaming(T::*)>
225     : MethodTraits<RawBidirectionalStreaming*> {
226   using Service = T;
227 };
228 
229 }  // namespace pw::rpc::internal
230