xref: /aosp_15_r20/external/pigweed/pw_rpc/raw/public/pw_rpc/raw/internal/method.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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, MethodType::kUnary, {}};
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(id,
55                      AsynchronousUnaryInvoker,
56                      MethodType::kUnary,
57                      Function{.asynchronous_unary = wrapper});
58   }
59 
60   template <auto kMethod>
ServerStreaming(uint32_t id)61   static constexpr RawMethod ServerStreaming(uint32_t id) {
62     constexpr ServerStreamingFunction wrapper =
63         [](Service& service, ConstByteSpan request, RawServerWriter& writer) {
64           return CallMethodImplFunction<kMethod>(service, request, writer);
65         };
66     return RawMethod(id,
67                      ServerStreamingInvoker,
68                      MethodType::kServerStreaming,
69                      Function{.server_streaming = wrapper});
70   }
71 
72   template <auto kMethod>
ClientStreaming(uint32_t id)73   static constexpr RawMethod ClientStreaming(uint32_t id) {
74     constexpr StreamRequestFunction wrapper =
75         [](Service& service, RawServerReaderWriter& reader) {
76           return CallMethodImplFunction<kMethod>(
77               service, static_cast<RawServerReader&>(reader));
78         };
79     return RawMethod(id,
80                      ClientStreamingInvoker,
81                      MethodType::kClientStreaming,
82                      Function{.stream_request = wrapper});
83   }
84 
85   template <auto kMethod>
BidirectionalStreaming(uint32_t id)86   static constexpr RawMethod BidirectionalStreaming(uint32_t id) {
87     constexpr StreamRequestFunction wrapper =
88         [](Service& service, RawServerReaderWriter& reader_writer) {
89           return CallMethodImplFunction<kMethod>(service, reader_writer);
90         };
91     return RawMethod(id,
92                      BidirectionalStreamingInvoker,
93                      MethodType::kBidirectionalStreaming,
94                      Function{.stream_request = wrapper});
95   }
96 
97   // Represents an invalid method. Used to reduce error message verbosity.
Invalid()98   static constexpr RawMethod Invalid() {
99     return {0, InvalidInvoker, MethodType::kUnary, {}};
100   }
101 
102  private:
103   // Wraps the user-defined functions.
104   using SynchronousUnaryFunction = StatusWithSize (*)(Service&,
105                                                       ConstByteSpan,
106                                                       ByteSpan);
107 
108   using AsynchronousUnaryFunction = void (*)(Service&,
109                                              ConstByteSpan,
110                                              RawUnaryResponder&);
111 
112   using ServerStreamingFunction = void (*)(Service&,
113                                            ConstByteSpan,
114                                            RawServerWriter&);
115 
116   using StreamRequestFunction = void (*)(Service&, RawServerReaderWriter&);
117 
118   union Function {
119     SynchronousUnaryFunction synchronous_unary;
120     AsynchronousUnaryFunction asynchronous_unary;
121     ServerStreamingFunction server_streaming;
122     StreamRequestFunction stream_request;
123   };
124 
RawMethod(uint32_t id,Invoker invoker,MethodType type,Function function)125   constexpr RawMethod(uint32_t id,
126                       Invoker invoker,
127                       MethodType type,
128                       Function function)
129       : Method(id, invoker, type), function_(function) {}
130 
131   static void AsynchronousUnaryInvoker(const CallContext& context,
132                                        const Packet& request)
133       PW_UNLOCK_FUNCTION(rpc_lock());
134 
135   static void ServerStreamingInvoker(const CallContext& context,
136                                      const Packet& request)
137       PW_UNLOCK_FUNCTION(rpc_lock());
138 
139   static void ClientStreamingInvoker(const CallContext& context, const Packet&)
140       PW_UNLOCK_FUNCTION(rpc_lock());
141 
142   static void BidirectionalStreamingInvoker(const CallContext& context,
143                                             const Packet&)
144       PW_UNLOCK_FUNCTION(rpc_lock());
145 
146   // Stores the user-defined RPC.
147   Function function_;
148 };
149 
150 // Expected function signatures for user-implemented RPC functions.
151 using RawSynchronousUnary = StatusWithSize(ConstByteSpan, ByteSpan);
152 using RawAsynchronousUnary = void(ConstByteSpan, RawUnaryResponder&);
153 using RawServerStreaming = void(ConstByteSpan, RawServerWriter&);
154 using RawClientStreaming = void(RawServerReader&);
155 using RawBidirectionalStreaming = void(RawServerReaderWriter&);
156 
157 // MethodTraits specialization for a static synchronous raw unary method.
158 template <>
159 struct MethodTraits<RawSynchronousUnary*> {
160   using Implementation = RawMethod;
161 
162   static constexpr MethodType kType = MethodType::kUnary;
163   static constexpr bool kSynchronous = true;
164 
165   static constexpr bool kServerStreaming = false;
166   static constexpr bool kClientStreaming = false;
167 };
168 
169 // MethodTraits specialization for a synchronous raw unary method.
170 template <typename T>
171 struct MethodTraits<RawSynchronousUnary(T::*)>
172     : MethodTraits<RawSynchronousUnary*> {
173   using Service = T;
174 };
175 
176 // MethodTraits specialization for a static asynchronous raw unary method.
177 template <>
178 struct MethodTraits<RawAsynchronousUnary*>
179     : MethodTraits<RawSynchronousUnary*> {
180   static constexpr bool kSynchronous = false;
181 };
182 
183 // MethodTraits specialization for an asynchronous raw unary method.
184 template <typename T>
185 struct MethodTraits<RawAsynchronousUnary(T::*)>
186     : MethodTraits<RawSynchronousUnary(T::*)> {
187   static constexpr bool kSynchronous = false;
188 };
189 
190 // MethodTraits specialization for a static raw server streaming method.
191 template <>
192 struct MethodTraits<RawServerStreaming*> {
193   using Implementation = RawMethod;
194   static constexpr MethodType kType = MethodType::kServerStreaming;
195   static constexpr bool kServerStreaming = true;
196   static constexpr bool kClientStreaming = false;
197 };
198 
199 // MethodTraits specialization for a raw server streaming method.
200 template <typename T>
201 struct MethodTraits<RawServerStreaming(T::*)>
202     : MethodTraits<RawServerStreaming*> {
203   using Service = T;
204 };
205 
206 // MethodTraits specialization for a static raw client streaming method.
207 template <>
208 struct MethodTraits<RawClientStreaming*> {
209   using Implementation = RawMethod;
210   static constexpr MethodType kType = MethodType::kClientStreaming;
211   static constexpr bool kServerStreaming = false;
212   static constexpr bool kClientStreaming = true;
213 };
214 
215 // MethodTraits specialization for a raw client streaming method.
216 template <typename T>
217 struct MethodTraits<RawClientStreaming(T::*)>
218     : MethodTraits<RawClientStreaming*> {
219   using Service = T;
220 };
221 
222 // MethodTraits specialization for a static raw bidirectional streaming method.
223 template <>
224 struct MethodTraits<RawBidirectionalStreaming*> {
225   using Implementation = RawMethod;
226   static constexpr MethodType kType = MethodType::kBidirectionalStreaming;
227   static constexpr bool kServerStreaming = true;
228   static constexpr bool kClientStreaming = true;
229 };
230 
231 // MethodTraits specialization for a raw bidirectional streaming method.
232 template <typename T>
233 struct MethodTraits<RawBidirectionalStreaming(T::*)>
234     : MethodTraits<RawBidirectionalStreaming*> {
235   using Service = T;
236 };
237 
238 }  // namespace pw::rpc::internal
239