]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/common/io.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libstd / sys / common / io.rs
CommitLineData
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.
10use prelude::v1::*;
11use io;
12use io::ErrorKind;
13use io::Read;
14use 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.
26pub 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)]
55pub 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)]
95mod 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}