Feature gate: #![feature(seek_io_take)], #![feature(seek_io_take_position)]
(feature gate open to change)
This is a tracking issue for adding seek instance for io::Take, see issue #37214.
Why
Imagine there's a smaller components within a larger file, the component have predefined ranges, reading beyond the range should be a hard error. But some fields are variable size encoded, so it's hard to know how many bytes to read until we already decoded/read a large part of it. It is super cumbersome to check every read is within the limit (of the component); however, with io::Take, this is much easier: We only need to create a new io::Take by limiting the upper bound to the component's spec. and just let the user to read what ever needed -- any attempt to read beyond the limit would cause a hard io error.
This is all good, but sometimes we need more powerful io rather than read. For instance, we may need peek and restore stream_position() depends on what data was peek-ed, skip a large chunk of unwanted bytes, or maybe we simply wanted to keep track of the stream_position() for better error handling. This is not possible because io::Take is not Seek.
Public API
Not yet stabilized API:
impl<T> Take<T> {
// Unstable as `seek_io_take_position`
pub fn position(&self) -> u64;
}
Insta-stable in #138023:
// Stabilized as `seek_io_take`
impl<T: Seek> Seek for Take<T> {
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
// snip
}
}
This is possible by adding a cursor member to io::Take, together with limit, we have:
- cursor + limit === original_limit (when Take is constructed)
- Seek beyond original_limit => stays at original_limit
- Seek beyond 0 (< 0) =>
ErrorKind::InvalidInput (EINVAL).
- Read beyond original_limit => io error.
- seek without position changes is honored (This is expected, see
BufReader doc).
The proposed method has an advantage over approach in #37214, by not using an extra stream_position() when io::Take is constructed.
History:
Feature gate:
#![feature(seek_io_take)],#
This is a tracking issue for adding seek instance for
io::Take, see issue #37214.Why
Imagine there's a smaller components within a larger file, the component have predefined ranges, reading beyond the range should be a hard error. But some fields are variable size encoded, so it's hard to know how many bytes to read until we already decoded/read a large part of it. It is super cumbersome to check every read is within the limit (of the component); however, with
io::Take, this is much easier: We only need to create a newio::Takeby limiting the upper bound to the component's spec. and just let the user to read what ever needed -- any attempt to read beyond the limit would cause a hard io error.This is all good, but sometimes we need more powerful io rather than read. For instance, we may need
peekand restorestream_position()depends on what data waspeek-ed, skip a large chunk of unwanted bytes, or maybe we simply wanted to keep track of thestream_position()for better error handling. This is not possible becauseio::Takeis notSeek.Public API
Not yet stabilized API:
Insta-stable in #138023:
This is possible by adding a
cursormember toio::Take, together withlimit, we have:ErrorKind::InvalidInput(EINVAL).BufReaderdoc).The proposed method has an advantage over approach in #37214, by not using an extra
stream_position()whenio::Takeis constructed.History:
impl<T: Seek> Seek for Take<T>, introduceTake::positionAddstd::io::Seekinstance forstd::io::Take#138023