1 use crate::fs::OpenOptions;
4 use crate::io::SeekFrom;
5 use crate::io::{BufRead, Read, Seek, Write};
6 use crate::os::unix::io::AsRawFd;
7 use crate::sys_common::io::test::tmpdir;
10 fn copy_specialization() -> Result<()> {
11 use crate::io::{BufReader, BufWriter};
13 let tmp_path = tmpdir();
14 let source_path = tmp_path.join("copy-spec.source");
15 let sink_path = tmp_path.join("copy-spec.sink");
17 let result: Result<()> = try {
18 let mut source = crate::fs::OpenOptions::new()
24 source.write_all(b"abcdefghiklmnopqr")?;
25 source.seek(SeekFrom::Start(8))?;
26 let mut source = BufReader::with_capacity(8, source.take(5));
28 assert_eq!(source.buffer(), b"iklmn");
29 source.get_mut().set_limit(6);
30 source.get_mut().get_mut().seek(SeekFrom::Start(1))?; // "bcdefg"
31 let mut source = source.take(10); // "iklmnbcdef"
33 let mut sink = crate::fs::OpenOptions::new()
39 sink.write_all(b"000000")?;
40 let mut sink = BufWriter::with_capacity(5, sink);
41 sink.write_all(b"wxyz")?;
42 assert_eq!(sink.buffer(), b"wxyz");
44 let copied = crate::io::copy(&mut source, &mut sink)?;
45 assert_eq!(copied, 10, "copy obeyed limit imposed by Take");
46 assert_eq!(sink.buffer().len(), 0, "sink buffer was flushed");
47 assert_eq!(source.limit(), 0, "outer Take was exhausted");
48 assert_eq!(source.get_ref().buffer().len(), 0, "source buffer should be drained");
50 source.get_ref().get_ref().limit(),
52 "inner Take allowed reading beyond end of file, some bytes should be left"
55 let mut sink = sink.into_inner()?;
56 sink.seek(SeekFrom::Start(0))?;
57 let mut copied = Vec::new();
58 sink.read_to_end(&mut copied)?;
59 assert_eq!(&copied, b"000000wxyziklmnbcdef");
62 let rm1 = crate::fs::remove_file(source_path);
63 let rm2 = crate::fs::remove_file(sink_path);
65 result.and(rm1).and(rm2)
69 fn copies_append_mode_sink() -> Result<()> {
70 let tmp_path = tmpdir();
71 let source_path = tmp_path.join("copies_append_mode.source");
72 let sink_path = tmp_path.join("copies_append_mode.sink");
74 OpenOptions::new().create(true).truncate(true).write(true).read(true).open(&source_path)?;
75 write!(source, "not empty")?;
76 source.seek(SeekFrom::Start(0))?;
77 let mut sink = OpenOptions::new().create(true).append(true).open(&sink_path)?;
79 let copied = crate::io::copy(&mut source, &mut sink)?;
81 assert_eq!(copied, 9);
87 fn bench_file_to_file_copy(b: &mut test::Bencher) {
88 const BYTES: usize = 128 * 1024;
89 let temp_path = tmpdir();
90 let src_path = temp_path.join("file-copy-bench-src");
91 let mut src = crate::fs::OpenOptions::new()
98 src.write(&vec![0u8; BYTES]).unwrap();
100 let sink_path = temp_path.join("file-copy-bench-sink");
101 let mut sink = crate::fs::OpenOptions::new()
108 b.bytes = BYTES as u64;
110 src.seek(SeekFrom::Start(0)).unwrap();
111 sink.seek(SeekFrom::Start(0)).unwrap();
112 assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
117 fn bench_file_to_socket_copy(b: &mut test::Bencher) {
118 const BYTES: usize = 128 * 1024;
119 let temp_path = tmpdir();
120 let src_path = temp_path.join("pipe-copy-bench-src");
121 let mut src = OpenOptions::new()
128 src.write(&vec![0u8; BYTES]).unwrap();
130 let sink_drainer = crate::net::TcpListener::bind("localhost:0").unwrap();
131 let mut sink = crate::net::TcpStream::connect(sink_drainer.local_addr().unwrap()).unwrap();
132 let mut sink_drainer = sink_drainer.accept().unwrap().0;
134 crate::thread::spawn(move || {
135 let mut sink_buf = vec![0u8; 1024 * 1024];
137 sink_drainer.read(&mut sink_buf[..]).unwrap();
141 b.bytes = BYTES as u64;
143 src.seek(SeekFrom::Start(0)).unwrap();
144 assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
149 fn bench_file_to_uds_copy(b: &mut test::Bencher) {
150 const BYTES: usize = 128 * 1024;
151 let temp_path = tmpdir();
152 let src_path = temp_path.join("uds-copy-bench-src");
153 let mut src = OpenOptions::new()
160 src.write(&vec![0u8; BYTES]).unwrap();
162 let (mut sink, mut sink_drainer) = crate::os::unix::net::UnixStream::pair().unwrap();
164 crate::thread::spawn(move || {
165 let mut sink_buf = vec![0u8; 1024 * 1024];
167 sink_drainer.read(&mut sink_buf[..]).unwrap();
171 b.bytes = BYTES as u64;
173 src.seek(SeekFrom::Start(0)).unwrap();
174 assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
178 #[cfg(any(target_os = "linux", target_os = "android"))]
180 fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) {
181 use super::CopyResult;
182 use crate::io::ErrorKind;
183 use crate::process::{ChildStdin, ChildStdout};
184 use crate::sys_common::FromInner;
186 let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap();
188 let mut read_end = ChildStdout::from_inner(read_end);
189 let write_end = ChildStdin::from_inner(write_end);
191 let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap();
192 let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap();
194 let local_end = crate::sync::Arc::new(acceptor.accept().unwrap().0);
196 // the data flow in this benchmark:
198 // socket(tx) local_source
199 // remote_end (write) +--------> (splice to)
206 // remote_end (read) <---------+ (splice to) *
207 // socket(rx) local_end
209 // * benchmark loop using io::copy
211 crate::thread::spawn(move || {
212 let mut sink_buf = vec![0u8; 1024 * 1024];
213 remote_end.set_nonblocking(true).unwrap();
215 match remote_end.write(&mut sink_buf[..]) {
216 Err(err) if err.kind() == ErrorKind::WouldBlock => {}
219 err.expect("write failed");
222 match remote_end.read(&mut sink_buf[..]) {
223 Err(err) if err.kind() == ErrorKind::WouldBlock => {}
226 err.expect("read failed");
232 // check that splice works, otherwise the benchmark would hang
233 let probe = super::sendfile_splice(
234 super::SpliceMode::Splice,
235 local_end.as_raw_fd(),
236 write_end.as_raw_fd(),
241 CopyResult::Ended(1) => {
245 eprintln!("splice failed, skipping benchmark");
250 let local_source = local_end.clone();
251 crate::thread::spawn(move || {
253 super::sendfile_splice(
254 super::SpliceMode::Splice,
255 local_source.as_raw_fd(),
256 write_end.as_raw_fd(),
262 const BYTES: usize = 128 * 1024;
263 b.bytes = BYTES as u64;
267 io::copy(&mut (&mut read_end).take(BYTES as u64), &mut &*local_end).unwrap()