]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #85815 - YuhanLiin:buf-read-data-left, r=m-ou-se
authorbors <bors@rust-lang.org>
Fri, 18 Jun 2021 20:11:51 +0000 (20:11 +0000)
committerbors <bors@rust-lang.org>
Fri, 18 Jun 2021 20:11:51 +0000 (20:11 +0000)
Add has_data_left() to BufRead

This is a continuation of #40747 and also addresses #40745. The problem with the previous PR was that it had "eof" in its method name. This PR uses a more descriptive method name, but I'm open to changing it.

1  2 
library/std/src/io/mod.rs
library/std/src/io/tests.rs

index a25ef8c87a5d23e5eeda8674241957799984e645,6963f4132ac909f9eb8aa490bfff7fcb4e29959a..00b85604a3f67bd5bd4dbd00b4f8313eb56aa5de
  mod tests;
  
  use crate::cmp;
 +use crate::convert::TryInto;
  use crate::fmt;
 +use crate::mem::replace;
  use crate::ops::{Deref, DerefMut};
  use crate::ptr;
  use crate::slice;
@@@ -1046,32 -1044,6 +1046,32 @@@ impl<'a> IoSliceMut<'a> 
  
      /// Advance the internal cursor of the slice.
      ///
 +    /// Also see [`IoSliceMut::advance_slices`] to advance the cursors of
 +    /// multiple buffers.
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// #![feature(io_slice_advance)]
 +    ///
 +    /// use std::io::IoSliceMut;
 +    /// use std::ops::Deref;
 +    ///
 +    /// let mut data = [1; 8];
 +    /// let mut buf = IoSliceMut::new(&mut data);
 +    ///
 +    /// // Mark 3 bytes as read.
 +    /// buf.advance(3);
 +    /// assert_eq!(buf.deref(), [1; 5].as_ref());
 +    /// ```
 +    #[unstable(feature = "io_slice_advance", issue = "62726")]
 +    #[inline]
 +    pub fn advance(&mut self, n: usize) {
 +        self.0.advance(n)
 +    }
 +
 +    /// Advance the internal cursor of the slices.
 +    ///
      /// # Notes
      ///
      /// Elements in the slice may be modified if the cursor is not advanced to
      /// ][..];
      ///
      /// // Mark 10 bytes as read.
 -    /// bufs = IoSliceMut::advance(bufs, 10);
 +    /// IoSliceMut::advance_slices(&mut bufs, 10);
      /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
      /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
      /// ```
      #[unstable(feature = "io_slice_advance", issue = "62726")]
      #[inline]
 -    pub fn advance<'b>(bufs: &'b mut [IoSliceMut<'a>], n: usize) -> &'b mut [IoSliceMut<'a>] {
 +    pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
          // Number of buffers to remove.
          let mut remove = 0;
          // Total length of all the to be removed buffers.
              }
          }
  
 -        let bufs = &mut bufs[remove..];
 +        *bufs = &mut replace(bufs, &mut [])[remove..];
          if !bufs.is_empty() {
 -            bufs[0].0.advance(n - accumulated_len)
 +            bufs[0].advance(n - accumulated_len)
          }
 -        bufs
      }
  }
  
@@@ -1180,32 -1153,6 +1180,32 @@@ impl<'a> IoSlice<'a> 
  
      /// Advance the internal cursor of the slice.
      ///
 +    /// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple
 +    /// buffers.
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// #![feature(io_slice_advance)]
 +    ///
 +    /// use std::io::IoSlice;
 +    /// use std::ops::Deref;
 +    ///
 +    /// let mut data = [1; 8];
 +    /// let mut buf = IoSlice::new(&mut data);
 +    ///
 +    /// // Mark 3 bytes as read.
 +    /// buf.advance(3);
 +    /// assert_eq!(buf.deref(), [1; 5].as_ref());
 +    /// ```
 +    #[unstable(feature = "io_slice_advance", issue = "62726")]
 +    #[inline]
 +    pub fn advance(&mut self, n: usize) {
 +        self.0.advance(n)
 +    }
 +
 +    /// Advance the internal cursor of the slices.
 +    ///
      /// # Notes
      ///
      /// Elements in the slice may be modified if the cursor is not advanced to
      /// ][..];
      ///
      /// // Mark 10 bytes as written.
 -    /// bufs = IoSlice::advance(bufs, 10);
 +    /// IoSlice::advance_slices(&mut bufs, 10);
      /// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
      /// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
      #[unstable(feature = "io_slice_advance", issue = "62726")]
      #[inline]
 -    pub fn advance<'b>(bufs: &'b mut [IoSlice<'a>], n: usize) -> &'b mut [IoSlice<'a>] {
 +    pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
          // Number of buffers to remove.
          let mut remove = 0;
          // Total length of all the to be removed buffers.
              }
          }
  
 -        let bufs = &mut bufs[remove..];
 +        *bufs = &mut replace(bufs, &mut [])[remove..];
          if !bufs.is_empty() {
 -            bufs[0].0.advance(n - accumulated_len)
 +            bufs[0].advance(n - accumulated_len)
          }
 -        bufs
      }
  }
  
@@@ -1563,7 -1511,7 +1563,7 @@@ pub trait Write 
      fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
          // Guarantee that bufs is empty if it contains no data,
          // to avoid calling write_vectored if there is no data to be written.
 -        bufs = IoSlice::advance(bufs, 0);
 +        IoSlice::advance_slices(&mut bufs, 0);
          while !bufs.is_empty() {
              match self.write_vectored(bufs) {
                  Ok(0) => {
                          &"failed to write whole buffer",
                      ));
                  }
 -                Ok(n) => bufs = IoSlice::advance(bufs, n),
 +                Ok(n) => IoSlice::advance_slices(&mut bufs, n),
                  Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
                  Err(e) => return Err(e),
              }
@@@ -2005,6 -1953,37 +2005,37 @@@ pub trait BufRead: Read 
      #[stable(feature = "rust1", since = "1.0.0")]
      fn consume(&mut self, amt: usize);
  
+     /// Check if the underlying `Read` has any data left to be read.
+     ///
+     /// This function may fill the buffer to check for data,
+     /// so this functions returns `Result<bool>`, not `bool`.
+     ///
+     /// Default implementation calls `fill_buf` and checks that
+     /// returned slice is empty (which means that there is no data left,
+     /// since EOF is reached).
+     ///
+     /// Examples
+     ///
+     /// ```
+     /// #![feature(buf_read_has_data_left)]
+     /// use std::io;
+     /// use std::io::prelude::*;
+     ///
+     /// let stdin = io::stdin();
+     /// let mut stdin = stdin.lock();
+     ///
+     /// while stdin.has_data_left().unwrap() {
+     ///     let mut line = String::new();
+     ///     stdin.read_line(&mut line).unwrap();
+     ///     // work with line
+     ///     println!("{:?}", line);
+     /// }
+     /// ```
+     #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")]
+     fn has_data_left(&mut self) -> Result<bool> {
+         self.fill_buf().map(|b| !b.is_empty())
+     }
      /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
      ///
      /// This function will read bytes from the underlying stream until the
@@@ -2343,15 -2322,13 +2374,15 @@@ impl<T: BufRead, U: BufRead> BufRead fo
  }
  
  impl<T, U> SizeHint for Chain<T, U> {
 +    #[inline]
      fn lower_bound(&self) -> usize {
          SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
      }
  
 +    #[inline]
      fn upper_bound(&self) -> Option<usize> {
          match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
 -            (Some(first), Some(second)) => Some(first + second),
 +            (Some(first), Some(second)) => first.checked_add(second),
              _ => None,
          }
      }
@@@ -2556,21 -2533,6 +2587,21 @@@ impl<T: BufRead> BufRead for Take<T> 
      }
  }
  
 +impl<T> SizeHint for Take<T> {
 +    #[inline]
 +    fn lower_bound(&self) -> usize {
 +        cmp::min(SizeHint::lower_bound(&self.inner) as u64, self.limit) as usize
 +    }
 +
 +    #[inline]
 +    fn upper_bound(&self) -> Option<usize> {
 +        match SizeHint::upper_bound(&self.inner) {
 +            Some(upper_bound) => Some(cmp::min(upper_bound as u64, self.limit) as usize),
 +            None => self.limit.try_into().ok(),
 +        }
 +    }
 +}
 +
  /// An iterator over `u8` values of a reader.
  ///
  /// This struct is generally created by calling [`bytes`] on a reader.
@@@ -2615,53 -2577,15 +2646,53 @@@ trait SizeHint 
  }
  
  impl<T> SizeHint for T {
 +    #[inline]
      default fn lower_bound(&self) -> usize {
          0
      }
  
 +    #[inline]
      default fn upper_bound(&self) -> Option<usize> {
          None
      }
  }
  
 +impl<T> SizeHint for &mut T {
 +    #[inline]
 +    fn lower_bound(&self) -> usize {
 +        SizeHint::lower_bound(*self)
 +    }
 +
 +    #[inline]
 +    fn upper_bound(&self) -> Option<usize> {
 +        SizeHint::upper_bound(*self)
 +    }
 +}
 +
 +impl<T> SizeHint for Box<T> {
 +    #[inline]
 +    fn lower_bound(&self) -> usize {
 +        SizeHint::lower_bound(&**self)
 +    }
 +
 +    #[inline]
 +    fn upper_bound(&self) -> Option<usize> {
 +        SizeHint::upper_bound(&**self)
 +    }
 +}
 +
 +impl SizeHint for &[u8] {
 +    #[inline]
 +    fn lower_bound(&self) -> usize {
 +        self.len()
 +    }
 +
 +    #[inline]
 +    fn upper_bound(&self) -> Option<usize> {
 +        Some(self.len())
 +    }
 +}
 +
  /// An iterator over the contents of an instance of `BufRead` split on a
  /// particular byte.
  ///
index 2ee30f5fb4f08cbd7e9f98d3beb61d3dd6327345,4206b79405864ed56d64a2d7082b79c7fc6890ab..b73bcf85fbee25cdddb446bd3dbe37e27f6c26f7
@@@ -71,6 -71,16 +71,16 @@@ fn lines() 
      assert!(s.next().is_none());
  }
  
+ #[test]
+ fn buf_read_has_data_left() {
+     let mut buf = Cursor::new(&b"abcd"[..]);
+     assert!(buf.has_data_left().unwrap());
+     buf.read_exact(&mut [0; 2]).unwrap();
+     assert!(buf.has_data_left().unwrap());
+     buf.read_exact(&mut [0; 2]).unwrap();
+     assert!(!buf.has_data_left().unwrap());
+ }
  #[test]
  fn read_to_end() {
      let mut c = Cursor::new(&b""[..]);
@@@ -224,24 -234,6 +234,24 @@@ fn empty_size_hint() 
      assert_eq!(size_hint, (0, Some(0)));
  }
  
 +#[test]
 +fn slice_size_hint() {
 +    let size_hint = (&[1, 2, 3]).bytes().size_hint();
 +    assert_eq!(size_hint, (3, Some(3)));
 +}
 +
 +#[test]
 +fn take_size_hint() {
 +    let size_hint = (&[1, 2, 3]).take(2).bytes().size_hint();
 +    assert_eq!(size_hint, (2, Some(2)));
 +
 +    let size_hint = (&[1, 2, 3]).take(4).bytes().size_hint();
 +    assert_eq!(size_hint, (3, Some(3)));
 +
 +    let size_hint = io::repeat(0).take(3).bytes().size_hint();
 +    assert_eq!(size_hint, (3, Some(3)));
 +}
 +
  #[test]
  fn chain_empty_size_hint() {
      let chain = io::empty().chain(io::empty());
@@@ -260,7 -252,7 +270,7 @@@ fn chain_size_hint() 
  
      let chain = buf_reader_1.chain(buf_reader_2);
      let size_hint = chain.bytes().size_hint();
 -    assert_eq!(size_hint, (testdata.len(), None));
 +    assert_eq!(size_hint, (testdata.len(), Some(testdata.len())));
  }
  
  #[test]
@@@ -371,7 -363,7 +381,7 @@@ fn test_read_to_end_capacity() -> io::R
  }
  
  #[test]
 -fn io_slice_mut_advance() {
 +fn io_slice_mut_advance_slices() {
      let mut buf1 = [1; 8];
      let mut buf2 = [2; 16];
      let mut buf3 = [3; 8];
      ][..];
  
      // Only in a single buffer..
 -    bufs = IoSliceMut::advance(bufs, 1);
 +    IoSliceMut::advance_slices(&mut bufs, 1);
      assert_eq!(bufs[0].deref(), [1; 7].as_ref());
      assert_eq!(bufs[1].deref(), [2; 16].as_ref());
      assert_eq!(bufs[2].deref(), [3; 8].as_ref());
  
      // Removing a buffer, leaving others as is.
 -    bufs = IoSliceMut::advance(bufs, 7);
 +    IoSliceMut::advance_slices(&mut bufs, 7);
      assert_eq!(bufs[0].deref(), [2; 16].as_ref());
      assert_eq!(bufs[1].deref(), [3; 8].as_ref());
  
      // Removing a buffer and removing from the next buffer.
 -    bufs = IoSliceMut::advance(bufs, 18);
 +    IoSliceMut::advance_slices(&mut bufs, 18);
      assert_eq!(bufs[0].deref(), [3; 6].as_ref());
  }
  
  #[test]
 -fn io_slice_mut_advance_empty_slice() {
 -    let empty_bufs = &mut [][..];
 +fn io_slice_mut_advance_slices_empty_slice() {
 +    let mut empty_bufs = &mut [][..];
      // Shouldn't panic.
 -    IoSliceMut::advance(empty_bufs, 1);
 +    IoSliceMut::advance_slices(&mut empty_bufs, 1);
  }
  
  #[test]
 -fn io_slice_mut_advance_beyond_total_length() {
 +fn io_slice_mut_advance_slices_beyond_total_length() {
      let mut buf1 = [1; 8];
      let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
  
      // Going beyond the total length should be ok.
 -    bufs = IoSliceMut::advance(bufs, 9);
 +    IoSliceMut::advance_slices(&mut bufs, 9);
      assert!(bufs.is_empty());
  }
  
  #[test]
 -fn io_slice_advance() {
 +fn io_slice_advance_slices() {
      let buf1 = [1; 8];
      let buf2 = [2; 16];
      let buf3 = [3; 8];
      let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
  
      // Only in a single buffer..
 -    bufs = IoSlice::advance(bufs, 1);
 +    IoSlice::advance_slices(&mut bufs, 1);
      assert_eq!(bufs[0].deref(), [1; 7].as_ref());
      assert_eq!(bufs[1].deref(), [2; 16].as_ref());
      assert_eq!(bufs[2].deref(), [3; 8].as_ref());
  
      // Removing a buffer, leaving others as is.
 -    bufs = IoSlice::advance(bufs, 7);
 +    IoSlice::advance_slices(&mut bufs, 7);
      assert_eq!(bufs[0].deref(), [2; 16].as_ref());
      assert_eq!(bufs[1].deref(), [3; 8].as_ref());
  
      // Removing a buffer and removing from the next buffer.
 -    bufs = IoSlice::advance(bufs, 18);
 +    IoSlice::advance_slices(&mut bufs, 18);
      assert_eq!(bufs[0].deref(), [3; 6].as_ref());
  }
  
  #[test]
 -fn io_slice_advance_empty_slice() {
 -    let empty_bufs = &mut [][..];
 +fn io_slice_advance_slices_empty_slice() {
 +    let mut empty_bufs = &mut [][..];
      // Shouldn't panic.
 -    IoSlice::advance(empty_bufs, 1);
 +    IoSlice::advance_slices(&mut empty_bufs, 1);
  }
  
  #[test]
 -fn io_slice_advance_beyond_total_length() {
 +fn io_slice_advance_slices_beyond_total_length() {
      let buf1 = [1; 8];
      let mut bufs = &mut [IoSlice::new(&buf1)][..];
  
      // Going beyond the total length should be ok.
 -    bufs = IoSlice::advance(bufs, 9);
 +    IoSlice::advance_slices(&mut bufs, 9);
      assert!(bufs.is_empty());
  }