C/C++ API Reference
Loading...
Searching...
No Matches
channel.h
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// __ ___ ___ _ _ ___ _ _ ___
17// \ \ / /_\ | _ \ \| |_ _| \| |/ __|
18// \ \/\/ / _ \| / .` || || .` | (_ |
19// \_/\_/_/ \_\_|_\_|\_|___|_|\_|\___|
20// _____ _____ ___ ___ ___ __ __ ___ _ _ _____ _ _
21// | __\ \/ / _ \ __| _ \_ _| \/ | __| \| |_ _/_\ | |
22// | _| > <| _/ _|| /| || |\/| | _|| .` | | |/ _ \| |__
23// |___/_/\_\_| |___|_|_\___|_| |_|___|_|\_| |_/_/ \_\____|
24//
25// This module is in an early, experimental state. The APIs are in flux and may
26// change without notice. Please do not rely on it in production code, but feel
27// free to explore and share feedback with the Pigweed team!
28
29#include <cstddef>
30#include <cstdint>
31#include <limits>
32#include <utility>
33
34#include "pw_async2/dispatcher.h"
35#include "pw_async2/poll.h"
36#include "pw_bytes/span.h"
37#include "pw_channel/properties.h"
38#include "pw_multibuf/multibuf.h"
39#include "pw_result/result.h"
40#include "pw_status/status.h"
41
42namespace pw::channel {
43
45
54template <DataType kDataType, Property... kProperties>
55class Channel {
56 public:
58 [[nodiscard]] static constexpr DataType data_type() { return kDataType; }
59
61 [[nodiscard]] static constexpr bool reliable() {
62 return ((kProperties == Property::kReliable) || ...);
63 }
65 [[nodiscard]] static constexpr bool seekable() {
66 return ((kProperties == Property::kSeekable) || ...);
67 }
69 [[nodiscard]] static constexpr bool readable() {
70 return ((kProperties == Property::kReadable) || ...);
71 }
73 [[nodiscard]] static constexpr bool writable() {
74 return ((kProperties == Property::kWritable) || ...);
75 }
76
79 [[nodiscard]] constexpr bool is_read_open() const;
80
83 [[nodiscard]] constexpr bool is_write_open() const;
84
86 [[nodiscard]] constexpr bool is_read_or_write_open() const {
87 return is_read_open() || is_write_open();
88 }
89
96 async2::Context& cx, size_t min_bytes);
103
104 // Conversions
105
107 template <typename Sibling,
108 typename = internal::EnableIfConversionIsValid<Channel, Sibling>>
109 constexpr operator Sibling&() {
110 return as<Sibling>();
111 }
112 template <typename Sibling,
113 typename = internal::EnableIfConversionIsValid<Channel, Sibling>>
114 constexpr operator const Sibling&() const {
115 return as<Sibling>();
116 }
117
119 template <typename Sibling>
120 [[nodiscard]] Sibling& as() {
121 internal::CheckThatConversionIsValid<Channel, Sibling>();
122 return static_cast<Sibling&>(static_cast<AnyChannel&>(*this));
123 }
124 template <typename Sibling>
125 [[nodiscard]] const Sibling& as() const {
126 internal::CheckThatConversionIsValid<Channel, Sibling>();
127 return static_cast<const Sibling&>(static_cast<const AnyChannel&>(*this));
128 }
129
132 template <Property... kOtherChannelProperties>
133 [[nodiscard]] auto& as() {
134 return as<Channel<data_type(), kOtherChannelProperties...>>();
135 }
136 template <Property... kOtherChannelProperties>
137 [[nodiscard]] const auto& as() const {
138 return as<Channel<data_type(), kOtherChannelProperties...>>();
139 }
140
142 [[nodiscard]] Channel<DataType::kByte, kProperties...>&
144 static_assert(kDataType == DataType::kDatagram,
145 "IgnoreDatagramBoundaries() may only be called to use a "
146 "datagram channel to a byte channel");
147 return static_cast<Channel<DataType::kByte, kProperties...>&>(
148 static_cast<AnyChannel&>(*this));
149 }
150
151 [[nodiscard]] const Channel<DataType::kByte, kProperties...>&
153 static_assert(kDataType == DataType::kDatagram,
154 "IgnoreDatagramBoundaries() may only be called to use a "
155 "datagram channel to a byte channel");
156 return static_cast<const Channel<DataType::kByte, kProperties...>&>(
157 static_cast<const AnyChannel&>(*this));
158 }
159
160 private:
161 static_assert(internal::PropertiesAreValid<kProperties...>());
162
163 friend class AnyChannel;
164
165 explicit constexpr Channel() = default;
166};
167
183 : private Channel<DataType::kByte, kReadable>,
184 private Channel<DataType::kByte, kWritable>,
185 private Channel<DataType::kByte, kReadable, kWritable>,
186 private Channel<DataType::kByte, kReliable, kReadable>,
187 private Channel<DataType::kByte, kReliable, kWritable>,
188 private Channel<DataType::kByte, kReliable, kReadable, kWritable>,
189 private Channel<DataType::kDatagram, kReadable>,
190 private Channel<DataType::kDatagram, kWritable>,
191 private Channel<DataType::kDatagram, kReadable, kWritable>,
192 private Channel<DataType::kDatagram, kReliable, kReadable>,
193 private Channel<DataType::kDatagram, kReliable, kWritable>,
194 private Channel<DataType::kDatagram, kReliable, kReadable, kWritable> {
195 public:
196 virtual ~AnyChannel() = default;
197
198 // Returned by Position() if getting the position is not supported.
199 // TODO: b/323622630 - `Seek` and `Position` are not yet implemented.
200 // static constexpr size_t kUnknownPosition =
201 // std::numeric_limits<size_t>::max();
202
203 // Channel properties
204
206 [[nodiscard]] constexpr DataType data_type() const { return data_type_; }
207
209 [[nodiscard]] constexpr bool reliable() const {
210 return (properties_ & Property::kReliable) != 0;
211 }
212
214 [[nodiscard]] constexpr bool seekable() const {
215 return (properties_ & Property::kSeekable) != 0;
216 }
217
219 [[nodiscard]] constexpr bool readable() const {
220 return (properties_ & Property::kReadable) != 0;
221 }
222
224 [[nodiscard]] constexpr bool writable() const {
225 return (properties_ & Property::kWritable) != 0;
226 }
227
230 [[nodiscard]] constexpr bool is_read_open() const { return read_open_; }
231
234 [[nodiscard]] constexpr bool is_write_open() const { return write_open_; }
235
237 [[nodiscard]] constexpr bool is_read_or_write_open() const {
238 return read_open_ || write_open_;
239 }
240
241 // Read API
242
261 if (!is_read_open()) {
263 }
264 async2::PollResult<multibuf::MultiBuf> result = DoPendRead(cx);
265 if (result.IsReady() && result->status().IsFailedPrecondition()) {
266 set_read_closed();
267 }
268 return result;
269 }
270
271 // Write API
272
290 if (!is_write_open()) {
292 }
293 async2::Poll<Status> result = DoPendReadyToWrite(cx);
294 if (result.IsReady() && result->IsFailedPrecondition()) {
295 set_write_closed();
296 }
297 return result;
298 }
299
321 async2::Context& cx, size_t min_bytes) {
322 return DoPendAllocateWriteBuffer(cx, min_bytes);
323 }
324
348 if (!is_write_open()) {
350 }
351 Status status = DoStageWrite(std::move(data));
352 if (status.IsFailedPrecondition()) {
353 set_write_closed();
354 }
355 return status;
356 }
357
367 if (!is_write_open()) {
369 }
370 async2::Poll<Status> status = DoPendWrite(cx);
371 if (status.IsReady() && status->IsFailedPrecondition()) {
372 set_write_closed();
373 }
374 return status;
375 }
376
393 Status Seek(async2::Context& cx, ptrdiff_t position, Whence whence);
394
399 size_t Position() const;
400
410 if (!is_read_or_write_open()) {
412 }
413 auto result = DoPendClose(cx);
414 if (result.IsReady()) {
415 set_read_closed();
416 set_write_closed();
417 }
418 return result;
419 }
420
421 protected:
422 // Marks the channel as closed for reading, but does nothing else.
423 //
424 // PendClose() always marks the channel closed when DoPendClose() returns
425 // Ready(), regardless of the status.
426 void set_read_closed() { read_open_ = false; }
427
428 // Marks the channel as closed for writing, but does nothing else.
429 //
430 // PendClose() always marks the channel closed when DoPendClose() returns
431 // Ready(), regardless of the status.
432 void set_write_closed() { write_open_ = false; }
433
434 private:
435 template <DataType, Property...>
436 friend class Channel; // Allow static_casts to AnyChannel
437
438 template <DataType, Property...>
439 friend class internal::BaseChannelImpl; // Allow inheritance
440
441 // `AnyChannel` may only be constructed by deriving from `ChannelImpl`.
442 explicit constexpr AnyChannel(DataType type, uint8_t properties)
443 : data_type_(type),
444 properties_(properties),
445 read_open_(readable()),
446 write_open_(writable()) {}
447
448 // Virtual interface
449
450 // Read functions
451
452 virtual async2::PollResult<multibuf::MultiBuf> DoPendRead(
453 async2::Context& cx) = 0;
454
455 // Write functions
456
457 virtual async2::PollOptional<multibuf::MultiBuf> DoPendAllocateWriteBuffer(
458 async2::Context& cx, size_t min_bytes) = 0;
459
460 virtual pw::async2::Poll<Status> DoPendReadyToWrite(async2::Context& cx) = 0;
461
462 virtual Status DoStageWrite(multibuf::MultiBuf&& buffer) = 0;
463
464 virtual pw::async2::Poll<Status> DoPendWrite(async2::Context& cx) = 0;
465
466 // Seek functions
468
469 // virtual Status DoSeek(ptrdiff_t position, Whence whence) = 0;
470
471 // virtual size_t DoPosition() const = 0;
472
473 // Common functions
475
476 DataType data_type_;
477 uint8_t properties_;
478 bool read_open_;
479 bool write_open_;
480};
481
483template <Property... kProperties>
484using ByteChannel = Channel<DataType::kByte, kProperties...>;
485
487template <Property... kProperties>
488using DatagramChannel = Channel<DataType::kDatagram, kProperties...>;
489
496
503
510
518
519// Implementation extension classes.
520
530template <DataType kDataType, Property... kProperties>
532 static_assert(internal::PropertiesAreValid<kProperties...>());
533};
534
536template <Property... kProperties>
537using ByteChannelImpl = ChannelImpl<DataType::kByte, kProperties...>;
538
540template <Property... kProperties>
541using DatagramChannelImpl = ChannelImpl<DataType::kDatagram, kProperties...>;
542
549template <typename ChannelType>
551
553
554template <DataType kDataType, Property... kProperties>
555class Implement<Channel<kDataType, kProperties...>>
556 : public ChannelImpl<kDataType, kProperties...> {
557 protected:
558 explicit constexpr Implement() = default;
559};
560
561} // namespace pw::channel
562
563// Include specializations for supported Channel types.
564#include "pw_channel/internal/channel_specializations.h"
Definition: status.h:120
static constexpr Status FailedPrecondition()
Definition: status.h:243
constexpr bool IsFailedPrecondition() const
Definition: status.h:381
Definition: context.h:55
Definition: poll.h:60
Definition: channel.h:194
constexpr bool readable() const
Returns whether the channel implementation is readable.
Definition: channel.h:219
async2::Poll< pw::Status > PendClose(async2::Context &cx)
Definition: channel.h:409
async2::Poll< Status > PendWrite(async2::Context &cx)
Definition: channel.h:366
async2::Poll< Status > PendReadyToWrite(pw::async2::Context &cx)
Definition: channel.h:289
constexpr bool is_read_or_write_open() const
True if the channel is open for either reading or writing.
Definition: channel.h:237
async2::PollResult< multibuf::MultiBuf > PendRead(async2::Context &cx)
Definition: channel.h:260
Status Seek(async2::Context &cx, ptrdiff_t position, Whence whence)
constexpr bool reliable() const
Returns whether the channel implementation is reliable.
Definition: channel.h:209
constexpr bool writable() const
Returns whether the channel implementation is writable.
Definition: channel.h:224
size_t Position() const
constexpr bool is_read_open() const
Definition: channel.h:230
Status StageWrite(multibuf::MultiBuf &&data)
Definition: channel.h:347
async2::PollOptional< multibuf::MultiBuf > PendAllocateWriteBuffer(async2::Context &cx, size_t min_bytes)
Definition: channel.h:320
constexpr bool is_write_open() const
Definition: channel.h:234
constexpr bool seekable() const
Returns whether the channel implementation is seekable.
Definition: channel.h:214
virtual async2::Poll< Status > DoPendClose(async2::Context &cx)=0
TODO: b/323622630 - Seek and Position are not yet implemented.
constexpr DataType data_type() const
Returns the data type of the channel implementation.
Definition: channel.h:206
Definition: channel.h:55
async2::Poll< Status > PendWrite(async2::Context &cx)
constexpr bool is_read_open() const
async2::PollResult< multibuf::MultiBuf > PendRead(async2::Context &cx)
static constexpr bool seekable()
Returns whether the channel type is seekable.
Definition: channel.h:65
static constexpr bool readable()
Returns whether the channel type is readable.
Definition: channel.h:69
constexpr bool is_write_open() const
Sibling & as()
Returns a reference to this channel as another compatible channel type.
Definition: channel.h:120
static constexpr bool reliable()
Returns whether the channel type is reliable.
Definition: channel.h:61
auto & as()
Definition: channel.h:133
constexpr bool is_read_or_write_open() const
True if the channel is open for reading or writing.
Definition: channel.h:86
async2::Poll< Status > PendReadyToWrite(pw::async2::Context &cx)
async2::PollOptional< multibuf::MultiBuf > PendAllocateWriteBuffer(async2::Context &cx, size_t min_bytes)
Status StageWrite(multibuf::MultiBuf &&data)
async2::Poll< pw::Status > PendClose(async2::Context &cx)
Channel< DataType::kByte, kProperties... > & IgnoreDatagramBoundaries()
Definition: channel.h:143
static constexpr DataType data_type()
Returns the data type of this channel.
Definition: channel.h:58
static constexpr bool writable()
Returns whether the channel type is writable.
Definition: channel.h:73
Definition: channel.h:531
Definition: channel.h:550
Definition: multibuf_v1.h:248
constexpr bool IsReady() const noexcept
Returns whether or not this value is Ready.
Definition: poll.h:133