blob: 868f407270ce23fb6e07a876e5d523bef78bc1a6 [file] [log] [blame]
// Copyright 2021 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
// The header provides a set of helper utils for protobuf related operations.
// The APIs may not be finalized yet.
#pragma once
#include <cstddef>
#include <string_view>
#include "pw_assert/assert.h"
#include "pw_status/status.h"
#include "pw_stream/stream.h"
namespace pw::stream {
// A reader wrapper that reads from a sub-interval of a given seekable
// source reader. The IntervalReader tracks and maintains its own read offset.
// It seeks the source reader to its current read offset before reading. In
// this way, multiple IntervalReaders can share the same source reader without
// interfering with each other.
class IntervalReader : public SeekableReader {
public:
constexpr IntervalReader() : status_(Status::Unavailable()) {}
// Create an IntervalReader with an error status.
constexpr IntervalReader(Status status) : status_(status) {
PW_ASSERT(!status.ok());
}
// source_reader -- The source reader to read from.
// start -- starting offset to read in `source_reader`
// end -- ending offset in `source_reader`.
constexpr IntervalReader(SeekableReader& source_reader,
size_t start,
size_t end)
: source_reader_(&source_reader),
start_(start),
end_(end),
current_(start) {}
// Reset the read offset to the start of the interval
IntervalReader& Reset() {
current_ = start_;
return *this;
}
// Move the read offset to the end of the interval;
IntervalReader& Exhaust() {
current_ = end_;
return *this;
}
// Get a reference to the source reader.
SeekableReader& source_reader() { return *source_reader_; }
size_t start() const { return start_; }
size_t end() const { return end_; }
size_t current() const { return current_; }
size_t interval_size() const { return end_ - start_; }
bool ok() const { return status_.ok(); }
Status status() const { return status_; }
// For iterator comparison in Message.
bool operator==(const IntervalReader& other) const {
return source_reader_ == other.source_reader_ && start_ == other.start_ &&
end_ == other.end_ && current_ == other.current_;
}
private:
StatusWithSize DoRead(ByteSpan destination) final;
Status DoSeek(ptrdiff_t offset, Whence origin) final;
size_t DoTell() final { return current_ - start_; }
size_t ConservativeLimit(LimitType limit) const override {
if (limit == LimitType::kRead) {
return end_ - current_;
}
return 0;
}
SeekableReader* source_reader_ = nullptr;
size_t start_ = 0;
size_t end_ = 0;
size_t current_ = 0;
Status status_ = OkStatus();
};
} // namespace pw::stream