C/C++ API Reference
Loading...
Searching...
No Matches
stream.h
1// Copyright 2021 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 <array>
17#include <cstddef>
18#include <cstdint>
19#include <limits>
20
21#include "pw_assert/assert.h"
22#include "pw_bytes/span.h"
23#include "pw_result/result.h"
24#include "pw_span/span.h"
25#include "pw_status/status.h"
26#include "pw_status/status_with_size.h"
27#include "pw_toolchain/internal/sibling_cast.h"
28
29namespace pw::stream {
30
32
45class Stream {
46 public:
48 enum Whence : uint8_t {
51 kBeginning = 0b001,
52
58 kCurrent = 0b010,
59
62 kEnd = 0b100,
63 };
64
66 static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max();
67
69 static constexpr size_t kUnknownPosition = std::numeric_limits<size_t>::max();
70
71 virtual ~Stream() = default;
72
75 constexpr bool readable() const { return readable_; }
76
79 constexpr bool writable() const { return writable_; }
80
83 constexpr bool seekable() const { return seekability_ != Seekability::kNone; }
84
86 constexpr bool seekable(Whence origin) const {
87 return (static_cast<uint8_t>(seekability_) & origin) != 0u;
88 }
89
114 PW_DASSERT(dest.empty() || dest.data() != nullptr);
115 StatusWithSize result = DoRead(dest);
116
117 if (result.ok()) {
118 return dest.first(result.size());
119 }
120 return result.status();
121 }
123 Result<ByteSpan> Read(void* dest, size_t size_bytes) {
124 return Read(span(static_cast<std::byte*>(dest), size_bytes));
125 }
126
134 ByteSpan dest = buffer;
135 while (!dest.empty()) {
136 auto result = Read(dest);
137 if (!result.ok()) {
138 return result.status();
139 }
140 const size_t bytes_read = result->size();
141 PW_DASSERT(bytes_read != 0); // Should never happen, according to API.
142 dest = dest.subspan(bytes_read);
143 }
144 return buffer;
145 }
146
175 PW_DASSERT(data.empty() || data.data() != nullptr);
176 return DoWrite(data);
177 }
179 Status Write(const void* data, size_t size_bytes) {
180 return Write(span(static_cast<const std::byte*>(data), size_bytes));
181 }
183 Status Write(const std::byte b) { return Write(&b, 1); }
184
197 Status Seek(ptrdiff_t offset, Whence origin = kBeginning) {
198 return DoSeek(offset, origin);
199 }
200
207 size_t Tell() { return DoTell(); }
208
217 size_t ConservativeReadLimit() const {
218 return ConservativeLimit(LimitType::kRead);
219 }
220
229 size_t ConservativeWriteLimit() const {
230 return ConservativeLimit(LimitType::kWrite);
231 }
232
233 protected:
234 // Used to indicate the type of limit being queried in ConservativeLimit.
235 enum class LimitType : bool { kRead, kWrite };
236
237 private:
238 // The Stream class should not be extended directly, so its constructor is
239 // private. To implement a new Stream, extend one of its derived classes.
240 friend class Reader;
241 friend class RelativeSeekableReader;
242 friend class SeekableReader;
243 friend class NonSeekableReader;
244
245 friend class Writer;
246 friend class RelativeSeekableWriter;
247 friend class SeekableWriter;
248 friend class NonSeekableWriter;
249
250 friend class ReaderWriter;
251 friend class RelativeSeekableReaderWriter;
252 friend class SeekableReaderWriter;
253 friend class NonSeekableReaderWriter;
254
259 enum class Seekability : uint8_t {
261 kNone = 0,
262
266 kRelative = kCurrent,
267
269 kAbsolute = kBeginning | kCurrent | kEnd,
270 };
271
272 // These are the virtual methods that are implemented by derived classes. The
273 // public API functions call these virtual functions.
274
275 constexpr Stream(bool readable, bool writable, Seekability seekability)
276 : readable_(readable), writable_(writable), seekability_(seekability) {}
277
279 virtual StatusWithSize DoRead(ByteSpan destination) = 0;
280
282 virtual Status DoWrite(ConstByteSpan data) = 0;
283
285 virtual Status DoSeek(ptrdiff_t offset, Whence origin) = 0;
286
289 virtual size_t DoTell() { return kUnknownPosition; }
290
296 virtual size_t ConservativeLimit(LimitType limit_type) const {
297 if (limit_type == LimitType::kRead) {
298 return readable() ? kUnlimited : 0;
299 }
300 return writable() ? kUnlimited : 0;
301 }
302
303 bool readable_;
304 bool writable_;
305 Seekability seekability_;
306};
307
309
311
326class Reader : public Stream {
327 private:
328 friend class RelativeSeekableReader;
329 friend class NonSeekableReader;
330
331 constexpr Reader(Seekability seekability)
332 : Stream(true, false, seekability) {}
333
334 using Stream::Write;
335
337};
338
355 protected:
356 constexpr RelativeSeekableReader()
357 : RelativeSeekableReader(Seekability::kRelative) {}
358
359 private:
360 friend class SeekableReader;
361
362 constexpr RelativeSeekableReader(Seekability seekability)
363 : Reader(seekability) {}
364};
365
376 protected:
377 constexpr SeekableReader() : RelativeSeekableReader(Seekability::kAbsolute) {}
378};
379
388class NonSeekableReader : public Reader {
389 protected:
390 constexpr NonSeekableReader() : Reader(Seekability::kNone) {}
391
392 private:
393 using Reader::Seek;
394
395 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
396};
397
399
401
415class Writer : public Stream {
416 private:
417 friend class RelativeSeekableWriter;
418 friend class NonSeekableWriter;
419
420 constexpr Writer(Seekability seekability)
421 : Stream(false, true, seekability) {}
422
423 using Stream::Read;
424
426 return StatusWithSize::Unimplemented();
427 }
428};
429
446 protected:
447 constexpr RelativeSeekableWriter()
448 : RelativeSeekableWriter(Seekability::kRelative) {}
449
450 private:
451 friend class SeekableWriter;
452
453 constexpr RelativeSeekableWriter(Seekability seekability)
454 : Writer(seekability) {}
455};
456
467 protected:
468 constexpr SeekableWriter() : RelativeSeekableWriter(Seekability::kAbsolute) {}
469};
470
479class NonSeekableWriter : public Writer {
480 protected:
481 constexpr NonSeekableWriter() : Writer(Seekability::kNone) {}
482
483 private:
484 using Writer::Seek;
485
486 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
487};
488
490
492
507class ReaderWriter : public Stream {
508 public:
509 // ReaderWriters may be used as Readers.
510 Reader& as_reader() { return internal::SiblingCast<Reader&, Stream>(*this); }
511 const Reader& as_reader() const {
512 return internal::SiblingCast<const Reader&, Stream>(*this);
513 }
514
515 operator Reader&() { return as_reader(); }
516 operator const Reader&() const { return as_reader(); }
517
518 // ReaderWriters may be used as Writers.
519 Writer& as_writer() { return internal::SiblingCast<Writer&, Stream>(*this); }
520 const Writer& as_writer() const {
521 return internal::SiblingCast<const Writer&, Stream>(*this);
522 }
523
524 operator Writer&() { return as_writer(); }
525 operator const Writer&() const { return as_writer(); }
526
527 private:
528 friend class RelativeSeekableReaderWriter;
529 friend class NonSeekableReaderWriter;
530
531 constexpr ReaderWriter(Seekability seekability)
532 : Stream(true, true, seekability) {}
533};
534
551 public:
552 // RelativeSeekableReaderWriters may be used as RelativeSeekableReaders or
553 // RelativeSeekableWriters.
554 operator RelativeSeekableReader&() {
555 return internal::SiblingCast<RelativeSeekableReader&, Stream>(*this);
556 }
557 operator const RelativeSeekableReader&() const {
558 return internal::SiblingCast<const RelativeSeekableReader&, Stream>(*this);
559 }
560 operator RelativeSeekableWriter&() {
561 return internal::SiblingCast<RelativeSeekableWriter&, Stream>(*this);
562 }
563 operator const RelativeSeekableWriter&() const {
564 return internal::SiblingCast<const RelativeSeekableWriter&, Stream>(*this);
565 }
566
567 protected:
569 : ReaderWriter(Seekability::kRelative) {}
570
571 private:
572 friend class SeekableReaderWriter;
573
574 constexpr RelativeSeekableReaderWriter(Seekability seekability)
575 : ReaderWriter(seekability) {}
576};
577
588 public:
589 // SeekableReaderWriters may be used as SeekableReaders.
590 SeekableReader& as_seekable_reader() {
591 return internal::SiblingCast<SeekableReader&, Stream>(*this);
592 }
593 const SeekableReader& as_seekable_reader() const {
594 return internal::SiblingCast<const SeekableReader&, Stream>(*this);
595 }
596
597 operator SeekableReader&() { return as_seekable_reader(); }
598 operator const SeekableReader&() const { return as_seekable_reader(); }
599
600 // SeekableReaderWriters may be used as SeekableWriters.
601 SeekableWriter& as_seekable_writer() {
602 return internal::SiblingCast<SeekableWriter&, Stream>(*this);
603 }
604 const SeekableWriter& as_seekable_writer() const {
605 return internal::SiblingCast<const SeekableWriter&, Stream>(*this);
606 }
607
608 operator SeekableWriter&() { return as_seekable_writer(); }
609 operator const SeekableWriter&() const { return as_seekable_writer(); }
610
611 protected:
612 constexpr SeekableReaderWriter()
613 : RelativeSeekableReaderWriter(Seekability::kAbsolute) {}
614};
615
626 public:
627 // NonSeekableReaderWriters may be used as either NonSeekableReaders or
628 // NonSeekableWriters. Note that NonSeekableReaderWriter& generally should not
629 // be used in APIs, which should accept ReaderWriter& instead.
630 operator NonSeekableReader&() {
631 return internal::SiblingCast<NonSeekableReader&, Stream>(*this);
632 }
633 operator const NonSeekableReader&() const {
634 return internal::SiblingCast<const NonSeekableReader&, Stream>(*this);
635 }
636 operator NonSeekableWriter&() {
637 return internal::SiblingCast<NonSeekableWriter&, Stream>(*this);
638 }
639 operator const NonSeekableWriter&() const {
640 return internal::SiblingCast<const NonSeekableWriter&, Stream>(*this);
641 }
642
643 protected:
644 constexpr NonSeekableReaderWriter() : ReaderWriter(Seekability::kNone) {}
645
646 private:
647 using ReaderWriter::Seek;
648
649 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
650};
651
653
654} // namespace pw::stream
Definition: result.h:143
Definition: status.h:120
static constexpr Status Unimplemented()
Definition: status.h:280
Definition: status_with_size.h:51
constexpr bool ok() const
True if status() == OkStatus().
Definition: status_with_size.h:154
constexpr size_t size() const
Definition: status_with_size.h:148
Definition: stream.h:388
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:395
Definition: stream.h:625
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:649
Definition: stream.h:479
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:486
Definition: stream.h:326
Status DoWrite(ConstByteSpan) final
Virtual Write() function implemented by derived classes.
Definition: stream.h:336
Definition: stream.h:507
Definition: stream.h:354
Definition: stream.h:445
Definition: stream.h:375
Definition: stream.h:587
Definition: stream.h:466
Definition: stream.h:45
virtual Status DoWrite(ConstByteSpan data)=0
Virtual Write() function implemented by derived classes.
Whence
Positions from which to seek.
Definition: stream.h:48
@ kCurrent
Definition: stream.h:58
@ kBeginning
Definition: stream.h:51
@ kEnd
Definition: stream.h:62
virtual StatusWithSize DoRead(ByteSpan destination)=0
Virtual Read() function implemented by derived classes.
Status Seek(ptrdiff_t offset, Whence origin=kBeginning)
Definition: stream.h:197
static constexpr size_t kUnlimited
Value returned from read/write limit if unlimited.
Definition: stream.h:66
constexpr bool seekable() const
Definition: stream.h:83
constexpr bool seekable(Whence origin) const
True if the stream supports seeking from the specified origin.
Definition: stream.h:86
virtual size_t ConservativeLimit(LimitType limit_type) const
Definition: stream.h:296
virtual Status DoSeek(ptrdiff_t offset, Whence origin)=0
Virtual Seek() function implemented by derived classes.
Status Write(ConstByteSpan data)
Definition: stream.h:174
constexpr bool readable() const
Definition: stream.h:75
size_t Tell()
Definition: stream.h:207
static constexpr size_t kUnknownPosition
Returned by Tell() if getting the position is not supported.
Definition: stream.h:69
size_t ConservativeWriteLimit() const
Definition: stream.h:229
Result< ByteSpan > ReadExact(ByteSpan const buffer)
Definition: stream.h:133
Result< ByteSpan > Read(void *dest, size_t size_bytes)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: stream.h:123
size_t ConservativeReadLimit() const
Definition: stream.h:217
virtual size_t DoTell()
Definition: stream.h:289
Result< ByteSpan > Read(ByteSpan dest)
Definition: stream.h:113
Status Write(const std::byte b)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: stream.h:183
constexpr bool writable() const
Definition: stream.h:79
Status Write(const void *data, size_t size_bytes)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: stream.h:179
Definition: stream.h:415
StatusWithSize DoRead(ByteSpan) final
Virtual Read() function implemented by derived classes.
Definition: stream.h:425