Skip to content

Commit

Permalink
Rollup merge of rust-lang#98154 - vidhanio:master, r=workingjubilee
Browse files Browse the repository at this point in the history
merge functionality of `io::Sink` into `io::Empty`

Many times, there is a need for a simple dummy `io::Read`er + `io::Write`r, but currently the only options are `io::Empty` and `io::Sink` respectively. Having both of their functionality together requires writing your own boilerplate for something that makes sense to have in the standard library. This PR adds the functionality of `io::Sink` to `io::Empty`, making `io::Empty` be able to perform the tasks of both of the previous structs. (This idea was first mentioned in rust-lang#24235)

Note: I also updated some doc comments in `io::utils` in this pull request to fix inconsistencies between `io::Sink` and `io::Empty`.

API Change Proposal: rust-lang/libs-team#49
  • Loading branch information
matthiaskrgr authored Jul 30, 2023
2 parents 89acdae + 79a22f4 commit 27e3a74
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 26 deletions.
100 changes: 76 additions & 24 deletions library/std/src/io/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,41 @@ use crate::io::{
self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
};

/// A reader which is always at EOF.
/// `Empty` ignores any data written via [`Write`], and will always be empty
/// (returning zero bytes) when read via [`Read`].
///
/// This struct is generally created by calling [`empty()`]. Please see
/// the documentation of [`empty()`] for more details.
/// This struct is generally created by calling [`empty()`]. Please
/// see the documentation of [`empty()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
#[non_exhaustive]
#[derive(Copy, Clone, Default)]
#[derive(Copy, Clone, Debug, Default)]
pub struct Empty;

/// Constructs a new handle to an empty reader.
/// Creates a value that is always at EOF for reads, and ignores all data written.
///
/// All reads from the returned reader will return <code>[Ok]\(0)</code>.
/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
/// and the contents of the buffer will not be inspected.
///
/// All calls to [`read`] from the returned reader will return [`Ok(0)`].
///
/// [`Ok(buf.len())`]: Ok
/// [`Ok(0)`]: Ok
///
/// [`write`]: Write::write
/// [`read`]: Read::read
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::empty().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
///
///
/// ```rust
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
Expand Down Expand Up @@ -76,20 +93,61 @@ impl Seek for Empty {
}
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Empty").finish_non_exhaustive()
}
}

impl SizeHint for Empty {
#[inline]
fn upper_bound(&self) -> Option<usize> {
Some(0)
}
}

#[stable(feature = "empty_write", since = "1.64.0")]
impl Write for Empty {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}

#[inline]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum();
Ok(total_len)
}

#[inline]
fn is_write_vectored(&self) -> bool {
true
}

#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

#[stable(feature = "empty_write", since = "1.64.0")]
impl Write for &Empty {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
Ok(buf.len())
}

#[inline]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum();
Ok(total_len)
}

#[inline]
fn is_write_vectored(&self) -> bool {
true
}

#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please
Expand Down Expand Up @@ -182,19 +240,20 @@ impl fmt::Debug for Repeat {

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`]. Please
/// This struct is generally created by calling [`sink()`]. Please
/// see the documentation of [`sink()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
#[non_exhaustive]
#[derive(Copy, Clone, Default)]
#[derive(Copy, Clone, Debug, Default)]
pub struct Sink;

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
/// All calls to [`write`] on the returned instance will return [`Ok(buf.len())`]
/// and the contents of the buffer will not be inspected.
///
/// [`write`]: Write::write
/// [`Ok(buf.len())`]: Ok
///
/// # Examples
///
Expand Down Expand Up @@ -259,10 +318,3 @@ impl Write for &Sink {
Ok(())
}
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sink").finish_non_exhaustive()
}
}
13 changes: 11 additions & 2 deletions library/std/src/io/util/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn empty_reads() {
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(Read::by_ref(&mut e).read(&mut [0; 1024]).unwrap(), 0);

let buf: &mut [MaybeUninit<_>] = &mut [];
let mut buf: BorrowedBuf<'_> = buf.into();
Expand All @@ -40,7 +40,7 @@ fn empty_reads() {

let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
let mut buf: BorrowedBuf<'_> = buf.into();
e.by_ref().read_buf(buf.unfilled()).unwrap();
Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap();
assert_eq!(buf.len(), 0);
assert_eq!(buf.init_len(), 0);
}
Expand All @@ -65,6 +65,15 @@ fn empty_seeks() {
assert!(matches!(e.seek(SeekFrom::Current(i64::MAX)), Ok(0)));
}

#[test]
fn empty_sinks() {
let mut e = empty();
assert_eq!(e.write(&[]).unwrap(), 0);
assert_eq!(e.write(&[0]).unwrap(), 1);
assert_eq!(e.write(&[0; 1024]).unwrap(), 1024);
assert_eq!(Write::by_ref(&mut e).write(&[0; 1024]).unwrap(), 1024);
}

#[test]
fn repeat_repeats() {
let mut r = repeat(4);
Expand Down

0 comments on commit 27e3a74

Please sign in to comment.