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/base_server_writer.h" 18 #include "pw_rpc/internal/method.h" 19 #include "pw_rpc/internal/method_type.h" 20 #include "pw_status/status_with_size.h" 21 22 namespace pw::rpc { 23 24 class RawServerWriter : public internal::BaseServerWriter { 25 public: 26 RawServerWriter() = default; 27 RawServerWriter(RawServerWriter&&) = default; 28 RawServerWriter& operator=(RawServerWriter&&) = default; 29 30 ~RawServerWriter(); 31 32 // Returns a buffer in which a response payload can be built. PayloadBuffer()33 ByteSpan PayloadBuffer() { return AcquirePayloadBuffer(); } 34 35 // Sends a response packet with the given raw payload. The payload can either 36 // be in the buffer previously acquired from PayloadBuffer(), or an arbitrary 37 // external buffer. 38 Status Write(ConstByteSpan response); 39 }; 40 41 namespace internal { 42 43 // A RawMethod is a method invoker which does not perform any automatic protobuf 44 // serialization or deserialization. The implementer is given the raw binary 45 // payload of incoming requests, and is responsible for encoding responses to a 46 // provided buffer. This is intended for use in methods which would have large 47 // protobuf data structure overhead to lower stack usage, or in methods packing 48 // responses up to a channel's MTU. 49 class RawMethod : public Method { 50 public: 51 template <auto method> matches()52 static constexpr bool matches() { 53 return std::is_same_v<MethodImplementation<method>, RawMethod>; 54 } 55 56 template <auto method> Unary(uint32_t id)57 static constexpr RawMethod Unary(uint32_t id) { 58 constexpr UnaryFunction wrapper = 59 [](ServerCall& call, ConstByteSpan req, ByteSpan res) { 60 return CallMethodImplFunction<method>(call, req, res); 61 }; 62 return RawMethod(id, UnaryInvoker, Function{.unary = wrapper}); 63 } 64 65 template <auto method> ServerStreaming(uint32_t id)66 static constexpr RawMethod ServerStreaming(uint32_t id) { 67 constexpr ServerStreamingFunction wrapper = 68 [](ServerCall& call, ConstByteSpan request, BaseServerWriter& writer) { 69 CallMethodImplFunction<method>( 70 call, request, static_cast<RawServerWriter&>(writer)); 71 }; 72 return RawMethod( 73 id, ServerStreamingInvoker, Function{.server_streaming = wrapper}); 74 } 75 76 // Represents an invalid method. Used to reduce error message verbosity. Invalid()77 static constexpr RawMethod Invalid() { return {0, InvalidInvoker, {}}; } 78 79 private: 80 using UnaryFunction = StatusWithSize (*)(ServerCall&, 81 ConstByteSpan, 82 ByteSpan); 83 84 using ServerStreamingFunction = void (*)(ServerCall&, 85 ConstByteSpan, 86 BaseServerWriter&); 87 union Function { 88 UnaryFunction unary; 89 ServerStreamingFunction server_streaming; 90 // TODO(frolv): Support client and bidirectional streaming. 91 }; 92 RawMethod(uint32_t id,Invoker invoker,Function function)93 constexpr RawMethod(uint32_t id, Invoker invoker, Function function) 94 : Method(id, invoker), function_(function) {} 95 UnaryInvoker(const Method & method,ServerCall & call,const Packet & request)96 static void UnaryInvoker(const Method& method, 97 ServerCall& call, 98 const Packet& request) { 99 static_cast<const RawMethod&>(method).CallUnary(call, request); 100 } 101 ServerStreamingInvoker(const Method & method,ServerCall & call,const Packet & request)102 static void ServerStreamingInvoker(const Method& method, 103 ServerCall& call, 104 const Packet& request) { 105 static_cast<const RawMethod&>(method).CallServerStreaming(call, request); 106 } 107 108 void CallUnary(ServerCall& call, const Packet& request) const; 109 void CallServerStreaming(ServerCall& call, const Packet& request) const; 110 111 // Stores the user-defined RPC in a generic wrapper. 112 Function function_; 113 }; 114 115 // MethodTraits specialization for a static raw unary method. 116 template <> 117 struct MethodTraits<StatusWithSize (*)( 118 ServerContext&, ConstByteSpan, ByteSpan)> { 119 using Implementation = RawMethod; 120 static constexpr MethodType kType = MethodType::kUnary; 121 }; 122 123 // MethodTraits specialization for a raw unary method. 124 template <typename T> 125 struct MethodTraits<StatusWithSize (T::*)( 126 ServerContext&, ConstByteSpan, ByteSpan)> { 127 using Implementation = RawMethod; 128 static constexpr MethodType kType = MethodType::kUnary; 129 using Service = T; 130 }; 131 132 // MethodTraits specialization for a static raw server streaming method. 133 template <> 134 struct MethodTraits<void (*)(ServerContext&, ConstByteSpan, RawServerWriter&)> { 135 using Implementation = RawMethod; 136 static constexpr MethodType kType = MethodType::kServerStreaming; 137 }; 138 139 // MethodTraits specialization for a raw server streaming method. 140 template <typename T> 141 struct MethodTraits<void (T::*)( 142 ServerContext&, ConstByteSpan, RawServerWriter&)> { 143 using Implementation = RawMethod; 144 static constexpr MethodType kType = MethodType::kServerStreaming; 145 using Service = T; 146 }; 147 148 } // namespace internal 149 } // namespace pw::rpc 150