xref: /aosp_15_r20/external/pigweed/pw_channel/public/pw_channel/internal/channel_specializations.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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_assert/assert.h"
17 #include "pw_channel/channel.h"
18 
19 namespace pw::channel {
20 
21 // Channel functions that must be implemented inline after AnyChannel.
22 
23 template <DataType kDataType, Property... kProperties>
is_read_open()24 constexpr bool Channel<kDataType, kProperties...>::is_read_open() const {
25   return readable() && static_cast<const AnyChannel&>(*this).is_read_open();
26 }
27 
28 template <DataType kDataType, Property... kProperties>
is_write_open()29 constexpr bool Channel<kDataType, kProperties...>::is_write_open() const {
30   return writable() && static_cast<const AnyChannel&>(*this).is_write_open();
31 }
32 
33 template <DataType kDataType, Property... kProperties>
34 async2::Poll<Result<multibuf::MultiBuf>>
PendRead(async2::Context & cx)35 Channel<kDataType, kProperties...>::PendRead(async2::Context& cx) {
36   static_assert(readable(), "PendRead may only be called on readable channels");
37   return static_cast<AnyChannel&>(*this).PendRead(cx);
38 }
39 
40 template <DataType kDataType, Property... kProperties>
PendReadyToWrite(pw::async2::Context & cx)41 async2::Poll<Status> Channel<kDataType, kProperties...>::PendReadyToWrite(
42     pw::async2::Context& cx) {
43   static_assert(writable(),
44                 "PendReadyToWrite may only be called on writable channels");
45   return static_cast<AnyChannel&>(*this).PendReadyToWrite(cx);
46 }
47 template <DataType kDataType, Property... kProperties>
48 async2::Poll<std::optional<multibuf::MultiBuf>>
PendAllocateWriteBuffer(async2::Context & cx,size_t min_bytes)49 Channel<kDataType, kProperties...>::PendAllocateWriteBuffer(async2::Context& cx,
50                                                             size_t min_bytes) {
51   static_assert(
52       writable(),
53       "PendAllocateWriteBuffer may only be called on writable channels");
54   return static_cast<AnyChannel&>(*this).PendAllocateWriteBuffer(cx, min_bytes);
55 }
56 template <DataType kDataType, Property... kProperties>
StageWrite(multibuf::MultiBuf && data)57 Status Channel<kDataType, kProperties...>::StageWrite(
58     multibuf::MultiBuf&& data) {
59   static_assert(writable(),
60                 "StageWrite may only be called on writable channels");
61   return static_cast<AnyChannel&>(*this).StageWrite(std::move(data));
62 }
63 template <DataType kDataType, Property... kProperties>
PendWrite(async2::Context & cx)64 async2::Poll<Status> Channel<kDataType, kProperties...>::PendWrite(
65     async2::Context& cx) {
66   static_assert(writable(),
67                 "PendWrite may only be called on writable channels");
68   return static_cast<AnyChannel&>(*this).PendWrite(cx);
69 }
70 
71 template <DataType kDataType, Property... kProperties>
PendClose(async2::Context & cx)72 async2::Poll<pw::Status> Channel<kDataType, kProperties...>::PendClose(
73     async2::Context& cx) {
74   return static_cast<AnyChannel&>(*this).PendClose(cx);
75 }
76 
77 namespace internal {
78 
79 template <DataType kDataType, Property... kProperties>
80 class BaseChannelImpl : public AnyChannel {
81  public:
82   using Channel = Channel<kDataType, kProperties...>;
83 
channel()84   Channel& channel() { return *this; }
channel()85   const Channel& channel() const { return *this; }
86 
87   using Channel::as;
88   using Channel::IgnoreDatagramBoundaries;
89 
90   // Use the Channel's version of the AnyChannel API, so unsupported methods are
91   // disabled.
92   using Channel::PendAllocateWriteBuffer;
93   using Channel::PendClose;
94   using Channel::PendRead;
95   using Channel::PendReadyToWrite;
96   using Channel::PendWrite;
97   using Channel::StageWrite;
98 
99  private:
100   friend class ChannelImpl<kDataType, kProperties...>;
101 
BaseChannelImpl()102   constexpr BaseChannelImpl()
103       : AnyChannel(kDataType, (static_cast<uint8_t>(kProperties) | ...)) {}
104 };
105 
106 }  // namespace internal
107 
108 // Defines a channel specialization with the specified properties. ChannelImpl
109 // is specialized for each supported combination of byte/datagram and read/write
110 // attribute. Invalid combinations fall back to the default implementation and
111 // fail a static_assert.
112 //
113 // Channel is specialized to implement unsupported operations in a standard way.
114 // That way, extending a channel only requires implementing supported functions.
115 #define _PW_CHANNEL_IMPL(type, ...)                               \
116   template <>                                                     \
117   class ChannelImpl<DataType::__VA_ARGS__>                        \
118       : public internal::BaseChannelImpl<DataType::__VA_ARGS__> { \
119    protected:                                                     \
120     explicit constexpr ChannelImpl() = default;                   \
121                                                                   \
122    private:                                                       \
123     _PW_CHANNEL_##type                                            \
124   }
125 
126 // Macros that stub out read/write if unsupported.
127 #define _PW_CHANNEL_READ_WRITE
128 
129 #define _PW_CHANNEL_WRITE_ONLY                                                 \
130   async2::Poll<Result<multibuf::MultiBuf>> DoPendRead(async2::Context&)        \
131       final {                                                                  \
132     return async2::Ready(Result<multibuf::MultiBuf>(Status::Unimplemented())); \
133   }
134 
135 #define _PW_CHANNEL_READ_ONLY                                                \
136   async2::Poll<Status> DoPendReadyToWrite(async2::Context&) final {          \
137     return Status::Unimplemented();                                          \
138   }                                                                          \
139   async2::Poll<std::optional<multibuf::MultiBuf>> DoPendAllocateWriteBuffer( \
140       async2::Context&, size_t) final {                                      \
141     PW_ASSERT(false); /* shouldn't be called on non-writeable channels */    \
142   }                                                                          \
143   Status DoStageWrite(multibuf::MultiBuf&&) final {                          \
144     return Status::Unimplemented();                                          \
145   }                                                                          \
146   async2::Poll<Status> DoPendWrite(async2::Context&) final {                 \
147     return async2::Ready(Status::Unimplemented());                           \
148   }
149 
150 // Generate specializations for the supported channel types.
151 _PW_CHANNEL_IMPL(READ_WRITE, kByte, kReliable, kReadable, kWritable);
152 _PW_CHANNEL_IMPL(READ_ONLY, kByte, kReliable, kReadable);
153 _PW_CHANNEL_IMPL(WRITE_ONLY, kByte, kReliable, kWritable);
154 
155 _PW_CHANNEL_IMPL(READ_WRITE, kByte, kReadable, kWritable);
156 _PW_CHANNEL_IMPL(READ_ONLY, kByte, kReadable);
157 _PW_CHANNEL_IMPL(WRITE_ONLY, kByte, kWritable);
158 
159 _PW_CHANNEL_IMPL(READ_WRITE, kDatagram, kReliable, kReadable, kWritable);
160 _PW_CHANNEL_IMPL(READ_ONLY, kDatagram, kReliable, kReadable);
161 _PW_CHANNEL_IMPL(WRITE_ONLY, kDatagram, kReliable, kWritable);
162 
163 _PW_CHANNEL_IMPL(READ_WRITE, kDatagram, kReadable, kWritable);
164 _PW_CHANNEL_IMPL(READ_ONLY, kDatagram, kReadable);
165 _PW_CHANNEL_IMPL(WRITE_ONLY, kDatagram, kWritable);
166 
167 #undef _PW_CHANNEL_IMPL
168 #undef _PW_CHANNEL_READ_WRITE
169 #undef _PW_CHANNEL_READ_ONLY
170 #undef _PW_CHANNEL_WRITE_ONLY
171 
172 }  // namespace pw::channel
173