summaryrefslogtreecommitdiffstats
path: root/library/std/src/io/copy.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /library/std/src/io/copy.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/io/copy.rs')
-rw-r--r--library/std/src/io/copy.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index eafd078a7..4d51a719f 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,5 +1,7 @@
use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::alloc::Allocator;
+use crate::cmp;
+use crate::cmp::min;
use crate::collections::VecDeque;
use crate::io::IoSlice;
use crate::mem::MaybeUninit;
@@ -254,6 +256,78 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
}
}
+impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> {
+ fn buffer_size(&self) -> usize {
+ cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len())
+ }
+
+ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
+ let mut bytes = 0;
+
+ // avoid inflating empty/small vecs before we have determined that there's anything to read
+ if self.capacity() < DEFAULT_BUF_SIZE {
+ let stack_read_limit = DEFAULT_BUF_SIZE as u64;
+ bytes = stack_buffer_copy(&mut reader.take(stack_read_limit), self)?;
+ // fewer bytes than requested -> EOF reached
+ if bytes < stack_read_limit {
+ return Ok(bytes);
+ }
+ }
+
+ // don't immediately offer the vec's whole spare capacity, otherwise
+ // we might have to fully initialize it if the reader doesn't have a custom read_buf() impl
+ let mut max_read_size = DEFAULT_BUF_SIZE;
+
+ loop {
+ self.reserve(DEFAULT_BUF_SIZE);
+ let mut initialized_spare_capacity = 0;
+
+ loop {
+ let buf = self.spare_capacity_mut();
+ let read_size = min(max_read_size, buf.len());
+ let mut buf = BorrowedBuf::from(&mut buf[..read_size]);
+ // SAFETY: init is either 0 or the init_len from the previous iteration.
+ unsafe {
+ buf.set_init(initialized_spare_capacity);
+ }
+ match reader.read_buf(buf.unfilled()) {
+ Ok(()) => {
+ let bytes_read = buf.len();
+
+ // EOF
+ if bytes_read == 0 {
+ return Ok(bytes);
+ }
+
+ // the reader is returning short reads but it doesn't call ensure_init()
+ if buf.init_len() < buf.capacity() {
+ max_read_size = usize::MAX;
+ }
+ // the reader hasn't returned short reads so far
+ if bytes_read == buf.capacity() {
+ max_read_size *= 2;
+ }
+
+ initialized_spare_capacity = buf.init_len() - bytes_read;
+ bytes += bytes_read as u64;
+ // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
+ // and the number of read bytes can't exceed the spare capacity since
+ // that's what the buffer is borrowing from.
+ unsafe { self.set_len(self.len() + bytes_read) };
+
+ // spare capacity full, reserve more
+ if self.len() == self.capacity() {
+ break;
+ }
+ }
+ Err(e) if e.is_interrupted() => continue,
+ Err(e) => return Err(e),
+ }
+ }
+ }
+ }
+}
+
fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,