// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::cmp; use std::io; use std::io::prelude::*; use std::mem; pub struct BufReader { inner: R, buf: Box<[u8]>, pos: usize, cap: usize, } impl ::std::fmt::Debug for BufReader where R: ::std::fmt::Debug, { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { fmt.debug_struct("BufReader") .field("reader", &self.inner) .field( "buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()), ) .finish() } } impl BufReader { pub fn new(inner: R) -> BufReader { BufReader::with_buf(vec![0; 32 * 1024], inner) } pub fn with_buf(buf: Vec, inner: R) -> BufReader { BufReader { inner: inner, buf: buf.into_boxed_slice(), pos: 0, cap: 0, } } } impl BufReader { pub fn get_ref(&self) -> &R { &self.inner } pub fn get_mut(&mut self) -> &mut R { &mut self.inner } pub fn into_inner(self) -> R { self.inner } pub fn reset(&mut self, inner: R) -> R { self.pos = 0; self.cap = 0; mem::replace(&mut self.inner, inner) } } impl Read for BufReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { // If we don't have any buffered data and we're doing a massive read // (larger than our internal buffer), bypass our internal buffer // entirely. if self.pos == self.cap && buf.len() >= self.buf.len() { return self.inner.read(buf); } let nread = { let mut rem = self.fill_buf()?; rem.read(buf)? }; self.consume(nread); Ok(nread) } } impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { // If we've reached the end of our internal buffer then we need to fetch // some more data from the underlying reader. if self.pos == self.cap { self.cap = self.inner.read(&mut self.buf)?; self.pos = 0; } Ok(&self.buf[self.pos..self.cap]) } fn consume(&mut self, amt: usize) { self.pos = cmp::min(self.pos + amt, self.cap); } }