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 IntervalReaders can share the same source reader without 33 // interfering with each other. 34 class IntervalReader : public SeekableReader { 35 public: IntervalReader()36 constexpr IntervalReader() : status_(Status::Unavailable()) {} 37 38 // Create an IntervalReader with an error status. IntervalReader(Status status)39 constexpr IntervalReader(Status status) : status_(status) { 40 PW_ASSERT(!status.ok()); 41 } 42 43 // source_reader -- The source reader to read from. 44 // start -- starting offset to read in `source_reader` 45 // end -- ending offset in `source_reader`. IntervalReader(SeekableReader & source_reader,size_t start,size_t end)46 constexpr IntervalReader(SeekableReader& source_reader, 47 size_t start, 48 size_t end) 49 : source_reader_(&source_reader), 50 start_(start), 51 end_(end), 52 current_(start) {} 53 54 // Reset the read offset to the start of the interval Reset()55 IntervalReader& Reset() { 56 current_ = start_; 57 return *this; 58 } 59 60 // Move the read offset to the end of the interval; Exhaust()61 IntervalReader& Exhaust() { 62 current_ = end_; 63 return *this; 64 } 65 66 // Get a reference to the source reader. source_reader()67 SeekableReader& source_reader() { return *source_reader_; } start()68 size_t start() const { return start_; } end()69 size_t end() const { return end_; } current()70 size_t current() const { return current_; } interval_size()71 size_t interval_size() const { return end_ - start_; } ok()72 bool ok() const { return status_.ok(); } status()73 Status status() const { return status_; } 74 75 // For iterator comparison in Message. 76 bool operator==(const IntervalReader& other) const { 77 return source_reader_ == other.source_reader_ && start_ == other.start_ && 78 end_ == other.end_ && current_ == other.current_; 79 } 80 81 private: 82 StatusWithSize DoRead(ByteSpan destination) final; 83 Status DoSeek(ptrdiff_t offset, Whence origin) final; DoTell()84 size_t DoTell() final { return current_ - start_; } ConservativeLimit(LimitType limit)85 size_t ConservativeLimit(LimitType limit) const override { 86 if (limit == LimitType::kRead) { 87 return end_ - current_; 88 } 89 return 0; 90 } 91 92 SeekableReader* source_reader_ = nullptr; 93 size_t start_ = 0; 94 size_t end_ = 0; 95 size_t current_ = 0; 96 Status status_ = OkStatus(); 97 }; 98 99 } // namespace pw::stream 100