• 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 //
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