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 <cstdint> 17 #include <span> 18 #include <type_traits> 19 20 #include "pw_assert/light.h" 21 #include "pw_status/status.h" 22 23 namespace pw::rpc { 24 namespace internal { 25 26 class BaseClientCall; 27 28 } // namespace internal 29 30 class Client; 31 32 class ChannelOutput { 33 public: 34 // Creates a channel output with the provided name. The name is used for 35 // logging only. ChannelOutput(const char * name)36 constexpr ChannelOutput(const char* name) : name_(name) {} 37 38 virtual ~ChannelOutput() = default; 39 name()40 constexpr const char* name() const { return name_; } 41 42 // Acquire a buffer into which to write an outgoing RPC packet. The 43 // implementation is expected to handle synchronization if necessary. 44 virtual std::span<std::byte> AcquireBuffer() = 0; 45 46 // Sends the contents of a buffer previously obtained from AcquireBuffer(). 47 // This may be called with an empty span, in which case the buffer should be 48 // released without sending any data. 49 // 50 // Returns OK if the operation succeeded, or an implementation-defined Status 51 // value if there was an error. The implementation must NOT return 52 // FAILED_PRECONDITION or INTERNAL, which are reserved by pw_rpc. 53 virtual Status SendAndReleaseBuffer(std::span<const std::byte> buffer) = 0; 54 DiscardBuffer(std::span<const std::byte> buffer)55 void DiscardBuffer(std::span<const std::byte> buffer) { 56 SendAndReleaseBuffer(buffer.first(0)); 57 } 58 59 private: 60 const char* name_; 61 }; 62 63 class Channel { 64 public: 65 static constexpr uint32_t kUnassignedChannelId = 0; 66 67 // Creates a dynamically assignable channel without a set ID or output. Channel()68 constexpr Channel() 69 : id_(kUnassignedChannelId), output_(nullptr), client_(nullptr) {} 70 71 // Creates a channel with a static ID. The channel's output can also be 72 // static, or it can set to null to allow dynamically opening connections 73 // through the channel. 74 template <uint32_t kId> Create(ChannelOutput * output)75 constexpr static Channel Create(ChannelOutput* output) { 76 static_assert(kId != kUnassignedChannelId, "Channel ID cannot be 0"); 77 return Channel(kId, output); 78 } 79 80 // Creates a channel with a static ID from an enum value. 81 template <auto kId, 82 typename T = decltype(kId), 83 typename = std::enable_if_t<std::is_enum_v<T>>, 84 typename U = std::underlying_type_t<T>> Create(ChannelOutput * output)85 constexpr static Channel Create(ChannelOutput* output) { 86 constexpr U kIntId = static_cast<U>(kId); 87 static_assert(kIntId >= 0, "Channel ID cannot be negative"); 88 static_assert(kIntId <= std::numeric_limits<uint32_t>::max(), 89 "Channel ID must fit in a uint32"); 90 return Create<static_cast<uint32_t>(kIntId)>(output); 91 } 92 id()93 constexpr uint32_t id() const { return id_; } assigned()94 constexpr bool assigned() const { return id_ != kUnassignedChannelId; } 95 96 protected: Channel(uint32_t id,ChannelOutput * output)97 constexpr Channel(uint32_t id, ChannelOutput* output) 98 : id_(id), output_(output), client_(nullptr) { 99 PW_ASSERT(id != kUnassignedChannelId); 100 } 101 output()102 ChannelOutput& output() const { 103 PW_ASSERT(output_ != nullptr); 104 return *output_; 105 } 106 107 private: 108 friend class internal::BaseClientCall; 109 friend class Client; 110 client()111 constexpr Client* client() const { return client_; } set_client(Client * client)112 constexpr void set_client(Client* client) { client_ = client; } 113 114 uint32_t id_; 115 ChannelOutput* output_; 116 Client* client_; 117 }; 118 119 } // namespace pw::rpc 120