Rollup merge of #86037 - soerenmeier:cursor_remaining, r=yaahc

Add `io::Cursor::{remaining, remaining_slice, is_empty}`

Tracking issue: #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.
This commit is contained in:
Yuki Okushi 2021-06-22 07:37:46 +09:00 committed by GitHub
commit 4463b08652
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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
@ -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)
}
@ -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(())
}
@ -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;