]>
Commit | Line | Data |
---|---|---|
5869c6ff | 1 | use super::{BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE}; |
fc512014 XL |
2 | use crate::mem::MaybeUninit; |
3 | ||
4 | /// Copies the entire contents of a reader into a writer. | |
5 | /// | |
6 | /// This function will continuously read data from `reader` and then | |
7 | /// write it into `writer` in a streaming fashion until `reader` | |
8 | /// returns EOF. | |
9 | /// | |
10 | /// On success, the total number of bytes that were copied from | |
11 | /// `reader` to `writer` is returned. | |
12 | /// | |
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. | |
15 | /// | |
16 | /// [`fs::copy`]: crate::fs::copy | |
17 | /// | |
18 | /// # Errors | |
19 | /// | |
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. | |
23 | /// | |
24 | /// [`read`]: Read::read | |
25 | /// [`write`]: Write::write | |
26 | /// | |
27 | /// # Examples | |
28 | /// | |
29 | /// ``` | |
30 | /// use std::io; | |
31 | /// | |
32 | /// fn main() -> io::Result<()> { | |
33 | /// let mut reader: &[u8] = b"hello"; | |
34 | /// let mut writer: Vec<u8> = vec![]; | |
35 | /// | |
36 | /// io::copy(&mut reader, &mut writer)?; | |
37 | /// | |
38 | /// assert_eq!(&b"hello"[..], &writer[..]); | |
39 | /// Ok(()) | |
40 | /// } | |
41 | /// ``` | |
42 | #[stable(feature = "rust1", since = "1.0.0")] | |
5869c6ff | 43 | pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64> |
fc512014 XL |
44 | where |
45 | R: Read, | |
46 | W: Write, | |
47 | { | |
48 | cfg_if::cfg_if! { | |
49 | if #[cfg(any(target_os = "linux", target_os = "android"))] { | |
50 | crate::sys::kernel_copy::copy_spec(reader, writer) | |
51 | } else { | |
52 | generic_copy(reader, writer) | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
5869c6ff XL |
57 | /// The userspace read-write-loop implementation of `io::copy` that is used when |
58 | /// OS-specific specializations for copy offloading are not available or not applicable. | |
59 | pub(crate) fn generic_copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64> | |
fc512014 XL |
60 | where |
61 | R: Read, | |
62 | W: Write, | |
63 | { | |
5869c6ff XL |
64 | BufferedCopySpec::copy_to(reader, writer) |
65 | } | |
66 | ||
67 | /// Specialization of the read-write loop that either uses a stack buffer | |
68 | /// or reuses the internal buffer of a BufWriter | |
69 | trait BufferedCopySpec: Write { | |
70 | fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64>; | |
71 | } | |
72 | ||
73 | impl<W: Write + ?Sized> BufferedCopySpec for W { | |
74 | default fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> { | |
75 | stack_buffer_copy(reader, writer) | |
76 | } | |
77 | } | |
78 | ||
79 | impl<I: Write> BufferedCopySpec for BufWriter<I> { | |
80 | fn copy_to<R: Read + ?Sized>(reader: &mut R, writer: &mut Self) -> Result<u64> { | |
81 | if writer.capacity() < DEFAULT_BUF_SIZE { | |
82 | return stack_buffer_copy(reader, writer); | |
83 | } | |
84 | ||
85 | // FIXME: #42788 | |
86 | // | |
87 | // - This creates a (mut) reference to a slice of | |
88 | // _uninitialized_ integers, which is **undefined behavior** | |
89 | // | |
90 | // - Only the standard library gets to soundly "ignore" this, | |
91 | // based on its privileged knowledge of unstable rustc | |
92 | // internals; | |
93 | unsafe { | |
94 | let spare_cap = writer.buffer_mut().spare_capacity_mut(); | |
95 | reader.initializer().initialize(MaybeUninit::slice_assume_init_mut(spare_cap)); | |
96 | } | |
97 | ||
98 | let mut len = 0; | |
99 | ||
100 | loop { | |
101 | let buf = writer.buffer_mut(); | |
102 | let spare_cap = buf.spare_capacity_mut(); | |
103 | ||
104 | if spare_cap.len() >= DEFAULT_BUF_SIZE { | |
105 | match reader.read(unsafe { MaybeUninit::slice_assume_init_mut(spare_cap) }) { | |
106 | Ok(0) => return Ok(len), // EOF reached | |
107 | Ok(bytes_read) => { | |
108 | assert!(bytes_read <= spare_cap.len()); | |
6a06907d | 109 | // SAFETY: The initializer contract guarantees that either it or `read` |
5869c6ff XL |
110 | // will have initialized these bytes. And we just checked that the number |
111 | // of bytes is within the buffer capacity. | |
112 | unsafe { buf.set_len(buf.len() + bytes_read) }; | |
113 | len += bytes_read as u64; | |
114 | // Read again if the buffer still has enough capacity, as BufWriter itself would do | |
115 | // This will occur if the reader returns short reads | |
116 | continue; | |
117 | } | |
118 | Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, | |
119 | Err(e) => return Err(e), | |
120 | } | |
121 | } | |
122 | ||
123 | writer.flush_buf()?; | |
124 | } | |
125 | } | |
126 | } | |
127 | ||
128 | fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>( | |
129 | reader: &mut R, | |
130 | writer: &mut W, | |
131 | ) -> Result<u64> { | |
132 | let mut buf = MaybeUninit::<[u8; DEFAULT_BUF_SIZE]>::uninit(); | |
fc512014 XL |
133 | // FIXME: #42788 |
134 | // | |
135 | // - This creates a (mut) reference to a slice of | |
136 | // _uninitialized_ integers, which is **undefined behavior** | |
137 | // | |
138 | // - Only the standard library gets to soundly "ignore" this, | |
139 | // based on its privileged knowledge of unstable rustc | |
140 | // internals; | |
141 | unsafe { | |
142 | reader.initializer().initialize(buf.assume_init_mut()); | |
143 | } | |
144 | ||
145 | let mut written = 0; | |
146 | loop { | |
147 | let len = match reader.read(unsafe { buf.assume_init_mut() }) { | |
148 | Ok(0) => return Ok(written), | |
149 | Ok(len) => len, | |
150 | Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, | |
151 | Err(e) => return Err(e), | |
152 | }; | |
153 | writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?; | |
154 | written += len as u64; | |
155 | } | |
156 | } |