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
58template <DataType kDataType, Property... kProperties>
59class Channel {
60 public:
62 [[nodiscard]] static constexpr DataType data_type() { return kDataType; }
63
65 [[nodiscard]] static constexpr bool reliable() {
66 return ((kProperties == Property::kReliable) || ...);
67 }
69 [[nodiscard]] static constexpr bool seekable() {
70 return ((kProperties == Property::kSeekable) || ...);
71 }
73 [[nodiscard]] static constexpr bool readable() {
74 return ((kProperties == Property::kReadable) || ...);
75 }
77 [[nodiscard]] static constexpr bool writable() {
78 return ((kProperties == Property::kWritable) || ...);
79 }
80
83 [[nodiscard]] constexpr bool is_read_open() const;
84
87 [[nodiscard]] constexpr bool is_write_open() const;
88
90 [[nodiscard]] constexpr bool is_read_or_write_open() const {
91 return is_read_open() || is_write_open();
92 }
93
100 async2::Context& cx, size_t min_bytes);
107
108 // Conversions
109
111 template <typename Sibling,
112 typename = internal::EnableIfConversionIsValid<Channel, Sibling>>
113 constexpr operator Sibling&() {
114 return as<Sibling>();
115 }
116 template <typename Sibling,
117 typename = internal::EnableIfConversionIsValid<Channel, Sibling>>
118 constexpr operator const Sibling&() const {
119 return as<Sibling>();
120 }
121
123 template <typename Sibling>
124 [[nodiscard]] Sibling& as() {
125 internal::CheckThatConversionIsValid<Channel, Sibling>();
126 return static_cast<Sibling&>(static_cast<AnyChannel&>(*this));
127 }
128 template <typename Sibling>
129 [[nodiscard]] const Sibling& as() const {
130 internal::CheckThatConversionIsValid<Channel, Sibling>();
131 return static_cast<const Sibling&>(static_cast<const AnyChannel&>(*this));
132 }
133
136 template <Property... kOtherChannelProperties>
137 [[nodiscard]] auto& as() {
138 return as<Channel<data_type(), kOtherChannelProperties...>>();
139 }
140 template <Property... kOtherChannelProperties>
141 [[nodiscard]] const auto& as() const {
142 return as<Channel<data_type(), kOtherChannelProperties...>>();
143 }
144
146 [[nodiscard]] Channel<DataType::kByte, kProperties...>&
148 static_assert(kDataType == DataType::kDatagram,
149 "IgnoreDatagramBoundaries() may only be called to use a "
150 "datagram channel to a byte channel");
151 return static_cast<Channel<DataType::kByte, kProperties...>&>(
152 static_cast<AnyChannel&>(*this));
153 }
154
155 [[nodiscard]] const Channel<DataType::kByte, kProperties...>&
157 static_assert(kDataType == DataType::kDatagram,
158 "IgnoreDatagramBoundaries() may only be called to use a "
159 "datagram channel to a byte channel");
160 return static_cast<const Channel<DataType::kByte, kProperties...>&>(
161 static_cast<const AnyChannel&>(*this));
162 }
163
164 private:
165 static_assert(internal::PropertiesAreValid<kProperties...>());
166
167 friend class AnyChannel;
168
169 explicit constexpr Channel() = default;
170};
171
187 : private Channel<DataType::kByte, kReadable>,
188 private Channel<DataType::kByte, kWritable>,
189 private Channel<DataType::kByte, kReadable, kWritable>,
190 private Channel<DataType::kByte, kReliable, kReadable>,
191 private Channel<DataType::kByte, kReliable, kWritable>,
192 private Channel<DataType::kByte, kReliable, kReadable, kWritable>,
193 private Channel<DataType::kDatagram, kReadable>,
194 private Channel<DataType::kDatagram, kWritable>,
195 private Channel<DataType::kDatagram, kReadable, kWritable>,
196 private Channel<DataType::kDatagram, kReliable, kReadable>,
197 private Channel<DataType::kDatagram, kReliable, kWritable>,
198 private Channel<DataType::kDatagram, kReliable, kReadable, kWritable> {
199 public:
200 virtual ~AnyChannel() = default;
201
202 // Returned by Position() if getting the position is not supported.
203 // TODO: b/323622630 - `Seek` and `Position` are not yet implemented.
204 // static constexpr size_t kUnknownPosition =
205 // std::numeric_limits<size_t>::max();
206
207 // Channel properties
208
210 [[nodiscard]] constexpr DataType data_type() const { return data_type_; }
211
213 [[nodiscard]] constexpr bool reliable() const {
214 return (properties_ & Property::kReliable) != 0;
215 }
216
218 [[nodiscard]] constexpr bool seekable() const {
219 return (properties_ & Property::kSeekable) != 0;
220 }
221
223 [[nodiscard]] constexpr bool readable() const {
224 return (properties_ & Property::kReadable) != 0;
225 }
226
228 [[nodiscard]] constexpr bool writable() const {
229 return (properties_ & Property::kWritable) != 0;
230 }
231
234 [[nodiscard]] constexpr bool is_read_open() const { return read_open_; }
235
238 [[nodiscard]] constexpr bool is_write_open() const { return write_open_; }
239
241 [[nodiscard]] constexpr bool is_read_or_write_open() const {
242 return read_open_ || write_open_;
243 }
244
245 // Read API
246
265 if (!is_read_open()) {
267 }
268 async2::PollResult<multibuf::MultiBuf> result = DoPendRead(cx);
269 if (result.IsReady() && result->status().IsFailedPrecondition()) {
270 set_read_closed();
271 }
272 return result;
273 }
274
275 // Write API
276
294 if (!is_write_open()) {
296 }
297 async2::Poll<Status> result = DoPendReadyToWrite(cx);
298 if (result.IsReady() && result->IsFailedPrecondition()) {
299 set_write_closed();
300 }
301 return result;
302 }
303
325 async2::Context& cx, size_t min_bytes) {
326 return DoPendAllocateWriteBuffer(cx, min_bytes);
327 }
328
352 if (!is_write_open()) {
354 }
355 Status status = DoStageWrite(std::move(data));
356 if (status.IsFailedPrecondition()) {
357 set_write_closed();
358 }
359 return status;
360 }
361
371 if (!is_write_open()) {
373 }
374 async2::Poll<Status> status = DoPendWrite(cx);
375 if (status.IsReady() && status->IsFailedPrecondition()) {
376 set_write_closed();
377 }
378 return status;
379 }
380
397 Status Seek(async2::Context& cx, ptrdiff_t position, Whence whence);
398
403 size_t Position() const;
404
414 if (!is_read_or_write_open()) {
416 }
417 auto result = DoPendClose(cx);
418 if (result.IsReady()) {
419 set_read_closed();
420 set_write_closed();
421 }
422 return result;
423 }
424
425 protected:
426 // Marks the channel as closed for reading, but does nothing else.
427 //
428 // PendClose() always marks the channel closed when DoPendClose() returns
429 // Ready(), regardless of the status.
430 void set_read_closed() { read_open_ = false; }
431
432 // Marks the channel as closed for writing, but does nothing else.
433 //
434 // PendClose() always marks the channel closed when DoPendClose() returns
435 // Ready(), regardless of the status.
436 void set_write_closed() { write_open_ = false; }
437
438 private:
439 template <DataType, Property...>
440 friend class Channel; // Allow static_casts to AnyChannel
441
442 template <DataType, Property...>
443 friend class internal::BaseChannelImpl; // Allow inheritance
444
445 // `AnyChannel` may only be constructed by deriving from `ChannelImpl`.
446 explicit constexpr AnyChannel(DataType type, uint8_t properties)
447 : data_type_(type),
448 properties_(properties),
449 read_open_(readable()),
450 write_open_(writable()) {}
451
452 // Virtual interface
453
454 // Read functions
455
456 virtual async2::PollResult<multibuf::MultiBuf> DoPendRead(
457 async2::Context& cx) = 0;
458
459 // Write functions
460
461 virtual async2::PollOptional<multibuf::MultiBuf> DoPendAllocateWriteBuffer(
462 async2::Context& cx, size_t min_bytes) = 0;
463
464 virtual pw::async2::Poll<Status> DoPendReadyToWrite(async2::Context& cx) = 0;
465
466 virtual Status DoStageWrite(multibuf::MultiBuf&& buffer) = 0;
467
468 virtual pw::async2::Poll<Status> DoPendWrite(async2::Context& cx) = 0;
469
470 // Seek functions
472
473 // virtual Status DoSeek(ptrdiff_t position, Whence whence) = 0;
474
475 // virtual size_t DoPosition() const = 0;
476
477 // Common functions
479
480 DataType data_type_;
481 uint8_t properties_;
482 bool read_open_;
483 bool write_open_;
484};
485
487template <Property... kProperties>
488using ByteChannel = Channel<DataType::kByte, kProperties...>;
489
491template <Property... kProperties>
492using DatagramChannel = Channel<DataType::kDatagram, kProperties...>;
493
500
507
514
522
523// Implementation extension classes.
524
534template <DataType kDataType, Property... kProperties>
536 static_assert(internal::PropertiesAreValid<kProperties...>());
537};
538
540template <Property... kProperties>
541using ByteChannelImpl = ChannelImpl<DataType::kByte, kProperties...>;
542
544template <Property... kProperties>
545using DatagramChannelImpl = ChannelImpl<DataType::kDatagram, kProperties...>;
546
553template <typename ChannelType>
555
557
558template <DataType kDataType, Property... kProperties>
559class Implement<Channel<kDataType, kProperties...>>
560 : public ChannelImpl<kDataType, kProperties...> {
561 protected:
562 explicit constexpr Implement() = default;
563};
564
565} // namespace pw::channel
566
567// Include specializations for supported Channel types.
568#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:54
Definition: poll.h:60
Definition: channel.h:198
constexpr bool readable() const
Returns whether the channel implementation is readable.
Definition: channel.h:223
async2::Poll< pw::Status > PendClose(async2::Context &cx)
Definition: channel.h:413
async2::Poll< Status > PendWrite(async2::Context &cx)
Definition: channel.h:370
async2::Poll< Status > PendReadyToWrite(pw::async2::Context &cx)
Definition: channel.h:293
constexpr bool is_read_or_write_open() const
True if the channel is open for either reading or writing.
Definition: channel.h:241
async2::PollResult< multibuf::MultiBuf > PendRead(async2::Context &cx)
Definition: channel.h:264
Status Seek(async2::Context &cx, ptrdiff_t position, Whence whence)
constexpr bool reliable() const
Returns whether the channel implementation is reliable.
Definition: channel.h:213
constexpr bool writable() const
Returns whether the channel implementation is writable.
Definition: channel.h:228
size_t Position() const
constexpr bool is_read_open() const
Definition: channel.h:234
Status StageWrite(multibuf::MultiBuf &&data)
Definition: channel.h:351
async2::PollOptional< multibuf::MultiBuf > PendAllocateWriteBuffer(async2::Context &cx, size_t min_bytes)
Definition: channel.h:324
constexpr bool is_write_open() const
Definition: channel.h:238
constexpr bool seekable() const
Returns whether the channel implementation is seekable.
Definition: channel.h:218
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:210
Definition: channel.h:59
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:69
static constexpr bool readable()
Returns whether the channel type is readable.
Definition: channel.h:73
constexpr bool is_write_open() const
Sibling & as()
Returns a reference to this channel as another compatible channel type.
Definition: channel.h:124
static constexpr bool reliable()
Returns whether the channel type is reliable.
Definition: channel.h:65
auto & as()
Definition: channel.h:137
constexpr bool is_read_or_write_open() const
True if the channel is open for reading or writing.
Definition: channel.h:90
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:147
static constexpr DataType data_type()
Returns the data type of this channel.
Definition: channel.h:62
static constexpr bool writable()
Returns whether the channel type is writable.
Definition: channel.h:77
Definition: channel.h:535
Definition: channel.h:554
Definition: multibuf_v1.h:248
constexpr bool IsReady() const noexcept
Returns whether or not this value is Ready.
Definition: poll.h:133
Property
Basic properties of a MultiBuf.
Definition: properties.h:25