diff options
Diffstat (limited to 'library/std/src/io/mod.rs')
| -rw-r--r-- | library/std/src/io/mod.rs | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 96fac4f6bde..03f5f838311 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1214,7 +1214,7 @@ pub trait Read { where Self: Sized, { - Take { inner: self, limit } + Take { inner: self, len: limit, limit } } } @@ -2830,6 +2830,7 @@ impl<T, U> SizeHint for Chain<T, U> { #[derive(Debug)] pub struct Take<T> { inner: T, + len: u64, limit: u64, } @@ -2864,6 +2865,12 @@ impl<T> Take<T> { self.limit } + /// Returns the number of bytes read so far. + #[unstable(feature = "seek_io_take_position", issue = "97227")] + pub fn position(&self) -> u64 { + self.len - self.limit + } + /// Sets the number of bytes that can be read before this instance will /// return EOF. This is the same as constructing a new `Take` instance, so /// the amount of bytes read and the previous limit value don't matter when @@ -2889,6 +2896,7 @@ impl<T> Take<T> { /// ``` #[stable(feature = "take_set_limit", since = "1.27.0")] pub fn set_limit(&mut self, limit: u64) { + self.len = limit; self.limit = limit; } @@ -3076,6 +3084,49 @@ impl<T> SizeHint for Take<T> { } } +#[stable(feature = "seek_io_take", since = "CURRENT_RUSTC_VERSION")] +impl<T: Seek> Seek for Take<T> { + fn seek(&mut self, pos: SeekFrom) -> Result<u64> { + let new_position = match pos { + SeekFrom::Start(v) => Some(v), + SeekFrom::Current(v) => self.position().checked_add_signed(v), + SeekFrom::End(v) => self.len.checked_add_signed(v), + }; + let new_position = match new_position { + Some(v) if v <= self.len => v, + _ => return Err(ErrorKind::InvalidInput.into()), + }; + while new_position != self.position() { + if let Some(offset) = new_position.checked_signed_diff(self.position()) { + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + break; + } + let offset = if new_position > self.position() { i64::MAX } else { i64::MIN }; + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + } + Ok(new_position) + } + + fn stream_len(&mut self) -> Result<u64> { + Ok(self.len) + } + + fn stream_position(&mut self) -> Result<u64> { + Ok(self.position()) + } + + fn seek_relative(&mut self, offset: i64) -> Result<()> { + if !self.position().checked_add_signed(offset).is_some_and(|p| p <= self.len) { + return Err(ErrorKind::InvalidInput.into()); + } + self.inner.seek_relative(offset)?; + self.limit = self.limit.wrapping_sub(offset as u64); + Ok(()) + } +} + /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes`] on a reader. |
