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 // 15 // The header provides a set of helper utils for protobuf related operations. 16 // The APIs may not be finalized yet. 17 18 #pragma once 19 20 #include <cstddef> 21 #include <string_view> 22 23 #include "pw_assert/assert.h" 24 #include "pw_status/status.h" 25 #include "pw_stream/stream.h" 26 27 namespace pw::stream { 28 29 // A reader wrapper that reads from a sub-interval of a given seekable 30 // source reader. The IntervalReader tracks and maintains its own read offset. 31 // It seeks the source reader to its current read offset before reading. In 32 // this way, multiple IntervalReader can share the same source reader without 33 // interfereing each other. 34 // 35 // The reader additionally embedds a `Status` to indicate whether itself 36 // is valid. This is a workaround for Reader not being compatibile with 37 // Result<>. TODO(pwbug/363): Migrate this to Result<> once we have StatusOr 38 // like support. 39 class IntervalReader : public SeekableReader { 40 public: IntervalReader()41 constexpr IntervalReader() : status_(Status::Unavailable()) {} 42 43 // Create an IntervalReader with an error status. IntervalReader(Status status)44 constexpr IntervalReader(Status status) : status_(status) { 45 PW_ASSERT(!status.ok()); 46 } 47 48 // source_reader -- The source reader to read from. 49 // start -- starting offset to read in `source_reader` 50 // end -- ending offset in `source_reader`. IntervalReader(SeekableReader & source_reader,size_t start,size_t end)51 constexpr IntervalReader(SeekableReader& source_reader, 52 size_t start, 53 size_t end) 54 : source_reader_(&source_reader), 55 start_(start), 56 end_(end), 57 current_(start) {} 58 59 // Reset the read offset to the start of the interval Reset()60 IntervalReader& Reset() { 61 current_ = start_; 62 return *this; 63 } 64 65 // Move the read offset to the end of the intetrval; Exhaust()66 IntervalReader& Exhaust() { 67 current_ = end_; 68 return *this; 69 } 70 71 // Get a reference to the source reader. source_reader()72 SeekableReader& source_reader() { return *source_reader_; } start()73 size_t start() const { return start_; } end()74 size_t end() const { return end_; } current()75 size_t current() const { return current_; } interval_size()76 size_t interval_size() const { return end_ - start_; } ok()77 bool ok() const { return status_.ok(); } status()78 Status status() const { return status_; } 79 80 // For iterator comparison in Message. 81 bool operator==(const IntervalReader& other) const { 82 return source_reader_ == other.source_reader_ && start_ == other.start_ && 83 end_ == other.end_ && current_ == other.current_; 84 } 85 86 private: 87 StatusWithSize DoRead(ByteSpan destination) final; 88 Status DoSeek(ptrdiff_t offset, Whence origin) final; DoTell()89 size_t DoTell() const final { return current_ - start_; } ConservativeLimit(LimitType limit)90 size_t ConservativeLimit(LimitType limit) const override { 91 if (limit == LimitType::kRead) { 92 return end_ - current_; 93 } 94 return 0; 95 } 96 97 SeekableReader* source_reader_ = nullptr; 98 size_t start_ = 0; 99 size_t end_ = 0; 100 size_t current_ = 0; 101 Status status_ = OkStatus(); 102 }; 103 104 } // namespace pw::stream 105