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
123 PW_DASSERT(dest.empty() || dest.data() != nullptr);
124 StatusWithSize result = DoRead(dest);
125
126 if (result.ok()) {
127 return dest.first(result.size());
128 }
129 return result.status();
130 }
132 Result<ByteSpan> Read(void* dest, size_t size_bytes) {
133 return Read(span(static_cast<std::byte*>(dest), size_bytes));
134 }
135
143 ByteSpan dest = buffer;
144 while (!dest.empty()) {
145 auto result = Read(dest);
146 if (!result.ok()) {
147 return result.status();
148 }
149 const size_t bytes_read = result->size();
150 PW_DASSERT(bytes_read != 0); // Should never happen, according to API.
151 dest = dest.subspan(bytes_read);
152 }
153 return buffer;
154 }
155
193 PW_DASSERT(data.empty() || data.data() != nullptr);
194 return DoWrite(data);
195 }
197 Status Write(const void* data, size_t size_bytes) {
198 return Write(span(static_cast<const std::byte*>(data), size_bytes));
199 }
201 Status Write(const std::byte b) { return Write(&b, 1); }
202
222 Status Seek(ptrdiff_t offset, Whence origin = kBeginning) {
223 return DoSeek(offset, origin);
224 }
225
232 size_t Tell() { return DoTell(); }
233
242 size_t ConservativeReadLimit() const {
243 return ConservativeLimit(LimitType::kRead);
244 }
245
254 size_t ConservativeWriteLimit() const {
255 return ConservativeLimit(LimitType::kWrite);
256 }
257
258 protected:
259 // Used to indicate the type of limit being queried in ConservativeLimit.
260 enum class LimitType : bool { kRead, kWrite };
261
262 private:
263 // The Stream class should not be extended directly, so its constructor is
264 // private. To implement a new Stream, extend one of its derived classes.
265 friend class Reader;
266 friend class RelativeSeekableReader;
267 friend class SeekableReader;
268 friend class NonSeekableReader;
269
270 friend class Writer;
271 friend class RelativeSeekableWriter;
272 friend class SeekableWriter;
273 friend class NonSeekableWriter;
274
275 friend class ReaderWriter;
276 friend class RelativeSeekableReaderWriter;
277 friend class SeekableReaderWriter;
278 friend class NonSeekableReaderWriter;
279
284 enum class Seekability : uint8_t {
286 kNone = 0,
287
291 kRelative = kCurrent,
292
294 kAbsolute = kBeginning | kCurrent | kEnd,
295 };
296
297 // These are the virtual methods that are implemented by derived classes. The
298 // public API functions call these virtual functions.
299
300 constexpr Stream(bool readable, bool writable, Seekability seekability)
301 : readable_(readable), writable_(writable), seekability_(seekability) {}
302
304 virtual StatusWithSize DoRead(ByteSpan destination) = 0;
305
307 virtual Status DoWrite(ConstByteSpan data) = 0;
308
310 virtual Status DoSeek(ptrdiff_t offset, Whence origin) = 0;
311
314 virtual size_t DoTell() { return kUnknownPosition; }
315
321 virtual size_t ConservativeLimit(LimitType limit_type) const {
322 if (limit_type == LimitType::kRead) {
323 return readable() ? kUnlimited : 0;
324 }
325 return writable() ? kUnlimited : 0;
326 }
327
328 bool readable_;
329 bool writable_;
330 Seekability seekability_;
331};
332
334
336
351class Reader : public Stream {
352 private:
353 friend class RelativeSeekableReader;
354 friend class NonSeekableReader;
355
356 constexpr Reader(Seekability seekability)
357 : Stream(true, false, seekability) {}
358
359 using Stream::Write;
360
361 Status DoWrite(ConstByteSpan) final { return Status::Unimplemented(); }
362};
363
380 protected:
381 constexpr RelativeSeekableReader()
382 : RelativeSeekableReader(Seekability::kRelative) {}
383
384 private:
385 friend class SeekableReader;
386
387 constexpr RelativeSeekableReader(Seekability seekability)
388 : Reader(seekability) {}
389};
390
401 protected:
402 constexpr SeekableReader() : RelativeSeekableReader(Seekability::kAbsolute) {}
403};
404
413class NonSeekableReader : public Reader {
414 protected:
415 constexpr NonSeekableReader() : Reader(Seekability::kNone) {}
416
417 private:
418 using Reader::Seek;
419
420 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
421};
422
424
426
440class Writer : public Stream {
441 private:
442 friend class RelativeSeekableWriter;
443 friend class NonSeekableWriter;
444
445 constexpr Writer(Seekability seekability)
446 : Stream(false, true, seekability) {}
447
448 using Stream::Read;
449
451 return StatusWithSize::Unimplemented();
452 }
453};
454
471 protected:
472 constexpr RelativeSeekableWriter()
473 : RelativeSeekableWriter(Seekability::kRelative) {}
474
475 private:
476 friend class SeekableWriter;
477
478 constexpr RelativeSeekableWriter(Seekability seekability)
479 : Writer(seekability) {}
480};
481
492 protected:
493 constexpr SeekableWriter() : RelativeSeekableWriter(Seekability::kAbsolute) {}
494};
495
504class NonSeekableWriter : public Writer {
505 protected:
506 constexpr NonSeekableWriter() : Writer(Seekability::kNone) {}
507
508 private:
509 using Writer::Seek;
510
511 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
512};
513
515
517
532class ReaderWriter : public Stream {
533 public:
534 // ReaderWriters may be used as Readers.
535 Reader& as_reader() { return internal::SiblingCast<Reader&, Stream>(*this); }
536 const Reader& as_reader() const {
537 return internal::SiblingCast<const Reader&, Stream>(*this);
538 }
539
540 operator Reader&() { return as_reader(); }
541 operator const Reader&() const { return as_reader(); }
542
543 // ReaderWriters may be used as Writers.
544 Writer& as_writer() { return internal::SiblingCast<Writer&, Stream>(*this); }
545 const Writer& as_writer() const {
546 return internal::SiblingCast<const Writer&, Stream>(*this);
547 }
548
549 operator Writer&() { return as_writer(); }
550 operator const Writer&() const { return as_writer(); }
551
552 private:
553 friend class RelativeSeekableReaderWriter;
554 friend class NonSeekableReaderWriter;
555
556 constexpr ReaderWriter(Seekability seekability)
557 : Stream(true, true, seekability) {}
558};
559
576 public:
577 // RelativeSeekableReaderWriters may be used as RelativeSeekableReaders or
578 // RelativeSeekableWriters.
579 operator RelativeSeekableReader&() {
580 return internal::SiblingCast<RelativeSeekableReader&, Stream>(*this);
581 }
582 operator const RelativeSeekableReader&() const {
583 return internal::SiblingCast<const RelativeSeekableReader&, Stream>(*this);
584 }
585 operator RelativeSeekableWriter&() {
586 return internal::SiblingCast<RelativeSeekableWriter&, Stream>(*this);
587 }
588 operator const RelativeSeekableWriter&() const {
589 return internal::SiblingCast<const RelativeSeekableWriter&, Stream>(*this);
590 }
591
592 protected:
594 : ReaderWriter(Seekability::kRelative) {}
595
596 private:
597 friend class SeekableReaderWriter;
598
599 constexpr RelativeSeekableReaderWriter(Seekability seekability)
600 : ReaderWriter(seekability) {}
601};
602
613 public:
614 // SeekableReaderWriters may be used as SeekableReaders.
615 SeekableReader& as_seekable_reader() {
616 return internal::SiblingCast<SeekableReader&, Stream>(*this);
617 }
618 const SeekableReader& as_seekable_reader() const {
619 return internal::SiblingCast<const SeekableReader&, Stream>(*this);
620 }
621
622 operator SeekableReader&() { return as_seekable_reader(); }
623 operator const SeekableReader&() const { return as_seekable_reader(); }
624
625 // SeekableReaderWriters may be used as SeekableWriters.
626 SeekableWriter& as_seekable_writer() {
627 return internal::SiblingCast<SeekableWriter&, Stream>(*this);
628 }
629 const SeekableWriter& as_seekable_writer() const {
630 return internal::SiblingCast<const SeekableWriter&, Stream>(*this);
631 }
632
633 operator SeekableWriter&() { return as_seekable_writer(); }
634 operator const SeekableWriter&() const { return as_seekable_writer(); }
635
636 protected:
637 constexpr SeekableReaderWriter()
638 : RelativeSeekableReaderWriter(Seekability::kAbsolute) {}
639};
640
651 public:
652 // NonSeekableReaderWriters may be used as either NonSeekableReaders or
653 // NonSeekableWriters. Note that NonSeekableReaderWriter& generally should not
654 // be used in APIs, which should accept ReaderWriter& instead.
655 operator NonSeekableReader&() {
656 return internal::SiblingCast<NonSeekableReader&, Stream>(*this);
657 }
658 operator const NonSeekableReader&() const {
659 return internal::SiblingCast<const NonSeekableReader&, Stream>(*this);
660 }
661 operator NonSeekableWriter&() {
662 return internal::SiblingCast<NonSeekableWriter&, Stream>(*this);
663 }
664 operator const NonSeekableWriter&() const {
665 return internal::SiblingCast<const NonSeekableWriter&, Stream>(*this);
666 }
667
668 protected:
669 constexpr NonSeekableReaderWriter() : ReaderWriter(Seekability::kNone) {}
670
671 private:
672 using ReaderWriter::Seek;
673
674 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
675};
676
678
679} // namespace pw::stream
Definition: poll.h:25
Definition: status.h:86
Definition: status_with_size.h:49
constexpr bool ok() const
True if status() == OkStatus().
Definition: status_with_size.h:152
constexpr size_t size() const
Definition: status_with_size.h:146
Definition: stream.h:413
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:420
Definition: stream.h:650
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:674
Definition: stream.h:504
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:511
Definition: stream.h:351
Status DoWrite(ConstByteSpan) final
Virtual Write() function implemented by derived classes.
Definition: stream.h:361
Definition: stream.h:532
Definition: stream.h:379
Definition: stream.h:470
Definition: stream.h:400
Definition: stream.h:612
Definition: stream.h:491
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:222
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:321
virtual Status DoSeek(ptrdiff_t offset, Whence origin)=0
Virtual Seek() function implemented by derived classes.
Status Write(ConstByteSpan data)
Definition: stream.h:192
constexpr bool readable() const
Definition: stream.h:75
size_t Tell()
Definition: stream.h:232
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:254
Result< ByteSpan > ReadExact(ByteSpan const buffer)
Definition: stream.h:142
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:132
size_t ConservativeReadLimit() const
Definition: stream.h:242
virtual size_t DoTell()
Definition: stream.h:314
Result< ByteSpan > Read(ByteSpan dest)
Definition: stream.h:122
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:201
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:197
Definition: stream.h:440
StatusWithSize DoRead(ByteSpan) final
Virtual Read() function implemented by derived classes.
Definition: stream.h:450