1 use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}
;
2 use crate::mem
::MaybeUninit
;
4 /// Copies the entire contents of a reader into a writer.
6 /// This function will continuously read data from `reader` and then
7 /// write it into `writer` in a streaming fashion until `reader`
10 /// On success, the total number of bytes that were copied from
11 /// `reader` to `writer` is returned.
13 /// If you’re wanting to copy the contents of one file to another and you’re
14 /// working with filesystem paths, see the [`fs::copy`] function.
16 /// [`fs::copy`]: crate::fs::copy
20 /// This function will return an error immediately if any call to [`read`] or
21 /// [`write`] returns an error. All instances of [`ErrorKind::Interrupted`] are
22 /// handled by this function and the underlying operation is retried.
24 /// [`read`]: Read::read
25 /// [`write`]: Write::write
32 /// fn main() -> io::Result<()> {
33 /// let mut reader: &[u8] = b"hello";
34 /// let mut writer: Vec<u8> = vec![];
36 /// io::copy(&mut reader, &mut writer)?;
38 /// assert_eq!(&b"hello"[..], &writer[..]);
43 /// # Platform-specific behavior
45 /// On Linux (including Android), this function uses `copy_file_range(2)`,
46 /// `sendfile(2)` or `splice(2)` syscalls to move data directly between file
47 /// descriptors if possible.
49 /// Note that platform-specific behavior [may change in the future][changes].
51 /// [changes]: crate::io#platform-specific-behavior
52 #[stable(feature = "rust1", since = "1.0.0")]
53 pub fn copy
<R
: ?Sized
, W
: ?Sized
>(reader
: &mut R
, writer
: &mut W
) -> Result
<u64>
59 if #[cfg(any(target_os = "linux", target_os = "android"))] {
60 crate::sys
::kernel_copy
::copy_spec(reader
, writer
)
62 generic_copy(reader
, writer
)
67 /// The userspace read-write-loop implementation of `io::copy` that is used when
68 /// OS-specific specializations for copy offloading are not available or not applicable.
69 pub(crate) fn generic_copy
<R
: ?Sized
, W
: ?Sized
>(reader
: &mut R
, writer
: &mut W
) -> Result
<u64>
74 BufferedCopySpec
::copy_to(reader
, writer
)
77 /// Specialization of the read-write loop that either uses a stack buffer
78 /// or reuses the internal buffer of a BufWriter
79 trait BufferedCopySpec
: Write
{
80 fn copy_to
<R
: Read
+ ?Sized
>(reader
: &mut R
, writer
: &mut Self) -> Result
<u64>;
83 impl<W
: Write
+ ?Sized
> BufferedCopySpec
for W
{
84 default fn copy_to
<R
: Read
+ ?Sized
>(reader
: &mut R
, writer
: &mut Self) -> Result
<u64> {
85 stack_buffer_copy(reader
, writer
)
89 impl<I
: Write
> BufferedCopySpec
for BufWriter
<I
> {
90 fn copy_to
<R
: Read
+ ?Sized
>(reader
: &mut R
, writer
: &mut Self) -> Result
<u64> {
91 if writer
.capacity() < DEFAULT_BUF_SIZE
{
92 return stack_buffer_copy(reader
, writer
);
99 let buf
= writer
.buffer_mut();
100 let mut read_buf
: BorrowedBuf
<'_
> = buf
.spare_capacity_mut().into();
103 // SAFETY: init is either 0 or the init_len from the previous iteration.
104 read_buf
.set_init(init
);
107 if read_buf
.capacity() >= DEFAULT_BUF_SIZE
{
108 let mut cursor
= read_buf
.unfilled();
109 match reader
.read_buf(cursor
.reborrow()) {
111 let bytes_read
= cursor
.written();
117 init
= read_buf
.init_len() - bytes_read
;
118 len
+= bytes_read
as u64;
120 // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
121 unsafe { buf.set_len(buf.len() + bytes_read) }
;
123 // Read again if the buffer still has enough capacity, as BufWriter itself would do
124 // This will occur if the reader returns short reads
126 Err(ref e
) if e
.kind() == ErrorKind
::Interrupted
=> {}
127 Err(e
) => return Err(e
),
137 fn stack_buffer_copy
<R
: Read
+ ?Sized
, W
: Write
+ ?Sized
>(
141 let buf
: &mut [_
] = &mut [MaybeUninit
::uninit(); DEFAULT_BUF_SIZE
];
142 let mut buf
: BorrowedBuf
<'_
> = buf
.into();
147 match reader
.read_buf(buf
.unfilled()) {
149 Err(e
) if e
.kind() == ErrorKind
::Interrupted
=> continue,
150 Err(e
) => return Err(e
),
153 if buf
.filled().is_empty() {
157 len
+= buf
.filled().len() as u64;
158 writer
.write_all(buf
.filled())?
;