Skip to content

Commit

Permalink
Rollup merge of rust-lang#86037 - soerenmeier:cursor_remaining, r=yaahc
Browse files Browse the repository at this point in the history
Add `io::Cursor::{remaining, remaining_slice, is_empty}`

Tracking issue: rust-lang#86369

I came across an inconvenience when answering the following [Stack Overflow](https://stackoverflow.com/questions/67831170) question.
To get the remaining slice you have to call `buff.fill_buf().unwrap()`. Which in my opinion doesn't really tell you what is returned (in the context of Cursor). To improve readability and convenience when using Cursor i propose adding the method `remaining`.

The next thing i found inconvenient (unnecessary long) was detecting if the cursor reached the end. There are a few ways this can be achieved right now:
- `buff.fill_buf().unwrap().is_empty()`
- `buff.position() >= buff.get_ref().len()`
- `buff.bytes().next().is_none()`

Which all seem a bit unintuitive, hidden in trait documentations or just a bit long for such a simple task.
Therefor i propose another method called `is_empty`, maybe with another name, since this one may leave room for interpretation on what really is empty (the underlying slice, the remaining slice or maybe the position).

Since it seemed easier to create this PR instead of an RFC i did that, if an RFC is wanted, i can close this PR and write an RFC first.
  • Loading branch information
JohnTitor authored Jun 21, 2021
2 parents 7f1a4a2 + 664bde0 commit 4463b08
Showing 1 changed file with 85 additions and 4 deletions.
89 changes: 85 additions & 4 deletions library/std/src/io/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,88 @@ impl<T> Cursor<T> {
}
}

impl<T> Cursor<T>
where
T: AsRef<[u8]>,
{
/// Returns the remaining length.
///
/// # Examples
///
/// ```
/// #![feature(cursor_remaining)]
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.remaining(), 5);
///
/// buff.set_position(2);
/// assert_eq!(buff.remaining(), 3);
///
/// buff.set_position(4);
/// assert_eq!(buff.remaining(), 1);
///
/// buff.set_position(6);
/// assert_eq!(buff.remaining(), 0);
/// ```
#[unstable(feature = "cursor_remaining", issue = "86369")]
pub fn remaining(&self) -> u64 {
(self.inner.as_ref().len() as u64).checked_sub(self.pos).unwrap_or(0)
}

/// Returns the remaining slice.
///
/// # Examples
///
/// ```
/// #![feature(cursor_remaining)]
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.remaining_slice(), &[1, 2, 3, 4, 5]);
///
/// buff.set_position(2);
/// assert_eq!(buff.remaining_slice(), &[3, 4, 5]);
///
/// buff.set_position(4);
/// assert_eq!(buff.remaining_slice(), &[5]);
///
/// buff.set_position(6);
/// assert_eq!(buff.remaining_slice(), &[]);
/// ```
#[unstable(feature = "cursor_remaining", issue = "86369")]
pub fn remaining_slice(&self) -> &[u8] {
let len = self.pos.min(self.inner.as_ref().len() as u64);
&self.inner.as_ref()[(len as usize)..]
}

/// Returns `true` if the remaining slice is empty.
///
/// # Examples
///
/// ```
/// #![feature(cursor_remaining)]
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// buff.set_position(2);
/// assert!(!buff.is_empty());
///
/// buff.set_position(5);
/// assert!(buff.is_empty());
///
/// buff.set_position(10);
/// assert!(buff.is_empty());
/// ```
#[unstable(feature = "cursor_remaining", issue = "86369")]
pub fn is_empty(&self) -> bool {
self.pos >= self.inner.as_ref().len() as u64
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Cursor<T>
where
Expand Down Expand Up @@ -268,7 +350,7 @@ where
T: AsRef<[u8]>,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = Read::read(&mut self.fill_buf()?, buf)?;
let n = Read::read(&mut self.remaining_slice(), buf)?;
self.pos += n as u64;
Ok(n)
}
Expand All @@ -291,7 +373,7 @@ where

fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
let n = buf.len();
Read::read_exact(&mut self.fill_buf()?, buf)?;
Read::read_exact(&mut self.remaining_slice(), buf)?;
self.pos += n as u64;
Ok(())
}
Expand All @@ -308,8 +390,7 @@ where
T: AsRef<[u8]>,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
Ok(&self.inner.as_ref()[(amt as usize)..])
Ok(self.remaining_slice())
}
fn consume(&mut self, amt: usize) {
self.pos += amt as u64;
Expand Down

0 comments on commit 4463b08

Please sign in to comment.