Pigweed
 
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
43class Stream {
44 public:
46 enum Whence : uint8_t {
49 kBeginning = 0b001,
50
56 kCurrent = 0b010,
57
60 kEnd = 0b100,
61 };
62
64 static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max();
65
67 static constexpr size_t kUnknownPosition = std::numeric_limits<size_t>::max();
68
69 virtual ~Stream() = default;
70
73 constexpr bool readable() const { return readable_; }
74
77 constexpr bool writable() const { return writable_; }
78
81 constexpr bool seekable() const { return seekability_ != Seekability::kNone; }
82
84 constexpr bool seekable(Whence origin) const {
85 return (static_cast<uint8_t>(seekability_) & origin) != 0u;
86 }
87
120 Result<ByteSpan> Read(ByteSpan dest) {
121 PW_DASSERT(dest.empty() || dest.data() != nullptr);
122 StatusWithSize result = DoRead(dest);
123
124 if (result.ok()) {
125 return dest.first(result.size());
126 }
127 return result.status();
128 }
130 Result<ByteSpan> Read(void* dest, size_t size_bytes) {
131 return Read(span(static_cast<std::byte*>(dest), size_bytes));
132 }
133
140 Result<ByteSpan> ReadExact(ByteSpan const buffer) {
141 ByteSpan dest = buffer;
142 while (!dest.empty()) {
143 auto result = Read(dest);
144 if (!result.ok()) {
145 return result.status();
146 }
147 const size_t bytes_read = result->size();
148 PW_DASSERT(bytes_read != 0); // Should never happen, according to API.
149 dest = dest.subspan(bytes_read);
150 }
151 return buffer;
152 }
153
190 Status Write(ConstByteSpan data) {
191 PW_DASSERT(data.empty() || data.data() != nullptr);
192 return DoWrite(data);
193 }
195 Status Write(const void* data, size_t size_bytes) {
196 return Write(span(static_cast<const std::byte*>(data), size_bytes));
197 }
199 Status Write(const std::byte b) { return Write(&b, 1); }
200
220 Status Seek(ptrdiff_t offset, Whence origin = kBeginning) {
221 return DoSeek(offset, origin);
222 }
223
230 size_t Tell() { return DoTell(); }
231
240 size_t ConservativeReadLimit() const {
241 return ConservativeLimit(LimitType::kRead);
242 }
243
252 size_t ConservativeWriteLimit() const {
253 return ConservativeLimit(LimitType::kWrite);
254 }
255
256 protected:
257 // Used to indicate the type of limit being queried in ConservativeLimit.
258 enum class LimitType : bool { kRead, kWrite };
259
260 private:
261 // The Stream class should not be extended directly, so its constructor is
262 // private. To implement a new Stream, extend one of its derived classes.
263 friend class Reader;
264 friend class RelativeSeekableReader;
265 friend class SeekableReader;
266 friend class NonSeekableReader;
267
268 friend class Writer;
269 friend class RelativeSeekableWriter;
270 friend class SeekableWriter;
271 friend class NonSeekableWriter;
272
273 friend class ReaderWriter;
274 friend class RelativeSeekableReaderWriter;
275 friend class SeekableReaderWriter;
276 friend class NonSeekableReaderWriter;
277
282 enum class Seekability : uint8_t {
284 kNone = 0,
285
289 kRelative = kCurrent,
290
292 kAbsolute = kBeginning | kCurrent | kEnd,
293 };
294
295 // These are the virtual methods that are implemented by derived classes. The
296 // public API functions call these virtual functions.
297
298 constexpr Stream(bool readable, bool writable, Seekability seekability)
299 : readable_(readable), writable_(writable), seekability_(seekability) {}
300
302 virtual StatusWithSize DoRead(ByteSpan destination) = 0;
303
305 virtual Status DoWrite(ConstByteSpan data) = 0;
306
308 virtual Status DoSeek(ptrdiff_t offset, Whence origin) = 0;
309
312 virtual size_t DoTell() { return kUnknownPosition; }
313
319 virtual size_t ConservativeLimit(LimitType limit_type) const {
320 if (limit_type == LimitType::kRead) {
321 return readable() ? kUnlimited : 0;
322 }
323 return writable() ? kUnlimited : 0;
324 }
325
326 bool readable_;
327 bool writable_;
328 Seekability seekability_;
329};
330
345class Reader : public Stream {
346 private:
347 friend class RelativeSeekableReader;
348 friend class NonSeekableReader;
349
350 constexpr Reader(Seekability seekability)
351 : Stream(true, false, seekability) {}
352
353 using Stream::Write;
354
355 Status DoWrite(ConstByteSpan) final { return Status::Unimplemented(); }
356};
357
374 protected:
375 constexpr RelativeSeekableReader()
376 : RelativeSeekableReader(Seekability::kRelative) {}
377
378 private:
379 friend class SeekableReader;
380
381 constexpr RelativeSeekableReader(Seekability seekability)
382 : Reader(seekability) {}
383};
384
395 protected:
396 constexpr SeekableReader() : RelativeSeekableReader(Seekability::kAbsolute) {}
397};
398
407class NonSeekableReader : public Reader {
408 protected:
409 constexpr NonSeekableReader() : Reader(Seekability::kNone) {}
410
411 private:
412 using Reader::Seek;
413
414 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
415};
416
430class Writer : public Stream {
431 private:
432 friend class RelativeSeekableWriter;
433 friend class NonSeekableWriter;
434
435 constexpr Writer(Seekability seekability)
436 : Stream(false, true, seekability) {}
437
438 using Stream::Read;
439
440 StatusWithSize DoRead(ByteSpan) final {
441 return StatusWithSize::Unimplemented();
442 }
443};
444
461 protected:
462 constexpr RelativeSeekableWriter()
463 : RelativeSeekableWriter(Seekability::kRelative) {}
464
465 private:
466 friend class SeekableWriter;
467
468 constexpr RelativeSeekableWriter(Seekability seekability)
469 : Writer(seekability) {}
470};
471
482 protected:
483 constexpr SeekableWriter() : RelativeSeekableWriter(Seekability::kAbsolute) {}
484};
485
494class NonSeekableWriter : public Writer {
495 protected:
496 constexpr NonSeekableWriter() : Writer(Seekability::kNone) {}
497
498 private:
499 using Writer::Seek;
500
501 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
502};
503
518class ReaderWriter : public Stream {
519 public:
520 // ReaderWriters may be used as Readers.
521 Reader& as_reader() { return internal::SiblingCast<Reader&, Stream>(*this); }
522 const Reader& as_reader() const {
523 return internal::SiblingCast<const Reader&, Stream>(*this);
524 }
525
526 operator Reader&() { return as_reader(); }
527 operator const Reader&() const { return as_reader(); }
528
529 // ReaderWriters may be used as Writers.
530 Writer& as_writer() { return internal::SiblingCast<Writer&, Stream>(*this); }
531 const Writer& as_writer() const {
532 return internal::SiblingCast<const Writer&, Stream>(*this);
533 }
534
535 operator Writer&() { return as_writer(); }
536 operator const Writer&() const { return as_writer(); }
537
538 private:
539 friend class RelativeSeekableReaderWriter;
540 friend class NonSeekableReaderWriter;
541
542 constexpr ReaderWriter(Seekability seekability)
543 : Stream(true, true, seekability) {}
544};
545
562 public:
563 // RelativeSeekableReaderWriters may be used as RelativeSeekableReaders or
564 // RelativeSeekableWriters.
565 operator RelativeSeekableReader&() {
566 return internal::SiblingCast<RelativeSeekableReader&, Stream>(*this);
567 }
568 operator const RelativeSeekableReader&() const {
569 return internal::SiblingCast<const RelativeSeekableReader&, Stream>(*this);
570 }
571 operator RelativeSeekableWriter&() {
572 return internal::SiblingCast<RelativeSeekableWriter&, Stream>(*this);
573 }
574 operator const RelativeSeekableWriter&() const {
575 return internal::SiblingCast<const RelativeSeekableWriter&, Stream>(*this);
576 }
577
578 protected:
580 : ReaderWriter(Seekability::kRelative) {}
581
582 private:
583 friend class SeekableReaderWriter;
584
585 constexpr RelativeSeekableReaderWriter(Seekability seekability)
586 : ReaderWriter(seekability) {}
587};
588
599 public:
600 // SeekableReaderWriters may be used as SeekableReaders.
601 SeekableReader& as_seekable_reader() {
602 return internal::SiblingCast<SeekableReader&, Stream>(*this);
603 }
604 const SeekableReader& as_seekable_reader() const {
605 return internal::SiblingCast<const SeekableReader&, Stream>(*this);
606 }
607
608 operator SeekableReader&() { return as_seekable_reader(); }
609 operator const SeekableReader&() const { return as_seekable_reader(); }
610
611 // SeekableReaderWriters may be used as SeekableWriters.
612 SeekableWriter& as_seekable_writer() {
613 return internal::SiblingCast<SeekableWriter&, Stream>(*this);
614 }
615 const SeekableWriter& as_seekable_writer() const {
616 return internal::SiblingCast<const SeekableWriter&, Stream>(*this);
617 }
618
619 operator SeekableWriter&() { return as_seekable_writer(); }
620 operator const SeekableWriter&() const { return as_seekable_writer(); }
621
622 protected:
623 constexpr SeekableReaderWriter()
624 : RelativeSeekableReaderWriter(Seekability::kAbsolute) {}
625};
626
637 public:
638 // NonSeekableReaderWriters may be used as either NonSeekableReaders or
639 // NonSeekableWriters. Note that NonSeekableReaderWriter& generally should not
640 // be used in APIs, which should accept ReaderWriter& instead.
641 operator NonSeekableReader&() {
642 return internal::SiblingCast<NonSeekableReader&, Stream>(*this);
643 }
644 operator const NonSeekableReader&() const {
645 return internal::SiblingCast<const NonSeekableReader&, Stream>(*this);
646 }
647 operator NonSeekableWriter&() {
648 return internal::SiblingCast<NonSeekableWriter&, Stream>(*this);
649 }
650 operator const NonSeekableWriter&() const {
651 return internal::SiblingCast<const NonSeekableWriter&, Stream>(*this);
652 }
653
654 protected:
655 constexpr NonSeekableReaderWriter() : ReaderWriter(Seekability::kNone) {}
656
657 private:
658 using ReaderWriter::Seek;
659
660 Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
661};
662
663} // namespace pw::stream
Definition: status.h:85
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:407
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:414
Definition: stream.h:636
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:660
Definition: stream.h:494
Status DoSeek(ptrdiff_t, Whence) final
Virtual Seek() function implemented by derived classes.
Definition: stream.h:501
Definition: stream.h:345
Status DoWrite(ConstByteSpan) final
Virtual Write() function implemented by derived classes.
Definition: stream.h:355
Definition: stream.h:518
Definition: stream.h:373
Definition: stream.h:460
Definition: stream.h:394
Definition: stream.h:598
Definition: stream.h:481
Definition: stream.h:43
virtual Status DoWrite(ConstByteSpan data)=0
Virtual Write() function implemented by derived classes.
Whence
Positions from which to seek.
Definition: stream.h:46
@ kCurrent
Definition: stream.h:56
@ kBeginning
Definition: stream.h:49
@ kEnd
Definition: stream.h:60
virtual StatusWithSize DoRead(ByteSpan destination)=0
Virtual Read() function implemented by derived classes.
Status Seek(ptrdiff_t offset, Whence origin=kBeginning)
Definition: stream.h:220
static constexpr size_t kUnlimited
Value returned from read/write limit if unlimited.
Definition: stream.h:64
constexpr bool seekable() const
Definition: stream.h:81
constexpr bool seekable(Whence origin) const
True if the stream supports seeking from the specified origin.
Definition: stream.h:84
virtual size_t ConservativeLimit(LimitType limit_type) const
Definition: stream.h:319
virtual Status DoSeek(ptrdiff_t offset, Whence origin)=0
Virtual Seek() function implemented by derived classes.
Status Write(ConstByteSpan data)
Definition: stream.h:190
constexpr bool readable() const
Definition: stream.h:73
size_t Tell()
Definition: stream.h:230
static constexpr size_t kUnknownPosition
Returned by Tell() if getting the position is not supported.
Definition: stream.h:67
size_t ConservativeWriteLimit() const
Definition: stream.h:252
Result< ByteSpan > ReadExact(ByteSpan const buffer)
Definition: stream.h:140
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:130
size_t ConservativeReadLimit() const
Definition: stream.h:240
virtual size_t DoTell()
Definition: stream.h:312
Result< ByteSpan > Read(ByteSpan dest)
Definition: stream.h:120
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:199
constexpr bool writable() const
Definition: stream.h:77
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:195
Definition: stream.h:430
StatusWithSize DoRead(ByteSpan) final
Virtual Read() function implemented by derived classes.
Definition: stream.h:440