diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /library/std/src/io/util | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | library/std/src/io/util.rs | 270 | ||||
-rw-r--r-- | library/std/src/io/util/tests.rs | 147 |
2 files changed, 417 insertions, 0 deletions
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs new file mode 100644 index 000000000..c1300cd67 --- /dev/null +++ b/library/std/src/io/util.rs @@ -0,0 +1,270 @@ +#![allow(missing_copy_implementations)] + +#[cfg(test)] +mod tests; + +use crate::fmt; +use crate::io::{ + self, BufRead, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, Write, +}; + +/// A reader which is always at EOF. +/// +/// 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)] +pub struct Empty; + +/// Constructs a new handle to an empty reader. +/// +/// All reads from the returned reader will return <code>[Ok]\(0)</code>. +/// +/// # Examples +/// +/// A slightly sad example of not reading anything into a buffer: +/// +/// ``` +/// use std::io::{self, Read}; +/// +/// let mut buffer = String::new(); +/// io::empty().read_to_string(&mut buffer).unwrap(); +/// assert!(buffer.is_empty()); +/// ``` +#[must_use] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] +pub const fn empty() -> Empty { + Empty +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Empty { + #[inline] + fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { + Ok(0) + } + + #[inline] + fn read_buf(&mut self, _buf: &mut ReadBuf<'_>) -> io::Result<()> { + Ok(()) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for Empty { + #[inline] + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Ok(&[]) + } + #[inline] + fn consume(&mut self, _n: usize) {} +} + +#[stable(feature = "empty_seek", since = "1.51.0")] +impl Seek for Empty { + fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> { + Ok(0) + } + + fn stream_len(&mut self) -> io::Result<u64> { + Ok(0) + } + + fn stream_position(&mut self) -> io::Result<u64> { + Ok(0) + } +} + +#[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) + } +} + +/// 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 +/// see the documentation of [`repeat()`] for more details. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Repeat { + byte: u8, +} + +/// Creates an instance of a reader that infinitely repeats one byte. +/// +/// All reads from this reader will succeed by filling the specified buffer with +/// the given byte. +/// +/// # Examples +/// +/// ``` +/// use std::io::{self, Read}; +/// +/// let mut buffer = [0; 3]; +/// io::repeat(0b101).read_exact(&mut buffer).unwrap(); +/// assert_eq!(buffer, [0b101, 0b101, 0b101]); +/// ``` +#[must_use] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] +pub const fn repeat(byte: u8) -> Repeat { + Repeat { byte } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Read for Repeat { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + for slot in &mut *buf { + *slot = self.byte; + } + Ok(buf.len()) + } + + fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> { + // SAFETY: No uninit bytes are being written + for slot in unsafe { buf.unfilled_mut() } { + slot.write(self.byte); + } + + let remaining = buf.remaining(); + + // SAFETY: the entire unfilled portion of buf has been initialized + unsafe { + buf.assume_init(remaining); + } + + buf.add_filled(remaining); + + Ok(()) + } + + #[inline] + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + let mut nwritten = 0; + for buf in bufs { + nwritten += self.read(buf)?; + } + Ok(nwritten) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } +} + +impl SizeHint for Repeat { + #[inline] + fn lower_bound(&self) -> usize { + usize::MAX + } + + #[inline] + fn upper_bound(&self) -> Option<usize> { + None + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl fmt::Debug for Repeat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Repeat").finish_non_exhaustive() + } +} + +/// A writer which will move data into the void. +/// +/// 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)] +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())` +/// and the contents of the buffer will not be inspected. +/// +/// [`write`]: Write::write +/// +/// # Examples +/// +/// ```rust +/// use std::io::{self, Write}; +/// +/// let buffer = vec![1, 2, 3, 5, 8]; +/// let num_bytes = io::sink().write(&buffer).unwrap(); +/// assert_eq!(num_bytes, 5); +/// ``` +#[must_use] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")] +pub const fn sink() -> Sink { + Sink +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Write for Sink { + #[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 = "write_mt", since = "1.48.0")] +impl Write for &Sink { + #[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 = "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() + } +} diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs new file mode 100644 index 000000000..08972a59a --- /dev/null +++ b/library/std/src/io/util/tests.rs @@ -0,0 +1,147 @@ +use crate::cmp::{max, min}; +use crate::io::prelude::*; +use crate::io::{ + copy, empty, repeat, sink, BufWriter, Empty, ReadBuf, Repeat, Result, SeekFrom, Sink, + DEFAULT_BUF_SIZE, +}; + +use crate::mem::MaybeUninit; + +#[test] +fn copy_copies() { + let mut r = repeat(0).take(4); + let mut w = sink(); + assert_eq!(copy(&mut r, &mut w).unwrap(), 4); + + let mut r = repeat(0).take(1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); +} + +struct ShortReader { + cap: usize, + read_size: usize, + observed_buffer: usize, +} + +impl Read for ShortReader { + fn read(&mut self, buf: &mut [u8]) -> Result<usize> { + let bytes = min(self.cap, self.read_size); + self.cap -= bytes; + self.observed_buffer = max(self.observed_buffer, buf.len()); + Ok(bytes) + } +} + +struct WriteObserver { + observed_buffer: usize, +} + +impl Write for WriteObserver { + fn write(&mut self, buf: &[u8]) -> Result<usize> { + self.observed_buffer = max(self.observed_buffer, buf.len()); + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<()> { + Ok(()) + } +} + +#[test] +fn copy_specializes_bufwriter() { + let cap = 117 * 1024; + let buf_sz = 16 * 1024; + let mut r = ShortReader { cap, observed_buffer: 0, read_size: 1337 }; + let mut w = BufWriter::with_capacity(buf_sz, WriteObserver { observed_buffer: 0 }); + assert_eq!( + copy(&mut r, &mut w).unwrap(), + cap as u64, + "expected the whole capacity to be copied" + ); + assert_eq!(r.observed_buffer, buf_sz, "expected a large buffer to be provided to the reader"); + assert!(w.get_mut().observed_buffer > DEFAULT_BUF_SIZE, "expected coalesced writes"); +} + +#[test] +fn sink_sinks() { + let mut s = sink(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.write(&[0]).unwrap(), 1); + assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); + assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); +} + +#[test] +fn empty_reads() { + let mut e = empty(); + 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); + + let mut buf = []; + let mut buf = ReadBuf::uninit(&mut buf); + e.read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); + + let mut buf = [MaybeUninit::uninit()]; + let mut buf = ReadBuf::uninit(&mut buf); + e.read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); + + let mut buf = [MaybeUninit::uninit(); 1024]; + let mut buf = ReadBuf::uninit(&mut buf); + e.read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); + + let mut buf = [MaybeUninit::uninit(); 1024]; + let mut buf = ReadBuf::uninit(&mut buf); + e.by_ref().read_buf(&mut buf).unwrap(); + assert_eq!(buf.filled_len(), 0); + assert_eq!(buf.initialized_len(), 0); +} + +#[test] +fn empty_seeks() { + let mut e = empty(); + assert!(matches!(e.seek(SeekFrom::Start(0)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::Start(1)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::Start(u64::MAX)), Ok(0))); + + assert!(matches!(e.seek(SeekFrom::End(i64::MIN)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::End(-1)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::End(0)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::End(1)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::End(i64::MAX)), Ok(0))); + + assert!(matches!(e.seek(SeekFrom::Current(i64::MIN)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::Current(-1)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::Current(0)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::Current(1)), Ok(0))); + assert!(matches!(e.seek(SeekFrom::Current(i64::MAX)), Ok(0))); +} + +#[test] +fn repeat_repeats() { + let mut r = repeat(4); + let mut b = [0; 1024]; + assert_eq!(r.read(&mut b).unwrap(), 1024); + assert!(b.iter().all(|b| *b == 4)); +} + +#[test] +fn take_some_bytes() { + assert_eq!(repeat(4).take(100).bytes().count(), 100); + assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); + assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); +} + +#[allow(dead_code)] +fn const_utils() { + const _: Empty = empty(); + const _: Repeat = repeat(b'c'); + const _: Sink = sink(); +} |