]>
Commit | Line | Data |
---|---|---|
c1a9b12d SL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | use prelude::v1::*; | |
11 | use io; | |
12 | use io::ErrorKind; | |
13 | use io::Read; | |
14 | use slice::from_raw_parts_mut; | |
15 | ||
16 | // Provides read_to_end functionality over an uninitialized buffer. | |
17 | // This function is unsafe because it calls the underlying | |
18 | // read function with a slice into uninitialized memory. The default | |
19 | // implementation of read_to_end for readers will zero out new memory in | |
20 | // the buf before passing it to read, but avoiding this zero can often | |
21 | // lead to a fairly significant performance win. | |
22 | // | |
23 | // Implementations using this method have to adhere to two guarantees: | |
24 | // * The implementation of read never reads the buffer provided. | |
25 | // * The implementation of read correctly reports how many bytes were written. | |
26 | pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> { | |
27 | ||
28 | let start_len = buf.len(); | |
29 | buf.reserve(16); | |
30 | ||
31 | // Always try to read into the empty space of the vector (from the length to the capacity). | |
32 | // If the vector ever fills up then we reserve an extra byte which should trigger the normal | |
33 | // reallocation routines for the vector, which will likely double the size. | |
34 | // | |
35 | // This function is similar to the read_to_end function in std::io, but the logic about | |
36 | // reservations and slicing is different enough that this is duplicated here. | |
37 | loop { | |
38 | if buf.len() == buf.capacity() { | |
39 | buf.reserve(1); | |
40 | } | |
41 | ||
42 | let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize), | |
43 | buf.capacity() - buf.len()); | |
44 | ||
45 | match r.read(buf_slice) { | |
46 | Ok(0) => { return Ok(buf.len() - start_len); } | |
47 | Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, | |
48 | Err(ref e) if e.kind() == ErrorKind::Interrupted => { } | |
49 | Err(e) => { return Err(e); } | |
50 | } | |
51 | } | |
52 | } | |
53 | ||
54a0048b SL |
54 | #[cfg(test)] |
55 | pub mod test { | |
56 | use prelude::v1::*; | |
57 | use path::{Path, PathBuf}; | |
58 | use env; | |
59 | use rand::{self, Rng}; | |
60 | use fs; | |
61 | ||
62 | pub struct TempDir(PathBuf); | |
63 | ||
64 | impl TempDir { | |
65 | pub fn join(&self, path: &str) -> PathBuf { | |
66 | let TempDir(ref p) = *self; | |
67 | p.join(path) | |
68 | } | |
69 | ||
70 | pub fn path<'a>(&'a self) -> &'a Path { | |
71 | let TempDir(ref p) = *self; | |
72 | p | |
73 | } | |
74 | } | |
75 | ||
76 | impl Drop for TempDir { | |
77 | fn drop(&mut self) { | |
78 | // Gee, seeing how we're testing the fs module I sure hope that we | |
79 | // at least implement this correctly! | |
80 | let TempDir(ref p) = *self; | |
81 | fs::remove_dir_all(p).unwrap(); | |
82 | } | |
83 | } | |
84 | ||
85 | pub fn tmpdir() -> TempDir { | |
86 | let p = env::temp_dir(); | |
87 | let mut r = rand::thread_rng(); | |
88 | let ret = p.join(&format!("rust-{}", r.next_u32())); | |
89 | fs::create_dir(&ret).unwrap(); | |
90 | TempDir(ret) | |
91 | } | |
92 | } | |
93 | ||
c1a9b12d SL |
94 | #[cfg(test)] |
95 | mod tests { | |
96 | use prelude::v1::*; | |
97 | use io::prelude::*; | |
98 | use super::*; | |
99 | use io; | |
100 | use io::{ErrorKind, Take, Repeat, repeat}; | |
c1a9b12d SL |
101 | use slice::from_raw_parts; |
102 | ||
103 | struct ErrorRepeat { | |
104 | lr: Take<Repeat> | |
105 | } | |
106 | ||
107 | fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat { | |
108 | ErrorRepeat { lr: repeat(byte).take(limit) } | |
109 | } | |
110 | ||
111 | impl Read for ErrorRepeat { | |
112 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
113 | let ret = self.lr.read(buf); | |
114 | if let Ok(0) = ret { | |
115 | return Err(io::Error::new(ErrorKind::Other, "")) | |
116 | } | |
117 | ret | |
118 | } | |
119 | } | |
120 | ||
121 | fn init_vec_data() -> Vec<u8> { | |
122 | let mut vec = vec![10u8; 200]; | |
123 | unsafe { vec.set_len(0); } | |
124 | vec | |
125 | } | |
126 | ||
127 | fn assert_all_eq(buf: &[u8], value: u8) { | |
128 | for n in buf { | |
129 | assert_eq!(*n, value); | |
130 | } | |
131 | } | |
132 | ||
133 | fn validate(buf: &Vec<u8>, good_read_len: usize) { | |
134 | assert_all_eq(buf, 1u8); | |
135 | let cap = buf.capacity(); | |
136 | let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize), | |
137 | cap - good_read_len) }; | |
138 | assert_all_eq(end_slice, 10u8); | |
139 | } | |
140 | ||
141 | #[test] | |
142 | fn read_to_end_uninit_error() { | |
143 | let mut er = error_repeat(1,100); | |
144 | let mut vec = init_vec_data(); | |
145 | if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } { | |
146 | validate(&vec, 100); | |
147 | } else { | |
148 | assert!(false); | |
149 | } | |
150 | } | |
151 | ||
152 | #[test] | |
153 | fn read_to_end_uninit_zero_len_vec() { | |
154 | let mut er = repeat(1).take(100); | |
155 | let mut vec = Vec::new(); | |
156 | let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; | |
157 | assert_all_eq(&vec, 1u8); | |
158 | assert_eq!(vec.len(), n); | |
159 | } | |
160 | ||
161 | #[test] | |
162 | fn read_to_end_uninit_good() { | |
163 | let mut er = repeat(1).take(100); | |
164 | let mut vec = init_vec_data(); | |
165 | let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; | |
166 | validate(&vec, 100); | |
167 | assert_eq!(vec.len(), n); | |
168 | } | |
169 | ||
170 | #[bench] | |
54a0048b | 171 | fn bench_uninitialized(b: &mut ::test::Bencher) { |
c1a9b12d SL |
172 | b.iter(|| { |
173 | let mut lr = repeat(1).take(10000000); | |
174 | let mut vec = Vec::with_capacity(1024); | |
9cc50fc6 | 175 | unsafe { read_to_end_uninitialized(&mut lr, &mut vec) } |
c1a9b12d SL |
176 | }); |
177 | } | |
178 | } |