• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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