• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 namespace pw::stream {
30 
31 /// A generic stream that may support reading, writing, and seeking, but makes
32 /// no guarantees about whether any operations are supported. Unsupported
33 /// functions return Status::Unimplemented() Stream serves as the base for the
34 /// Reader, Writer, and ReaderWriter interfaces.
35 ///
36 /// Stream cannot be extended directly. Instead, work with one of the derived
37 /// classes that explicitly supports the required functionality. Stream should
38 /// almost never be used in APIs; accept a derived class with the required
39 /// capabilities instead.
40 ///
41 /// All Stream methods are blocking. They return when the requested operation
42 /// completes.
43 class Stream {
44  public:
45   /// Positions from which to seek.
46   enum Whence : uint8_t {
47     /// Seek from the beginning of the stream. The offset is a direct offset
48     /// into the data.
49     kBeginning = 0b001,
50 
51     /// Seek from the current position in the stream. The offset is added to the
52     /// current position. Use a negative offset to seek backwards.
53     ///
54     /// Implementations may only support seeking within a limited range from the
55     /// current position.
56     kCurrent = 0b010,
57 
58     /// Seek from the end of the stream. The offset is added to the end
59     /// position. Use a negative offset to seek backwards from the end.
60     kEnd = 0b100,
61   };
62 
63   /// Value returned from read/write limit if unlimited.
64   static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max();
65 
66   /// Returned by Tell() if getting the position is not supported.
67   static constexpr size_t kUnknownPosition = std::numeric_limits<size_t>::max();
68 
69   virtual ~Stream() = default;
70 
71   /// @retval True If reading is supported.
72   /// @retval False If Read() returns UNIMPLEMENTED.
readable()73   constexpr bool readable() const { return readable_; }
74 
75   /// @retval True If writing is supported.
76   /// @retval False If Write() returns UNIMPLEMENTED.
writable()77   constexpr bool writable() const { return writable_; }
78 
79   /// @retval True If the stream supports seeking.
80   /// @retval False If the stream does not supports seeking.
seekable()81   constexpr bool seekable() const { return seekability_ != Seekability::kNone; }
82 
83   /// True if the stream supports seeking from the specified origin.
seekable(Whence origin)84   constexpr bool seekable(Whence origin) const {
85     return (static_cast<uint8_t>(seekability_) & origin) != 0u;
86   }
87 
88   /// Reads data from the stream into the provided buffer, if supported. As many
89   /// bytes as are available up to the buffer size are copied into the buffer.
90   /// Remaining bytes may by read in subsequent calls. If any number of bytes
91   /// are read returns OK with a span of the bytes read.
92   ///
93   /// If the reader has been exhausted and is and can no longer read additional
94   /// bytes it will return `OUT_OF_RANGE`. This is similar to end-of-file (EOF).
95   /// Read will only return `OUT_OF_RANGE` if ConservativeReadLimit() is and
96   /// will remain zero. A Read operation that is successful and also exhausts
97   /// the reader returns OK, with all following calls returning `OUT_OF_RANGE`.
98   ///
99   /// Derived classes should NOT try to override these public read methods.
100   /// Instead, provide an implementation by overriding DoRead().
101   ///
102   /// @returns @rst
103   ///
104   /// .. pw-status-codes::
105   ///
106   ///    OK: Between 1 and ``dest.size_bytes()`` were successfully
107   ///    read. Returns the span of read bytes.
108   ///
109   ///    UNIMPLEMENTED: This stream does not support reading.
110   ///
111   ///    FAILED_PRECONDITION: The Reader is not in state to read data.
112   ///
113   ///    RESOURCE_EXHAUSTED: Unable to read any bytes at this time. No
114   ///    bytes read. Try again once bytes become available.
115   ///
116   ///    OUT_OF_RANGE: Reader has been exhausted, similar to EOF. No bytes
117   ///    were read, no more will be read.
118   ///
119   /// @endrst
Read(ByteSpan dest)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   }
129   /// @overload
Read(void * dest,size_t size_bytes)130   Result<ByteSpan> Read(void* dest, size_t size_bytes) {
131     return Read(span(static_cast<std::byte*>(dest), size_bytes));
132   }
133 
134   /// Writes data to this stream. Data is not guaranteed to be fully written out
135   /// to final resting place on Write return.
136   ///
137   /// If the writer is unable to fully accept the input data size it will abort
138   /// the write and return `RESOURCE_EXHAUSTED`.
139   ///
140   /// If the writer has been exhausted and is and can no longer accept
141   /// additional bytes it will return `OUT_OF_RANGE`. This is similar to
142   /// end-of-file (EOF).  Write will only return `OUT_OF_RANGE` if
143   /// ConservativeWriteLimit() is and will remain zero. A Write operation that
144   /// is successful and also exhausts the writer returns OK, with all following
145   /// calls returning `OUT_OF_RANGE`. When ConservativeWriteLimit() is greater
146   /// than zero, a Write that is a number of bytes beyond what will exhaust the
147   /// Write will abort and return `RESOURCE_EXHAUSTED` rather than OUT_OF_RANGE
148   /// because the writer is still able to write bytes.
149   ///
150   /// Derived classes should NOT try to override the public Write methods.
151   /// Instead, provide an implementation by overriding DoWrite().
152   ///
153   /// @returns @rst
154   ///
155   /// .. pw-status-codes::
156   ///
157   ///    OK: Data was successfully accepted by the stream.
158   ///
159   ///    UNIMPLEMENTED: This stream does not support writing.
160   ///
161   ///    FAILED_PRECONDITION: The writer is not in a state to accept data.
162   ///
163   ///    RESOURCE_EXHAUSTED: The writer was unable to write all of requested
164   ///    data at this time. No data was written.
165   ///
166   ///    OUT_OF_RANGE: The Writer has been exhausted, similar to EOF. No
167   ///    data was written; no more will be written.
168   ///
169   /// @endrst
Write(ConstByteSpan data)170   Status Write(ConstByteSpan data) {
171     PW_DASSERT(data.empty() || data.data() != nullptr);
172     return DoWrite(data);
173   }
174   /// @overload
Write(const void * data,size_t size_bytes)175   Status Write(const void* data, size_t size_bytes) {
176     return Write(span(static_cast<const std::byte*>(data), size_bytes));
177   }
178   /// @overload
Write(const std::byte b)179   Status Write(const std::byte b) { return Write(&b, 1); }
180 
181   /// Changes the current position in the stream for both reading and writing,
182   /// if supported.
183   ///
184   /// Seeking to a negative offset is invalid. The behavior when seeking beyond
185   /// the end of a stream is determined by the implementation. The
186   /// implementation could fail with OUT_OF_RANGE or append bytes to the stream.
187   ///
188   /// @returns @rst
189   ///
190   /// .. pw-status-codes::
191   ///
192   ///    OK: Successfully updated the position.
193   ///
194   ///    UNIMPLEMENTED: Seeking is not supported for this stream.
195   ///
196   ///    OUT_OF_RANGE: Attempted to seek beyond the bounds of the
197   ///    stream. The position is unchanged.
198   ///
199   /// @endrst
200   Status Seek(ptrdiff_t offset, Whence origin = kBeginning) {
201     return DoSeek(offset, origin);
202   }
203 
204   /// Returns the current position in the stream, if supported. The position is
205   /// the offset from the beginning of the stream. Returns
206   /// Stream::kUnknownPosition (`size_t(-1)`) if the position is unknown.
207   ///
208   /// Streams that support seeking from the beginning always support Tell().
209   /// Other streams may or may not support Tell().
Tell()210   size_t Tell() { return DoTell(); }
211 
212   /// Liklely (not guaranteed) minimum bytes available to read at this time.
213   /// This number is advisory and not guaranteed to read full number of
214   /// requested bytes or without a `RESOURCE_EXHAUSTED` or `OUT_OF_RANGE`. As
215   /// Reader processes/handles/receives enqueued data or other contexts read
216   /// data this number can go up or down for some Readers.
217   ///
218   /// @retval zero if, in the current state, Read() would not return OkStatus().
219   /// @retval kUnlimited if the implementation imposes no limits on read sizes.
ConservativeReadLimit()220   size_t ConservativeReadLimit() const {
221     return ConservativeLimit(LimitType::kRead);
222   }
223 
224   /// Likely (not guaranteed) minimum bytes available to write at this time.
225   /// This number is advisory and not guaranteed to write without a
226   /// `RESOURCE_EXHAUSTED` or `OUT_OF_RANGE`. As Writer processes/handles
227   /// enqueued of other contexts write data this number can go up or down for
228   /// some Writers.  Returns zero if, in the current state, Write() would not
229   /// return OkStatus().
230   ///
231   /// Returns kUnlimited if the implementation has no limits on write sizes.
ConservativeWriteLimit()232   size_t ConservativeWriteLimit() const {
233     return ConservativeLimit(LimitType::kWrite);
234   }
235 
236  protected:
237   // Used to indicate the type of limit being queried in ConservativeLimit.
238   enum class LimitType : bool { kRead, kWrite };
239 
240  private:
241   // The Stream class should not be extended directly, so its constructor is
242   // private. To implement a new Stream, extend one of its derived classes.
243   friend class Reader;
244   friend class RelativeSeekableReader;
245   friend class SeekableReader;
246   friend class NonSeekableReader;
247 
248   friend class Writer;
249   friend class RelativeSeekableWriter;
250   friend class SeekableWriter;
251   friend class NonSeekableWriter;
252 
253   friend class ReaderWriter;
254   friend class RelativeSeekableReaderWriter;
255   friend class SeekableReaderWriter;
256   friend class NonSeekableReaderWriter;
257 
258   /// Seekability expresses the origins from which the stream always supports
259   /// seeking. Seeking from other origins may work, but is not guaranteed.
260   ///
261   /// Seekability is implemented as a bitfield of Whence values.
262   enum class Seekability : uint8_t {
263     /// No type of seeking is supported.
264     kNone = 0,
265 
266     /// Seeking from the current position is supported, but the range may be
267     /// limited. For example, a buffered stream might support seeking within the
268     /// buffered data, but not before or after.
269     kRelative = kCurrent,
270 
271     /// The stream supports random access anywhere within the stream.
272     kAbsolute = kBeginning | kCurrent | kEnd,
273   };
274 
275   // These are the virtual methods that are implemented by derived classes. The
276   // public API functions call these virtual functions.
277 
Stream(bool readable,bool writable,Seekability seekability)278   constexpr Stream(bool readable, bool writable, Seekability seekability)
279       : readable_(readable), writable_(writable), seekability_(seekability) {}
280 
281   /// Virtual Read() function implemented by derived classes.
282   virtual StatusWithSize DoRead(ByteSpan destination) = 0;
283 
284   /// Virtual Write() function implemented by derived classes.
285   virtual Status DoWrite(ConstByteSpan data) = 0;
286 
287   /// Virtual Seek() function implemented by derived classes.
288   virtual Status DoSeek(ptrdiff_t offset, Whence origin) = 0;
289 
290   /// Virtual Tell() function optionally implemented by derived classes.
291   /// The default implementation always returns kUnknownPosition.
DoTell()292   virtual size_t DoTell() { return kUnknownPosition; }
293 
294   /// Virtual function optionally implemented by derived classes that is used
295   /// for ConservativeReadLimit() and ConservativeWriteLimit().
296   ///
297   /// The default implementation returns kUnlimited or ``0`` depending on
298   /// whether the stream is readable/writable.
ConservativeLimit(LimitType limit_type)299   virtual size_t ConservativeLimit(LimitType limit_type) const {
300     if (limit_type == LimitType::kRead) {
301       return readable() ? kUnlimited : 0;
302     }
303     return writable() ? kUnlimited : 0;
304   }
305 
306   bool readable_;
307   bool writable_;
308   Seekability seekability_;
309 };
310 
311 /// A Stream that supports reading but not writing. The Write() method is
312 /// hidden.
313 ///
314 /// Use in APIs when:
315 ///   * Must read from, but not write to, a stream.
316 ///   * May or may not need seeking. Use a SeekableReader& if seeking is
317 ///     required.
318 ///
319 /// Inherit from when:
320 ///   * Reader cannot be extended directly. Instead, extend SeekableReader,
321 ///     NonSeekableReader, or (rarely) RelativeSeekableReader, as appropriate.
322 ///
323 /// A Reader may or may not support seeking. Check seekable() or try calling
324 /// Seek() to determine if the stream is seekable.
325 class Reader : public Stream {
326  private:
327   friend class RelativeSeekableReader;
328   friend class NonSeekableReader;
329 
Reader(Seekability seekability)330   constexpr Reader(Seekability seekability)
331       : Stream(true, false, seekability) {}
332 
333   using Stream::Write;
334 
DoWrite(ConstByteSpan)335   Status DoWrite(ConstByteSpan) final { return Status::Unimplemented(); }
336 };
337 
338 /// A Reader that supports at least relative seeking within some range of the
339 /// current position. Seeking beyond that or from other origins may or may not
340 /// be supported. The extent to which seeking is possible is NOT exposed by this
341 /// API.
342 ///
343 /// Use in APIs when:
344 ///   * Relative seeking is required. Usage in APIs should be rare; generally
345 ///     Reader should be used instead.
346 ///
347 /// Inherit from when:
348 ///   * Implementing a Reader that can only support seeking near the current
349 ///     position.
350 ///
351 /// A buffered Reader that only supports seeking within its buffer is a good
352 /// example of a RelativeSeekableReader.
353 class RelativeSeekableReader : public Reader {
354  protected:
RelativeSeekableReader()355   constexpr RelativeSeekableReader()
356       : RelativeSeekableReader(Seekability::kRelative) {}
357 
358  private:
359   friend class SeekableReader;
360 
RelativeSeekableReader(Seekability seekability)361   constexpr RelativeSeekableReader(Seekability seekability)
362       : Reader(seekability) {}
363 };
364 
365 /// A Reader that fully supports seeking.
366 ///
367 /// Use in APIs when:
368 ///   * Absolute seeking is required. Use Reader& if seeking is not required or
369 ///     seek failures can be handled gracefully.
370 ///
371 /// Inherit from when:
372 ///   * Implementing a reader that supports absolute seeking.
373 ///
374 class SeekableReader : public RelativeSeekableReader {
375  protected:
SeekableReader()376   constexpr SeekableReader() : RelativeSeekableReader(Seekability::kAbsolute) {}
377 };
378 
379 /// A Reader that does not support seeking. The Seek() method is hidden.
380 ///
381 /// Use in APIs when:
382 ///   * Do NOT use in APIs! If seeking is not required, use Reader& instead.
383 ///
384 /// Inherit from when:
385 ///   * Implementing a Reader that does not support seeking.
386 ///
387 class NonSeekableReader : public Reader {
388  protected:
NonSeekableReader()389   constexpr NonSeekableReader() : Reader(Seekability::kNone) {}
390 
391  private:
392   using Reader::Seek;
393 
DoSeek(ptrdiff_t,Whence)394   Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
395 };
396 
397 /// A Stream that supports writing but not reading. The Read() method is hidden.
398 ///
399 /// Use in APIs when:
400 ///   * Must write to, but not read from, a stream.
401 ///   * May or may not need seeking. Use a SeekableWriter& if seeking is
402 ///     required.
403 ///
404 /// Inherit from when:
405 ///   * Writer cannot be extended directly. Instead, extend SeekableWriter,
406 ///     NonSeekableWriter, or (rarely) RelativeSeekableWriter, as appropriate.
407 ///
408 /// A Writer may or may not support seeking. Check seekable() or try calling
409 /// Seek() to determine if the stream is seekable.
410 class Writer : public Stream {
411  private:
412   friend class RelativeSeekableWriter;
413   friend class NonSeekableWriter;
414 
Writer(Seekability seekability)415   constexpr Writer(Seekability seekability)
416       : Stream(false, true, seekability) {}
417 
418   using Stream::Read;
419 
DoRead(ByteSpan)420   StatusWithSize DoRead(ByteSpan) final {
421     return StatusWithSize::Unimplemented();
422   }
423 };
424 
425 /// A Writer that supports at least relative seeking within some range of the
426 /// current position. Seeking beyond that or from other origins may or may not
427 /// be supported. The extent to which seeking is possible is NOT exposed by this
428 /// API.
429 ///
430 /// Use in APIs when:
431 ///   * Relative seeking is required. Usage in APIs should be rare; generally
432 ///     Writer should be used instead.
433 ///
434 /// Inherit from when:
435 ///   * Implementing a Writer that can only support seeking near the current
436 ///     position.
437 ///
438 /// A buffered Writer that only supports seeking within its buffer is a good
439 /// example of a RelativeSeekableWriter.
440 class RelativeSeekableWriter : public Writer {
441  protected:
RelativeSeekableWriter()442   constexpr RelativeSeekableWriter()
443       : RelativeSeekableWriter(Seekability::kRelative) {}
444 
445  private:
446   friend class SeekableWriter;
447 
RelativeSeekableWriter(Seekability seekability)448   constexpr RelativeSeekableWriter(Seekability seekability)
449       : Writer(seekability) {}
450 };
451 
452 /// A Writer that fully supports seeking.
453 ///
454 /// Use in APIs when:
455 ///   * Absolute seeking is required. Use Writer& if seeking is not required or
456 ///     seek failures can be handled gracefully.
457 ///
458 /// Inherit from when:
459 ///   * Implementing a writer that supports absolute seeking.
460 ///
461 class SeekableWriter : public RelativeSeekableWriter {
462  protected:
SeekableWriter()463   constexpr SeekableWriter() : RelativeSeekableWriter(Seekability::kAbsolute) {}
464 };
465 
466 /// A Writer that does not support seeking. The Seek() method is hidden.
467 ///
468 /// Use in APIs when:
469 ///   * Do NOT use in APIs! If seeking is not required, use Writer& instead.
470 ///
471 /// Inherit from when:
472 ///   * Implementing a Writer that does not support seeking.
473 ///
474 class NonSeekableWriter : public Writer {
475  protected:
NonSeekableWriter()476   constexpr NonSeekableWriter() : Writer(Seekability::kNone) {}
477 
478  private:
479   using Writer::Seek;
480 
DoSeek(ptrdiff_t,Whence)481   Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
482 };
483 
484 /// A Stream that supports both reading and writing.
485 ///
486 /// Use in APIs when:
487 ///   * Must both read from and write to a stream.
488 ///   * May or may not need seeking. Use a SeekableReaderWriter& if seeking is
489 ///     required.
490 ///
491 /// Inherit from when:
492 ///   * Cannot extend ReaderWriter directly. Instead, extend
493 ///     SeekableReaderWriter, NonSeekableReaderWriter, or (rarely)
494 ///     RelativeSeekableReaderWriter, as appropriate.
495 ///
496 /// A ReaderWriter may or may not support seeking. Check seekable() or try
497 /// calling Seek() to determine if the stream is seekable.
498 class ReaderWriter : public Stream {
499  public:
500   // ReaderWriters may be used as Readers.
as_reader()501   Reader& as_reader() { return internal::SiblingCast<Reader&, Stream>(*this); }
as_reader()502   const Reader& as_reader() const {
503     return internal::SiblingCast<const Reader&, Stream>(*this);
504   }
505 
506   operator Reader&() { return as_reader(); }
507   operator const Reader&() const { return as_reader(); }
508 
509   // ReaderWriters may be used as Writers.
as_writer()510   Writer& as_writer() { return internal::SiblingCast<Writer&, Stream>(*this); }
as_writer()511   const Writer& as_writer() const {
512     return internal::SiblingCast<const Writer&, Stream>(*this);
513   }
514 
515   operator Writer&() { return as_writer(); }
516   operator const Writer&() const { return as_writer(); }
517 
518  private:
519   friend class RelativeSeekableReaderWriter;
520   friend class NonSeekableReaderWriter;
521 
ReaderWriter(Seekability seekability)522   constexpr ReaderWriter(Seekability seekability)
523       : Stream(true, true, seekability) {}
524 };
525 
526 /// A ReaderWriter that supports at least relative seeking within some range of
527 /// the current position. Seeking beyond that or from other origins may or may
528 /// not be supported. The extent to which seeking is possible is NOT exposed by
529 /// this API.
530 ///
531 /// Use in APIs when:
532 ///   * Relative seeking is required. Usage in APIs should be rare; generally
533 ///     ReaderWriter should be used instead.
534 ///
535 /// Inherit from when:
536 ///   * Implementing a ReaderWriter that can only support seeking near the
537 ///     current position.
538 ///
539 /// A buffered ReaderWriter that only supports seeking within its buffer is a
540 /// good example of a RelativeSeekableReaderWriter.
541 class RelativeSeekableReaderWriter : public ReaderWriter {
542  public:
543   // RelativeSeekableReaderWriters may be used as RelativeSeekableReaders or
544   // RelativeSeekableWriters.
545   operator RelativeSeekableReader&() {
546     return internal::SiblingCast<RelativeSeekableReader&, Stream>(*this);
547   }
548   operator const RelativeSeekableReader&() const {
549     return internal::SiblingCast<const RelativeSeekableReader&, Stream>(*this);
550   }
551   operator RelativeSeekableWriter&() {
552     return internal::SiblingCast<RelativeSeekableWriter&, Stream>(*this);
553   }
554   operator const RelativeSeekableWriter&() const {
555     return internal::SiblingCast<const RelativeSeekableWriter&, Stream>(*this);
556   }
557 
558  protected:
RelativeSeekableReaderWriter()559   constexpr RelativeSeekableReaderWriter()
560       : ReaderWriter(Seekability::kRelative) {}
561 
562  private:
563   friend class SeekableReaderWriter;
564 
RelativeSeekableReaderWriter(Seekability seekability)565   constexpr RelativeSeekableReaderWriter(Seekability seekability)
566       : ReaderWriter(seekability) {}
567 };
568 
569 /// A ReaderWriter that fully supports seeking.
570 ///
571 /// Use in APIs when:
572 ///   * Absolute seeking is required. Use ReaderWriter& if seeking is not
573 ///     required or seek failures can be handled gracefully.
574 ///
575 /// Inherit from when:
576 ///   * Implementing a writer that supports absolute seeking.
577 ///
578 class SeekableReaderWriter : public RelativeSeekableReaderWriter {
579  public:
580   // SeekableReaderWriters may be used as SeekableReaders.
as_seekable_reader()581   SeekableReader& as_seekable_reader() {
582     return internal::SiblingCast<SeekableReader&, Stream>(*this);
583   }
as_seekable_reader()584   const SeekableReader& as_seekable_reader() const {
585     return internal::SiblingCast<const SeekableReader&, Stream>(*this);
586   }
587 
588   operator SeekableReader&() { return as_seekable_reader(); }
589   operator const SeekableReader&() const { return as_seekable_reader(); }
590 
591   // SeekableReaderWriters may be used as SeekableWriters.
as_seekable_writer()592   SeekableWriter& as_seekable_writer() {
593     return internal::SiblingCast<SeekableWriter&, Stream>(*this);
594   }
as_seekable_writer()595   const SeekableWriter& as_seekable_writer() const {
596     return internal::SiblingCast<const SeekableWriter&, Stream>(*this);
597   }
598 
599   operator SeekableWriter&() { return as_seekable_writer(); }
600   operator const SeekableWriter&() const { return as_seekable_writer(); }
601 
602  protected:
SeekableReaderWriter()603   constexpr SeekableReaderWriter()
604       : RelativeSeekableReaderWriter(Seekability::kAbsolute) {}
605 };
606 
607 /// A ReaderWriter that does not support seeking. The Seek() method is hidden.
608 ///
609 /// Use in APIs when:
610 ///   * Do NOT use in APIs! If seeking is not required, use ReaderWriter&
611 ///     instead.
612 ///
613 /// Inherit from when:
614 ///   * Implementing a ReaderWriter that does not support seeking.
615 ///
616 class NonSeekableReaderWriter : public ReaderWriter {
617  public:
618   // NonSeekableReaderWriters may be used as either NonSeekableReaders or
619   // NonSeekableWriters. Note that NonSeekableReaderWriter& generally should not
620   // be used in APIs, which should accept ReaderWriter& instead.
621   operator NonSeekableReader&() {
622     return internal::SiblingCast<NonSeekableReader&, Stream>(*this);
623   }
624   operator const NonSeekableReader&() const {
625     return internal::SiblingCast<const NonSeekableReader&, Stream>(*this);
626   }
627   operator NonSeekableWriter&() {
628     return internal::SiblingCast<NonSeekableWriter&, Stream>(*this);
629   }
630   operator const NonSeekableWriter&() const {
631     return internal::SiblingCast<const NonSeekableWriter&, Stream>(*this);
632   }
633 
634  protected:
NonSeekableReaderWriter()635   constexpr NonSeekableReaderWriter() : ReaderWriter(Seekability::kNone) {}
636 
637  private:
638   using ReaderWriter::Seek;
639 
DoSeek(ptrdiff_t,Whence)640   Status DoSeek(ptrdiff_t, Whence) final { return Status::Unimplemented(); }
641 };
642 
643 }  // namespace pw::stream
644