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