]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2013 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. | |
1a4d82fc JJ |
10 | |
11 | //! Buffering wrappers for I/O traits | |
12 | ||
85aaf69f SL |
13 | use prelude::v1::*; |
14 | use io::prelude::*; | |
15 | ||
bd371182 | 16 | use marker::Reflect; |
1a4d82fc | 17 | use cmp; |
c34b1796 | 18 | use error; |
85aaf69f | 19 | use fmt; |
9346a6ac | 20 | use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; |
9cc50fc6 | 21 | use memchr; |
85aaf69f | 22 | |
c1a9b12d | 23 | /// The `BufReader` struct adds buffering to any reader. |
1a4d82fc | 24 | /// |
85aaf69f SL |
25 | /// It can be excessively inefficient to work directly with a `Read` instance. |
26 | /// For example, every call to `read` on `TcpStream` results in a system call. | |
27 | /// A `BufReader` performs large, infrequent reads on the underlying `Read` | |
28 | /// and maintains an in-memory buffer of the results. | |
62682a34 SL |
29 | /// |
30 | /// # Examples | |
31 | /// | |
c1a9b12d | 32 | /// ``` |
62682a34 SL |
33 | /// use std::io::prelude::*; |
34 | /// use std::io::BufReader; | |
35 | /// use std::fs::File; | |
36 | /// | |
37 | /// # fn foo() -> std::io::Result<()> { | |
38 | /// let mut f = try!(File::open("log.txt")); | |
39 | /// let mut reader = BufReader::new(f); | |
40 | /// | |
41 | /// let mut line = String::new(); | |
42 | /// let len = try!(reader.read_line(&mut line)); | |
43 | /// println!("First line is {} bytes long", len); | |
44 | /// # Ok(()) | |
45 | /// # } | |
46 | /// ``` | |
c34b1796 | 47 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 48 | pub struct BufReader<R> { |
1a4d82fc | 49 | inner: R, |
7453a54e | 50 | buf: Box<[u8]>, |
c34b1796 AL |
51 | pos: usize, |
52 | cap: usize, | |
1a4d82fc JJ |
53 | } |
54 | ||
85aaf69f | 55 | impl<R: Read> BufReader<R> { |
c1a9b12d SL |
56 | /// Creates a new `BufReader` with a default buffer capacity. |
57 | /// | |
58 | /// # Examples | |
59 | /// | |
60 | /// ``` | |
61 | /// use std::io::BufReader; | |
62 | /// use std::fs::File; | |
63 | /// | |
64 | /// # fn foo() -> std::io::Result<()> { | |
65 | /// let mut f = try!(File::open("log.txt")); | |
66 | /// let mut reader = BufReader::new(f); | |
67 | /// # Ok(()) | |
68 | /// # } | |
69 | /// ``` | |
c34b1796 | 70 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
71 | pub fn new(inner: R) -> BufReader<R> { |
72 | BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) | |
1a4d82fc JJ |
73 | } |
74 | ||
c1a9b12d SL |
75 | /// Creates a new `BufReader` with the specified buffer capacity. |
76 | /// | |
77 | /// # Examples | |
78 | /// | |
79 | /// Creating a buffer with ten bytes of capacity: | |
80 | /// | |
81 | /// ``` | |
82 | /// use std::io::BufReader; | |
83 | /// use std::fs::File; | |
84 | /// | |
85 | /// # fn foo() -> std::io::Result<()> { | |
86 | /// let mut f = try!(File::open("log.txt")); | |
87 | /// let mut reader = BufReader::with_capacity(10, f); | |
88 | /// # Ok(()) | |
89 | /// # } | |
90 | /// ``` | |
c34b1796 | 91 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
92 | pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> { |
93 | BufReader { | |
94 | inner: inner, | |
7453a54e | 95 | buf: vec![0; cap].into_boxed_slice(), |
c34b1796 AL |
96 | pos: 0, |
97 | cap: 0, | |
85aaf69f | 98 | } |
1a4d82fc JJ |
99 | } |
100 | ||
101 | /// Gets a reference to the underlying reader. | |
c1a9b12d SL |
102 | /// |
103 | /// It is inadvisable to directly read from the underlying reader. | |
104 | /// | |
105 | /// # Examples | |
106 | /// | |
107 | /// ``` | |
108 | /// use std::io::BufReader; | |
109 | /// use std::fs::File; | |
110 | /// | |
111 | /// # fn foo() -> std::io::Result<()> { | |
112 | /// let mut f1 = try!(File::open("log.txt")); | |
113 | /// let mut reader = BufReader::new(f1); | |
114 | /// | |
115 | /// let f2 = reader.get_ref(); | |
116 | /// # Ok(()) | |
117 | /// # } | |
118 | /// ``` | |
c34b1796 AL |
119 | #[stable(feature = "rust1", since = "1.0.0")] |
120 | pub fn get_ref(&self) -> &R { &self.inner } | |
1a4d82fc JJ |
121 | |
122 | /// Gets a mutable reference to the underlying reader. | |
123 | /// | |
1a4d82fc | 124 | /// It is inadvisable to directly read from the underlying reader. |
c1a9b12d SL |
125 | /// |
126 | /// # Examples | |
127 | /// | |
128 | /// ``` | |
129 | /// use std::io::BufReader; | |
130 | /// use std::fs::File; | |
131 | /// | |
132 | /// # fn foo() -> std::io::Result<()> { | |
133 | /// let mut f1 = try!(File::open("log.txt")); | |
134 | /// let mut reader = BufReader::new(f1); | |
135 | /// | |
136 | /// let f2 = reader.get_mut(); | |
137 | /// # Ok(()) | |
138 | /// # } | |
139 | /// ``` | |
c34b1796 | 140 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
141 | pub fn get_mut(&mut self) -> &mut R { &mut self.inner } |
142 | ||
85aaf69f | 143 | /// Unwraps this `BufReader`, returning the underlying reader. |
1a4d82fc JJ |
144 | /// |
145 | /// Note that any leftover data in the internal buffer is lost. | |
c1a9b12d SL |
146 | /// |
147 | /// # Examples | |
148 | /// | |
149 | /// ``` | |
150 | /// use std::io::BufReader; | |
151 | /// use std::fs::File; | |
152 | /// | |
153 | /// # fn foo() -> std::io::Result<()> { | |
154 | /// let mut f1 = try!(File::open("log.txt")); | |
155 | /// let mut reader = BufReader::new(f1); | |
156 | /// | |
157 | /// let f2 = reader.into_inner(); | |
158 | /// # Ok(()) | |
159 | /// # } | |
160 | /// ``` | |
c34b1796 | 161 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
162 | pub fn into_inner(self) -> R { self.inner } |
163 | } | |
164 | ||
c34b1796 | 165 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
166 | impl<R: Read> Read for BufReader<R> { |
167 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
168 | // If we don't have any buffered data and we're doing a massive read | |
169 | // (larger than our internal buffer), bypass our internal buffer | |
170 | // entirely. | |
c34b1796 | 171 | if self.pos == self.cap && buf.len() >= self.buf.len() { |
85aaf69f | 172 | return self.inner.read(buf); |
1a4d82fc | 173 | } |
c34b1796 | 174 | let nread = { |
54a0048b SL |
175 | let mut rem = self.fill_buf()?; |
176 | rem.read(buf)? | |
c34b1796 AL |
177 | }; |
178 | self.consume(nread); | |
179 | Ok(nread) | |
85aaf69f SL |
180 | } |
181 | } | |
182 | ||
c34b1796 | 183 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
184 | impl<R: Read> BufRead for BufReader<R> { |
185 | fn fill_buf(&mut self) -> io::Result<&[u8]> { | |
186 | // If we've reached the end of our internal buffer then we need to fetch | |
187 | // some more data from the underlying reader. | |
c34b1796 | 188 | if self.pos == self.cap { |
54a0048b | 189 | self.cap = self.inner.read(&mut self.buf)?; |
c34b1796 | 190 | self.pos = 0; |
85aaf69f | 191 | } |
c34b1796 | 192 | Ok(&self.buf[self.pos..self.cap]) |
1a4d82fc JJ |
193 | } |
194 | ||
c34b1796 AL |
195 | fn consume(&mut self, amt: usize) { |
196 | self.pos = cmp::min(self.pos + amt, self.cap); | |
1a4d82fc JJ |
197 | } |
198 | } | |
199 | ||
85aaf69f SL |
200 | #[stable(feature = "rust1", since = "1.0.0")] |
201 | impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug { | |
202 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | |
c34b1796 AL |
203 | fmt.debug_struct("BufReader") |
204 | .field("reader", &self.inner) | |
205 | .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) | |
206 | .finish() | |
1a4d82fc JJ |
207 | } |
208 | } | |
209 | ||
bd371182 | 210 | #[stable(feature = "rust1", since = "1.0.0")] |
9346a6ac AL |
211 | impl<R: Seek> Seek for BufReader<R> { |
212 | /// Seek to an offset, in bytes, in the underlying reader. | |
213 | /// | |
214 | /// The position used for seeking with `SeekFrom::Current(_)` is the | |
215 | /// position the underlying reader would be at if the `BufReader` had no | |
216 | /// internal buffer. | |
217 | /// | |
218 | /// Seeking always discards the internal buffer, even if the seek position | |
219 | /// would otherwise fall within it. This guarantees that calling | |
220 | /// `.unwrap()` immediately after a seek yields the underlying reader at | |
221 | /// the same position. | |
222 | /// | |
223 | /// See `std::io::Seek` for more details. | |
224 | /// | |
225 | /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` | |
226 | /// where `n` minus the internal buffer length underflows an `i64`, two | |
227 | /// seeks will be performed instead of one. If the second seek returns | |
228 | /// `Err`, the underlying reader will be left at the same position it would | |
229 | /// have if you seeked to `SeekFrom::Current(0)`. | |
230 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
231 | let result: u64; | |
232 | if let SeekFrom::Current(n) = pos { | |
233 | let remainder = (self.cap - self.pos) as i64; | |
234 | // it should be safe to assume that remainder fits within an i64 as the alternative | |
235 | // means we managed to allocate 8 ebibytes and that's absurd. | |
236 | // But it's not out of the realm of possibility for some weird underlying reader to | |
237 | // support seeking by i64::min_value() so we need to handle underflow when subtracting | |
238 | // remainder. | |
239 | if let Some(offset) = n.checked_sub(remainder) { | |
54a0048b | 240 | result = self.inner.seek(SeekFrom::Current(offset))?; |
9346a6ac AL |
241 | } else { |
242 | // seek backwards by our remainder, and then by the offset | |
54a0048b | 243 | self.inner.seek(SeekFrom::Current(-remainder))?; |
9346a6ac | 244 | self.pos = self.cap; // empty the buffer |
54a0048b | 245 | result = self.inner.seek(SeekFrom::Current(n))?; |
9346a6ac AL |
246 | } |
247 | } else { | |
248 | // Seeking with Start/End doesn't care about our buffer length. | |
54a0048b | 249 | result = self.inner.seek(pos)?; |
9346a6ac AL |
250 | } |
251 | self.pos = self.cap; // empty the buffer | |
252 | Ok(result) | |
253 | } | |
254 | } | |
255 | ||
c1a9b12d | 256 | /// Wraps a writer and buffers its output. |
1a4d82fc | 257 | /// |
c1a9b12d SL |
258 | /// It can be excessively inefficient to work directly with something that |
259 | /// implements `Write`. For example, every call to `write` on `TcpStream` | |
260 | /// results in a system call. A `BufWriter` keeps an in-memory buffer of data | |
261 | /// and writes it to an underlying writer in large, infrequent batches. | |
1a4d82fc | 262 | /// |
c34b1796 | 263 | /// The buffer will be written out when the writer is dropped. |
c1a9b12d SL |
264 | /// |
265 | /// # Examples | |
266 | /// | |
267 | /// Let's write the numbers one through ten to a `TcpStream`: | |
268 | /// | |
269 | /// ```no_run | |
270 | /// use std::io::prelude::*; | |
271 | /// use std::net::TcpStream; | |
272 | /// | |
273 | /// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); | |
274 | /// | |
275 | /// for i in 1..10 { | |
276 | /// stream.write(&[i]).unwrap(); | |
277 | /// } | |
278 | /// ``` | |
279 | /// | |
280 | /// Because we're not buffering, we write each one in turn, incurring the | |
281 | /// overhead of a system call per byte written. We can fix this with a | |
282 | /// `BufWriter`: | |
283 | /// | |
284 | /// ```no_run | |
285 | /// use std::io::prelude::*; | |
286 | /// use std::io::BufWriter; | |
287 | /// use std::net::TcpStream; | |
288 | /// | |
289 | /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
290 | /// | |
291 | /// for i in 1..10 { | |
292 | /// stream.write(&[i]).unwrap(); | |
293 | /// } | |
294 | /// ``` | |
295 | /// | |
296 | /// By wrapping the stream with a `BufWriter`, these ten writes are all grouped | |
297 | /// together by the buffer, and will all be written out in one system call when | |
298 | /// the `stream` is dropped. | |
c34b1796 AL |
299 | #[stable(feature = "rust1", since = "1.0.0")] |
300 | pub struct BufWriter<W: Write> { | |
1a4d82fc JJ |
301 | inner: Option<W>, |
302 | buf: Vec<u8>, | |
7453a54e SL |
303 | // #30888: If the inner writer panics in a call to write, we don't want to |
304 | // write the buffered data a second time in BufWriter's destructor. This | |
305 | // flag tells the Drop impl if it should skip the flush. | |
306 | panicked: bool, | |
1a4d82fc JJ |
307 | } |
308 | ||
c34b1796 AL |
309 | /// An error returned by `into_inner` which combines an error that |
310 | /// happened while writing out the buffer, and the buffered writer object | |
311 | /// which may be used to recover from the condition. | |
c1a9b12d SL |
312 | /// |
313 | /// # Examples | |
314 | /// | |
315 | /// ```no_run | |
316 | /// use std::io::BufWriter; | |
317 | /// use std::net::TcpStream; | |
318 | /// | |
319 | /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
320 | /// | |
321 | /// // do stuff with the stream | |
322 | /// | |
323 | /// // we want to get our `TcpStream` back, so let's try: | |
324 | /// | |
325 | /// let stream = match stream.into_inner() { | |
326 | /// Ok(s) => s, | |
327 | /// Err(e) => { | |
328 | /// // Here, e is an IntoInnerError | |
329 | /// panic!("An error occurred"); | |
330 | /// } | |
331 | /// }; | |
332 | /// ``` | |
85aaf69f | 333 | #[derive(Debug)] |
c34b1796 | 334 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
335 | pub struct IntoInnerError<W>(W, Error); |
336 | ||
337 | impl<W: Write> BufWriter<W> { | |
c1a9b12d SL |
338 | /// Creates a new `BufWriter` with a default buffer capacity. |
339 | /// | |
340 | /// # Examples | |
341 | /// | |
342 | /// ```no_run | |
343 | /// use std::io::BufWriter; | |
344 | /// use std::net::TcpStream; | |
345 | /// | |
346 | /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
347 | /// ``` | |
c34b1796 | 348 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
349 | pub fn new(inner: W) -> BufWriter<W> { |
350 | BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) | |
351 | } | |
352 | ||
c1a9b12d SL |
353 | /// Creates a new `BufWriter` with the specified buffer capacity. |
354 | /// | |
355 | /// # Examples | |
356 | /// | |
357 | /// Creating a buffer with a buffer of a hundred bytes. | |
358 | /// | |
359 | /// ```no_run | |
360 | /// use std::io::BufWriter; | |
361 | /// use std::net::TcpStream; | |
362 | /// | |
363 | /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); | |
364 | /// let mut buffer = BufWriter::with_capacity(100, stream); | |
365 | /// ``` | |
c34b1796 | 366 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
367 | pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> { |
368 | BufWriter { | |
1a4d82fc | 369 | inner: Some(inner), |
85aaf69f | 370 | buf: Vec::with_capacity(cap), |
7453a54e | 371 | panicked: false, |
1a4d82fc JJ |
372 | } |
373 | } | |
374 | ||
85aaf69f SL |
375 | fn flush_buf(&mut self) -> io::Result<()> { |
376 | let mut written = 0; | |
377 | let len = self.buf.len(); | |
378 | let mut ret = Ok(()); | |
379 | while written < len { | |
7453a54e SL |
380 | self.panicked = true; |
381 | let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); | |
382 | self.panicked = false; | |
383 | ||
384 | match r { | |
85aaf69f SL |
385 | Ok(0) => { |
386 | ret = Err(Error::new(ErrorKind::WriteZero, | |
c34b1796 | 387 | "failed to write the buffered data")); |
85aaf69f SL |
388 | break; |
389 | } | |
390 | Ok(n) => written += n, | |
c34b1796 | 391 | Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} |
85aaf69f | 392 | Err(e) => { ret = Err(e); break } |
1a4d82fc | 393 | |
85aaf69f SL |
394 | } |
395 | } | |
396 | if written > 0 { | |
c1a9b12d | 397 | self.buf.drain(..written); |
1a4d82fc | 398 | } |
85aaf69f | 399 | ret |
1a4d82fc JJ |
400 | } |
401 | ||
402 | /// Gets a reference to the underlying writer. | |
c1a9b12d SL |
403 | /// |
404 | /// # Examples | |
405 | /// | |
406 | /// ```no_run | |
407 | /// use std::io::BufWriter; | |
408 | /// use std::net::TcpStream; | |
409 | /// | |
410 | /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
411 | /// | |
412 | /// // we can use reference just like buffer | |
413 | /// let reference = buffer.get_ref(); | |
414 | /// ``` | |
c34b1796 | 415 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
416 | pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } |
417 | ||
c1a9b12d | 418 | /// Gets a mutable reference to the underlying writer. |
1a4d82fc | 419 | /// |
c1a9b12d | 420 | /// It is inadvisable to directly write to the underlying writer. |
1a4d82fc | 421 | /// |
c1a9b12d SL |
422 | /// # Examples |
423 | /// | |
424 | /// ```no_run | |
425 | /// use std::io::BufWriter; | |
426 | /// use std::net::TcpStream; | |
427 | /// | |
428 | /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
429 | /// | |
430 | /// // we can use reference just like buffer | |
431 | /// let reference = buffer.get_mut(); | |
432 | /// ``` | |
c34b1796 | 433 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc JJ |
434 | pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } |
435 | ||
85aaf69f | 436 | /// Unwraps this `BufWriter`, returning the underlying writer. |
1a4d82fc | 437 | /// |
c34b1796 | 438 | /// The buffer is written out before returning the writer. |
c1a9b12d SL |
439 | /// |
440 | /// # Examples | |
441 | /// | |
442 | /// ```no_run | |
443 | /// use std::io::BufWriter; | |
444 | /// use std::net::TcpStream; | |
445 | /// | |
446 | /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
447 | /// | |
448 | /// // unwrap the TcpStream and flush the buffer | |
449 | /// let stream = buffer.into_inner().unwrap(); | |
450 | /// ``` | |
c34b1796 | 451 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
452 | pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { |
453 | match self.flush_buf() { | |
454 | Err(e) => Err(IntoInnerError(self, e)), | |
455 | Ok(()) => Ok(self.inner.take().unwrap()) | |
456 | } | |
1a4d82fc JJ |
457 | } |
458 | } | |
459 | ||
c34b1796 | 460 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
461 | impl<W: Write> Write for BufWriter<W> { |
462 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
463 | if self.buf.len() + buf.len() > self.buf.capacity() { | |
54a0048b | 464 | self.flush_buf()?; |
1a4d82fc | 465 | } |
85aaf69f | 466 | if buf.len() >= self.buf.capacity() { |
7453a54e SL |
467 | self.panicked = true; |
468 | let r = self.inner.as_mut().unwrap().write(buf); | |
469 | self.panicked = false; | |
470 | r | |
1a4d82fc | 471 | } else { |
85aaf69f SL |
472 | let amt = cmp::min(buf.len(), self.buf.capacity()); |
473 | Write::write(&mut self.buf, &buf[..amt]) | |
1a4d82fc JJ |
474 | } |
475 | } | |
85aaf69f SL |
476 | fn flush(&mut self) -> io::Result<()> { |
477 | self.flush_buf().and_then(|()| self.get_mut().flush()) | |
478 | } | |
479 | } | |
1a4d82fc | 480 | |
85aaf69f | 481 | #[stable(feature = "rust1", since = "1.0.0")] |
c34b1796 | 482 | impl<W: Write> fmt::Debug for BufWriter<W> where W: fmt::Debug { |
85aaf69f | 483 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
c34b1796 AL |
484 | fmt.debug_struct("BufWriter") |
485 | .field("writer", &self.inner.as_ref().unwrap()) | |
486 | .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) | |
487 | .finish() | |
1a4d82fc JJ |
488 | } |
489 | } | |
490 | ||
bd371182 AL |
491 | #[stable(feature = "rust1", since = "1.0.0")] |
492 | impl<W: Write + Seek> Seek for BufWriter<W> { | |
9346a6ac AL |
493 | /// Seek to the offset, in bytes, in the underlying writer. |
494 | /// | |
495 | /// Seeking always writes out the internal buffer before seeking. | |
496 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
497 | self.flush_buf().and_then(|_| self.get_mut().seek(pos)) | |
498 | } | |
499 | } | |
500 | ||
92a42be0 | 501 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 502 | impl<W: Write> Drop for BufWriter<W> { |
1a4d82fc | 503 | fn drop(&mut self) { |
7453a54e | 504 | if self.inner.is_some() && !self.panicked { |
85aaf69f SL |
505 | // dtors should not panic, so we ignore a failed flush |
506 | let _r = self.flush_buf(); | |
1a4d82fc JJ |
507 | } |
508 | } | |
509 | } | |
510 | ||
85aaf69f | 511 | impl<W> IntoInnerError<W> { |
c1a9b12d | 512 | /// Returns the error which caused the call to `into_inner()` to fail. |
85aaf69f | 513 | /// |
c34b1796 | 514 | /// This error was returned when attempting to write the internal buffer. |
c1a9b12d SL |
515 | /// |
516 | /// # Examples | |
517 | /// | |
518 | /// ```no_run | |
519 | /// use std::io::BufWriter; | |
520 | /// use std::net::TcpStream; | |
521 | /// | |
522 | /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
523 | /// | |
524 | /// // do stuff with the stream | |
525 | /// | |
526 | /// // we want to get our `TcpStream` back, so let's try: | |
527 | /// | |
528 | /// let stream = match stream.into_inner() { | |
529 | /// Ok(s) => s, | |
530 | /// Err(e) => { | |
531 | /// // Here, e is an IntoInnerError, let's log the inner error. | |
532 | /// // | |
533 | /// // We'll just 'log' to stdout for this example. | |
534 | /// println!("{}", e.error()); | |
535 | /// | |
536 | /// panic!("An unexpected error occurred."); | |
537 | /// } | |
538 | /// }; | |
539 | /// ``` | |
c34b1796 | 540 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
541 | pub fn error(&self) -> &Error { &self.1 } |
542 | ||
c34b1796 | 543 | /// Returns the buffered writer instance which generated the error. |
85aaf69f | 544 | /// |
c34b1796 AL |
545 | /// The returned object can be used for error recovery, such as |
546 | /// re-inspecting the buffer. | |
c1a9b12d SL |
547 | /// |
548 | /// # Examples | |
549 | /// | |
550 | /// ```no_run | |
551 | /// use std::io::BufWriter; | |
552 | /// use std::net::TcpStream; | |
553 | /// | |
554 | /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); | |
555 | /// | |
556 | /// // do stuff with the stream | |
557 | /// | |
558 | /// // we want to get our `TcpStream` back, so let's try: | |
559 | /// | |
560 | /// let stream = match stream.into_inner() { | |
561 | /// Ok(s) => s, | |
562 | /// Err(e) => { | |
b039eaaf | 563 | /// // Here, e is an IntoInnerError, let's re-examine the buffer: |
c1a9b12d SL |
564 | /// let buffer = e.into_inner(); |
565 | /// | |
566 | /// // do stuff to try to recover | |
567 | /// | |
568 | /// // afterwards, let's just return the stream | |
569 | /// buffer.into_inner().unwrap() | |
570 | /// } | |
571 | /// }; | |
572 | /// ``` | |
c34b1796 | 573 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
574 | pub fn into_inner(self) -> W { self.0 } |
575 | } | |
576 | ||
c34b1796 AL |
577 | #[stable(feature = "rust1", since = "1.0.0")] |
578 | impl<W> From<IntoInnerError<W>> for Error { | |
579 | fn from(iie: IntoInnerError<W>) -> Error { iie.1 } | |
85aaf69f SL |
580 | } |
581 | ||
c34b1796 | 582 | #[stable(feature = "rust1", since = "1.0.0")] |
bd371182 | 583 | impl<W: Reflect + Send + fmt::Debug> error::Error for IntoInnerError<W> { |
c34b1796 AL |
584 | fn description(&self) -> &str { |
585 | error::Error::description(self.error()) | |
586 | } | |
85aaf69f SL |
587 | } |
588 | ||
c34b1796 | 589 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
590 | impl<W> fmt::Display for IntoInnerError<W> { |
591 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
592 | self.error().fmt(f) | |
593 | } | |
594 | } | |
595 | ||
c1a9b12d | 596 | /// Wraps a writer and buffers output to it, flushing whenever a newline |
85aaf69f | 597 | /// (`0x0a`, `'\n'`) is detected. |
1a4d82fc | 598 | /// |
c1a9b12d SL |
599 | /// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. |
600 | /// But it only does this batched write when it goes out of scope, or when the | |
601 | /// internal buffer is full. Sometimes, you'd prefer to write each line as it's | |
602 | /// completed, rather than the entire buffer at once. Enter `LineWriter`. It | |
603 | /// does exactly that. | |
604 | /// | |
605 | /// [bufwriter]: struct.BufWriter.html | |
606 | /// | |
607 | /// If there's still a partial line in the buffer when the `LineWriter` is | |
608 | /// dropped, it will flush those contents. | |
609 | /// | |
610 | /// # Examples | |
611 | /// | |
612 | /// We can use `LineWriter` to write one line at a time, significantly | |
613 | /// reducing the number of actual writes to the file. | |
614 | /// | |
615 | /// ``` | |
616 | /// use std::fs::File; | |
617 | /// use std::io::prelude::*; | |
618 | /// use std::io::LineWriter; | |
619 | /// | |
620 | /// # fn foo() -> std::io::Result<()> { | |
621 | /// let road_not_taken = b"I shall be telling this with a sigh | |
622 | /// Somewhere ages and ages hence: | |
623 | /// Two roads diverged in a wood, and I - | |
624 | /// I took the one less traveled by, | |
625 | /// And that has made all the difference."; | |
626 | /// | |
627 | /// let file = try!(File::create("poem.txt")); | |
628 | /// let mut file = LineWriter::new(file); | |
629 | /// | |
630 | /// for &byte in road_not_taken.iter() { | |
631 | /// file.write(&[byte]).unwrap(); | |
632 | /// } | |
633 | /// | |
634 | /// // let's check we did the right thing. | |
635 | /// let mut file = try!(File::open("poem.txt")); | |
636 | /// let mut contents = String::new(); | |
637 | /// | |
638 | /// try!(file.read_to_string(&mut contents)); | |
639 | /// | |
640 | /// assert_eq!(contents.as_bytes(), &road_not_taken[..]); | |
641 | /// # Ok(()) | |
642 | /// # } | |
643 | /// ``` | |
c34b1796 AL |
644 | #[stable(feature = "rust1", since = "1.0.0")] |
645 | pub struct LineWriter<W: Write> { | |
85aaf69f | 646 | inner: BufWriter<W>, |
1a4d82fc JJ |
647 | } |
648 | ||
85aaf69f | 649 | impl<W: Write> LineWriter<W> { |
c1a9b12d SL |
650 | /// Creates a new `LineWriter`. |
651 | /// | |
652 | /// # Examples | |
653 | /// | |
654 | /// ``` | |
655 | /// use std::fs::File; | |
656 | /// use std::io::LineWriter; | |
657 | /// | |
658 | /// # fn foo() -> std::io::Result<()> { | |
659 | /// let file = try!(File::create("poem.txt")); | |
660 | /// let file = LineWriter::new(file); | |
661 | /// # Ok(()) | |
662 | /// # } | |
663 | /// ``` | |
c34b1796 | 664 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f | 665 | pub fn new(inner: W) -> LineWriter<W> { |
1a4d82fc | 666 | // Lines typically aren't that long, don't use a giant buffer |
c34b1796 AL |
667 | LineWriter::with_capacity(1024, inner) |
668 | } | |
669 | ||
670 | /// Creates a new `LineWriter` with a specified capacity for the internal | |
671 | /// buffer. | |
c1a9b12d SL |
672 | /// |
673 | /// # Examples | |
674 | /// | |
675 | /// ``` | |
676 | /// use std::fs::File; | |
677 | /// use std::io::LineWriter; | |
678 | /// | |
679 | /// # fn foo() -> std::io::Result<()> { | |
680 | /// let file = try!(File::create("poem.txt")); | |
681 | /// let file = LineWriter::with_capacity(100, file); | |
682 | /// # Ok(()) | |
683 | /// # } | |
684 | /// ``` | |
c34b1796 AL |
685 | #[stable(feature = "rust1", since = "1.0.0")] |
686 | pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> { | |
687 | LineWriter { inner: BufWriter::with_capacity(cap, inner) } | |
1a4d82fc JJ |
688 | } |
689 | ||
690 | /// Gets a reference to the underlying writer. | |
c1a9b12d SL |
691 | /// |
692 | /// # Examples | |
693 | /// | |
694 | /// ``` | |
695 | /// use std::fs::File; | |
696 | /// use std::io::LineWriter; | |
697 | /// | |
698 | /// # fn foo() -> std::io::Result<()> { | |
699 | /// let file = try!(File::create("poem.txt")); | |
700 | /// let file = LineWriter::new(file); | |
701 | /// | |
702 | /// let reference = file.get_ref(); | |
703 | /// # Ok(()) | |
704 | /// # } | |
705 | /// ``` | |
c34b1796 AL |
706 | #[stable(feature = "rust1", since = "1.0.0")] |
707 | pub fn get_ref(&self) -> &W { self.inner.get_ref() } | |
708 | ||
709 | /// Gets a mutable reference to the underlying writer. | |
1a4d82fc | 710 | /// |
c34b1796 AL |
711 | /// Caution must be taken when calling methods on the mutable reference |
712 | /// returned as extra writes could corrupt the output stream. | |
c1a9b12d SL |
713 | /// |
714 | /// # Examples | |
715 | /// | |
716 | /// ``` | |
717 | /// use std::fs::File; | |
718 | /// use std::io::LineWriter; | |
719 | /// | |
720 | /// # fn foo() -> std::io::Result<()> { | |
721 | /// let file = try!(File::create("poem.txt")); | |
722 | /// let mut file = LineWriter::new(file); | |
723 | /// | |
724 | /// // we can use reference just like file | |
725 | /// let reference = file.get_mut(); | |
726 | /// # Ok(()) | |
727 | /// # } | |
728 | /// ``` | |
c34b1796 AL |
729 | #[stable(feature = "rust1", since = "1.0.0")] |
730 | pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } | |
1a4d82fc | 731 | |
85aaf69f | 732 | /// Unwraps this `LineWriter`, returning the underlying writer. |
1a4d82fc | 733 | /// |
c34b1796 | 734 | /// The internal buffer is written out before returning the writer. |
c1a9b12d SL |
735 | /// |
736 | /// # Examples | |
737 | /// | |
738 | /// ``` | |
739 | /// use std::fs::File; | |
740 | /// use std::io::LineWriter; | |
741 | /// | |
742 | /// # fn foo() -> std::io::Result<()> { | |
743 | /// let file = try!(File::create("poem.txt")); | |
744 | /// | |
745 | /// let writer: LineWriter<File> = LineWriter::new(file); | |
746 | /// | |
747 | /// let file: File = try!(writer.into_inner()); | |
748 | /// # Ok(()) | |
749 | /// # } | |
750 | /// ``` | |
c34b1796 | 751 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
752 | pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { |
753 | self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { | |
754 | IntoInnerError(LineWriter { inner: buf }, e) | |
755 | }) | |
756 | } | |
1a4d82fc JJ |
757 | } |
758 | ||
c34b1796 | 759 | #[stable(feature = "rust1", since = "1.0.0")] |
85aaf69f SL |
760 | impl<W: Write> Write for LineWriter<W> { |
761 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
9cc50fc6 | 762 | match memchr::memrchr(b'\n', buf) { |
1a4d82fc | 763 | Some(i) => { |
54a0048b SL |
764 | let n = self.inner.write(&buf[..i + 1])?; |
765 | if n != i + 1 || self.inner.flush().is_err() { | |
766 | // Do not return errors on partial writes. | |
767 | return Ok(n); | |
768 | } | |
85aaf69f | 769 | self.inner.write(&buf[i + 1..]).map(|i| n + i) |
1a4d82fc JJ |
770 | } |
771 | None => self.inner.write(buf), | |
772 | } | |
773 | } | |
774 | ||
85aaf69f | 775 | fn flush(&mut self) -> io::Result<()> { self.inner.flush() } |
1a4d82fc JJ |
776 | } |
777 | ||
85aaf69f | 778 | #[stable(feature = "rust1", since = "1.0.0")] |
c34b1796 | 779 | impl<W: Write> fmt::Debug for LineWriter<W> where W: fmt::Debug { |
85aaf69f | 780 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
c34b1796 AL |
781 | fmt.debug_struct("LineWriter") |
782 | .field("writer", &self.inner.inner) | |
783 | .field("buffer", | |
784 | &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity())) | |
785 | .finish() | |
85aaf69f SL |
786 | } |
787 | } | |
1a4d82fc | 788 | |
85aaf69f SL |
789 | #[cfg(test)] |
790 | mod tests { | |
791 | use prelude::v1::*; | |
792 | use io::prelude::*; | |
9cc50fc6 | 793 | use io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; |
7453a54e SL |
794 | use sync::atomic::{AtomicUsize, Ordering}; |
795 | use thread; | |
85aaf69f | 796 | use test; |
1a4d82fc JJ |
797 | |
798 | /// A dummy reader intended at testing short-reads propagation. | |
799 | pub struct ShortReader { | |
85aaf69f | 800 | lengths: Vec<usize>, |
1a4d82fc JJ |
801 | } |
802 | ||
85aaf69f SL |
803 | impl Read for ShortReader { |
804 | fn read(&mut self, _: &mut [u8]) -> io::Result<usize> { | |
1a4d82fc | 805 | if self.lengths.is_empty() { |
85aaf69f | 806 | Ok(0) |
1a4d82fc JJ |
807 | } else { |
808 | Ok(self.lengths.remove(0)) | |
809 | } | |
810 | } | |
811 | } | |
812 | ||
813 | #[test] | |
814 | fn test_buffered_reader() { | |
85aaf69f SL |
815 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; |
816 | let mut reader = BufReader::with_capacity(2, inner); | |
1a4d82fc JJ |
817 | |
818 | let mut buf = [0, 0, 0]; | |
819 | let nread = reader.read(&mut buf); | |
c34b1796 | 820 | assert_eq!(nread.unwrap(), 3); |
1a4d82fc JJ |
821 | let b: &[_] = &[5, 6, 7]; |
822 | assert_eq!(buf, b); | |
823 | ||
824 | let mut buf = [0, 0]; | |
825 | let nread = reader.read(&mut buf); | |
c34b1796 | 826 | assert_eq!(nread.unwrap(), 2); |
1a4d82fc JJ |
827 | let b: &[_] = &[0, 1]; |
828 | assert_eq!(buf, b); | |
829 | ||
830 | let mut buf = [0]; | |
831 | let nread = reader.read(&mut buf); | |
c34b1796 | 832 | assert_eq!(nread.unwrap(), 1); |
1a4d82fc JJ |
833 | let b: &[_] = &[2]; |
834 | assert_eq!(buf, b); | |
835 | ||
836 | let mut buf = [0, 0, 0]; | |
837 | let nread = reader.read(&mut buf); | |
c34b1796 | 838 | assert_eq!(nread.unwrap(), 1); |
1a4d82fc JJ |
839 | let b: &[_] = &[3, 0, 0]; |
840 | assert_eq!(buf, b); | |
841 | ||
842 | let nread = reader.read(&mut buf); | |
c34b1796 | 843 | assert_eq!(nread.unwrap(), 1); |
1a4d82fc JJ |
844 | let b: &[_] = &[4, 0, 0]; |
845 | assert_eq!(buf, b); | |
846 | ||
c34b1796 | 847 | assert_eq!(reader.read(&mut buf).unwrap(), 0); |
1a4d82fc JJ |
848 | } |
849 | ||
9346a6ac AL |
850 | #[test] |
851 | fn test_buffered_reader_seek() { | |
852 | let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; | |
853 | let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); | |
854 | ||
855 | assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); | |
856 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
857 | assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); | |
858 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); | |
859 | assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); | |
860 | assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); | |
861 | reader.consume(1); | |
862 | assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); | |
863 | } | |
864 | ||
865 | #[test] | |
866 | fn test_buffered_reader_seek_underflow() { | |
867 | // gimmick reader that yields its position modulo 256 for each byte | |
868 | struct PositionReader { | |
869 | pos: u64 | |
870 | } | |
871 | impl Read for PositionReader { | |
872 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { | |
873 | let len = buf.len(); | |
874 | for x in buf { | |
875 | *x = self.pos as u8; | |
876 | self.pos = self.pos.wrapping_add(1); | |
877 | } | |
878 | Ok(len) | |
879 | } | |
880 | } | |
881 | impl Seek for PositionReader { | |
882 | fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { | |
883 | match pos { | |
884 | SeekFrom::Start(n) => { | |
885 | self.pos = n; | |
886 | } | |
887 | SeekFrom::Current(n) => { | |
888 | self.pos = self.pos.wrapping_add(n as u64); | |
889 | } | |
890 | SeekFrom::End(n) => { | |
891 | self.pos = u64::max_value().wrapping_add(n as u64); | |
892 | } | |
893 | } | |
894 | Ok(self.pos) | |
895 | } | |
896 | } | |
897 | ||
898 | let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); | |
899 | assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); | |
900 | assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5)); | |
901 | assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); | |
902 | // the following seek will require two underlying seeks | |
903 | let expected = 9223372036854775802; | |
904 | assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); | |
905 | assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); | |
906 | // seeking to 0 should empty the buffer. | |
907 | assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); | |
908 | assert_eq!(reader.get_ref().pos, expected); | |
909 | } | |
910 | ||
1a4d82fc JJ |
911 | #[test] |
912 | fn test_buffered_writer() { | |
913 | let inner = Vec::new(); | |
85aaf69f | 914 | let mut writer = BufWriter::with_capacity(2, inner); |
1a4d82fc JJ |
915 | |
916 | writer.write(&[0, 1]).unwrap(); | |
85aaf69f | 917 | assert_eq!(*writer.get_ref(), [0, 1]); |
1a4d82fc JJ |
918 | |
919 | writer.write(&[2]).unwrap(); | |
85aaf69f | 920 | assert_eq!(*writer.get_ref(), [0, 1]); |
1a4d82fc JJ |
921 | |
922 | writer.write(&[3]).unwrap(); | |
85aaf69f | 923 | assert_eq!(*writer.get_ref(), [0, 1]); |
1a4d82fc JJ |
924 | |
925 | writer.flush().unwrap(); | |
85aaf69f | 926 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); |
1a4d82fc JJ |
927 | |
928 | writer.write(&[4]).unwrap(); | |
929 | writer.write(&[5]).unwrap(); | |
85aaf69f | 930 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); |
1a4d82fc JJ |
931 | |
932 | writer.write(&[6]).unwrap(); | |
85aaf69f | 933 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); |
1a4d82fc JJ |
934 | |
935 | writer.write(&[7, 8]).unwrap(); | |
85aaf69f | 936 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); |
1a4d82fc JJ |
937 | |
938 | writer.write(&[9, 10, 11]).unwrap(); | |
85aaf69f | 939 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); |
1a4d82fc JJ |
940 | |
941 | writer.flush().unwrap(); | |
85aaf69f | 942 | assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); |
1a4d82fc JJ |
943 | } |
944 | ||
945 | #[test] | |
946 | fn test_buffered_writer_inner_flushes() { | |
85aaf69f | 947 | let mut w = BufWriter::with_capacity(3, Vec::new()); |
1a4d82fc | 948 | w.write(&[0, 1]).unwrap(); |
85aaf69f SL |
949 | assert_eq!(*w.get_ref(), []); |
950 | let w = w.into_inner().unwrap(); | |
951 | assert_eq!(w, [0, 1]); | |
1a4d82fc JJ |
952 | } |
953 | ||
9346a6ac AL |
954 | #[test] |
955 | fn test_buffered_writer_seek() { | |
956 | let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); | |
957 | w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); | |
958 | w.write_all(&[6, 7]).unwrap(); | |
959 | assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); | |
960 | assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); | |
961 | assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); | |
962 | w.write_all(&[8, 9]).unwrap(); | |
963 | assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); | |
964 | } | |
965 | ||
1a4d82fc JJ |
966 | #[test] |
967 | fn test_read_until() { | |
85aaf69f SL |
968 | let inner: &[u8] = &[0, 1, 2, 1, 0]; |
969 | let mut reader = BufReader::with_capacity(2, inner); | |
970 | let mut v = Vec::new(); | |
971 | reader.read_until(0, &mut v).unwrap(); | |
972 | assert_eq!(v, [0]); | |
973 | v.truncate(0); | |
974 | reader.read_until(2, &mut v).unwrap(); | |
975 | assert_eq!(v, [1, 2]); | |
976 | v.truncate(0); | |
977 | reader.read_until(1, &mut v).unwrap(); | |
978 | assert_eq!(v, [1]); | |
979 | v.truncate(0); | |
980 | reader.read_until(8, &mut v).unwrap(); | |
981 | assert_eq!(v, [0]); | |
982 | v.truncate(0); | |
983 | reader.read_until(9, &mut v).unwrap(); | |
984 | assert_eq!(v, []); | |
1a4d82fc JJ |
985 | } |
986 | ||
54a0048b SL |
987 | #[test] |
988 | fn test_line_buffer_fail_flush() { | |
989 | // Issue #32085 | |
990 | struct FailFlushWriter<'a>(&'a mut Vec<u8>); | |
991 | ||
992 | impl<'a> Write for FailFlushWriter<'a> { | |
993 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { | |
994 | self.0.extend_from_slice(buf); | |
995 | Ok(buf.len()) | |
996 | } | |
997 | fn flush(&mut self) -> io::Result<()> { | |
998 | Err(io::Error::new(io::ErrorKind::Other, "flush failed")) | |
999 | } | |
1000 | } | |
1001 | ||
1002 | let mut buf = Vec::new(); | |
1003 | { | |
1004 | let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); | |
1005 | let to_write = b"abc\ndef"; | |
1006 | if let Ok(written) = writer.write(to_write) { | |
1007 | assert!(written < to_write.len(), "didn't flush on new line"); | |
1008 | // PASS | |
1009 | return; | |
1010 | } | |
1011 | } | |
1012 | assert!(buf.is_empty(), "write returned an error but wrote data"); | |
1013 | } | |
1014 | ||
1a4d82fc JJ |
1015 | #[test] |
1016 | fn test_line_buffer() { | |
85aaf69f | 1017 | let mut writer = LineWriter::new(Vec::new()); |
1a4d82fc | 1018 | writer.write(&[0]).unwrap(); |
85aaf69f | 1019 | assert_eq!(*writer.get_ref(), []); |
1a4d82fc | 1020 | writer.write(&[1]).unwrap(); |
85aaf69f | 1021 | assert_eq!(*writer.get_ref(), []); |
1a4d82fc | 1022 | writer.flush().unwrap(); |
85aaf69f | 1023 | assert_eq!(*writer.get_ref(), [0, 1]); |
1a4d82fc | 1024 | writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); |
85aaf69f | 1025 | assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); |
1a4d82fc | 1026 | writer.flush().unwrap(); |
85aaf69f | 1027 | assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); |
1a4d82fc | 1028 | writer.write(&[3, b'\n']).unwrap(); |
85aaf69f | 1029 | assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); |
1a4d82fc JJ |
1030 | } |
1031 | ||
1032 | #[test] | |
1033 | fn test_read_line() { | |
c34b1796 | 1034 | let in_buf: &[u8] = b"a\nb\nc"; |
85aaf69f SL |
1035 | let mut reader = BufReader::with_capacity(2, in_buf); |
1036 | let mut s = String::new(); | |
1037 | reader.read_line(&mut s).unwrap(); | |
1038 | assert_eq!(s, "a\n"); | |
1039 | s.truncate(0); | |
1040 | reader.read_line(&mut s).unwrap(); | |
1041 | assert_eq!(s, "b\n"); | |
1042 | s.truncate(0); | |
1043 | reader.read_line(&mut s).unwrap(); | |
1044 | assert_eq!(s, "c"); | |
1045 | s.truncate(0); | |
1046 | reader.read_line(&mut s).unwrap(); | |
1047 | assert_eq!(s, ""); | |
1a4d82fc JJ |
1048 | } |
1049 | ||
1050 | #[test] | |
1051 | fn test_lines() { | |
c34b1796 AL |
1052 | let in_buf: &[u8] = b"a\nb\nc"; |
1053 | let reader = BufReader::with_capacity(2, in_buf); | |
1a4d82fc | 1054 | let mut it = reader.lines(); |
c34b1796 AL |
1055 | assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); |
1056 | assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); | |
1057 | assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); | |
1058 | assert!(it.next().is_none()); | |
1a4d82fc JJ |
1059 | } |
1060 | ||
1061 | #[test] | |
1062 | fn test_short_reads() { | |
1063 | let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]}; | |
85aaf69f | 1064 | let mut reader = BufReader::new(inner); |
1a4d82fc | 1065 | let mut buf = [0, 0]; |
c34b1796 AL |
1066 | assert_eq!(reader.read(&mut buf).unwrap(), 0); |
1067 | assert_eq!(reader.read(&mut buf).unwrap(), 1); | |
1068 | assert_eq!(reader.read(&mut buf).unwrap(), 2); | |
1069 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
1070 | assert_eq!(reader.read(&mut buf).unwrap(), 1); | |
1071 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
1072 | assert_eq!(reader.read(&mut buf).unwrap(), 0); | |
1a4d82fc JJ |
1073 | } |
1074 | ||
1075 | #[test] | |
1076 | fn read_char_buffered() { | |
c34b1796 AL |
1077 | let buf = [195, 159]; |
1078 | let reader = BufReader::with_capacity(1, &buf[..]); | |
1079 | assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß'); | |
1a4d82fc JJ |
1080 | } |
1081 | ||
1082 | #[test] | |
1083 | fn test_chars() { | |
c34b1796 AL |
1084 | let buf = [195, 159, b'a']; |
1085 | let reader = BufReader::with_capacity(1, &buf[..]); | |
1a4d82fc | 1086 | let mut it = reader.chars(); |
c34b1796 AL |
1087 | assert_eq!(it.next().unwrap().unwrap(), 'ß'); |
1088 | assert_eq!(it.next().unwrap().unwrap(), 'a'); | |
1089 | assert!(it.next().is_none()); | |
1a4d82fc JJ |
1090 | } |
1091 | ||
1092 | #[test] | |
c34b1796 | 1093 | #[should_panic] |
1a4d82fc JJ |
1094 | fn dont_panic_in_drop_on_panicked_flush() { |
1095 | struct FailFlushWriter; | |
1096 | ||
85aaf69f SL |
1097 | impl Write for FailFlushWriter { |
1098 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) } | |
1099 | fn flush(&mut self) -> io::Result<()> { | |
1100 | Err(io::Error::last_os_error()) | |
1101 | } | |
1a4d82fc JJ |
1102 | } |
1103 | ||
1104 | let writer = FailFlushWriter; | |
85aaf69f | 1105 | let _writer = BufWriter::new(writer); |
1a4d82fc | 1106 | |
85aaf69f SL |
1107 | // If writer panics *again* due to the flush error then the process will |
1108 | // abort. | |
1a4d82fc JJ |
1109 | panic!(); |
1110 | } | |
1111 | ||
7453a54e SL |
1112 | #[test] |
1113 | fn panic_in_write_doesnt_flush_in_drop() { | |
1114 | static WRITES: AtomicUsize = AtomicUsize::new(0); | |
1115 | ||
1116 | struct PanicWriter; | |
1117 | ||
1118 | impl Write for PanicWriter { | |
1119 | fn write(&mut self, _: &[u8]) -> io::Result<usize> { | |
1120 | WRITES.fetch_add(1, Ordering::SeqCst); | |
1121 | panic!(); | |
1122 | } | |
1123 | fn flush(&mut self) -> io::Result<()> { Ok(()) } | |
1124 | } | |
1125 | ||
1126 | thread::spawn(|| { | |
1127 | let mut writer = BufWriter::new(PanicWriter); | |
1128 | let _ = writer.write(b"hello world"); | |
1129 | let _ = writer.flush(); | |
1130 | }).join().err().unwrap(); | |
1131 | ||
1132 | assert_eq!(WRITES.load(Ordering::SeqCst), 1); | |
1133 | } | |
1134 | ||
1a4d82fc | 1135 | #[bench] |
85aaf69f | 1136 | fn bench_buffered_reader(b: &mut test::Bencher) { |
1a4d82fc | 1137 | b.iter(|| { |
85aaf69f | 1138 | BufReader::new(io::empty()) |
1a4d82fc JJ |
1139 | }); |
1140 | } | |
1141 | ||
1142 | #[bench] | |
85aaf69f | 1143 | fn bench_buffered_writer(b: &mut test::Bencher) { |
1a4d82fc | 1144 | b.iter(|| { |
85aaf69f | 1145 | BufWriter::new(io::sink()) |
1a4d82fc JJ |
1146 | }); |
1147 | } | |
1a4d82fc | 1148 | } |