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