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