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