summaryrefslogtreecommitdiffstats
path: root/buffered-reader
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2018-01-01 22:31:27 +0100
committerNeal H. Walfield <neal@pep.foundation>2018-01-02 21:45:02 +0100
commit18f76fce2141a2db396bd914719918ffe92ea290 (patch)
treeb91f037f705b0f338a6330f87ed7e0c4c8a55ff5 /buffered-reader
parent9e8e5bf8f8e11b36164edda2473e112753e8101d (diff)
buffered_reader: Allow the user to store data in a BufferedReader.
- We want to associate some data with a BufferedReader instance. Because a BufferedReader points to another BufferedReader, we can't use a wrapper object. This change provides a mechanism to store any required data inside the actual `BufferedReader`. Note: this is a zero-cost abstraction. If no data needs to be stored, then there is no cost.
Diffstat (limited to 'buffered-reader')
-rw-r--r--buffered-reader/src/decompress.rs132
-rw-r--r--buffered-reader/src/generic.rs46
-rw-r--r--buffered-reader/src/lib.rs40
-rw-r--r--buffered-reader/src/limitor.rs60
-rw-r--r--buffered-reader/src/memory.rs43
5 files changed, 258 insertions, 63 deletions
diff --git a/buffered-reader/src/decompress.rs b/buffered-reader/src/decompress.rs
index 648037fc..0bad2e48 100644
--- a/buffered-reader/src/decompress.rs
+++ b/buffered-reader/src/decompress.rs
@@ -7,25 +7,37 @@ use bzip2::read::BzDecoder;
use super::*;
-pub struct BufferedReaderDeflate<R: BufferedReader> {
- reader: BufferedReaderGeneric<DeflateDecoder<R>>,
+pub struct BufferedReaderDeflate<R: BufferedReader<C>, C> {
+ reader: BufferedReaderGeneric<DeflateDecoder<R>, C>,
}
-impl <R: BufferedReader> BufferedReaderDeflate<R> {
- pub fn new(reader: R) -> BufferedReaderDeflate<R> {
+impl <R: BufferedReader<()>> BufferedReaderDeflate<R, ()> {
+ /// Instantiate a new deflate decompression reader. `reader` is
+ /// the source to wrap.
+ pub fn new(reader: R) -> Self {
+ Self::with_cookie(reader, ())
+ }
+}
+
+impl <R: BufferedReader<C>, C> BufferedReaderDeflate<R, C> {
+ /// Like `new()`, but sets a cookie, which can be retrieved using
+ /// the `cookie_ref` and `cookie_mut` methods, and set using
+ /// the `cookie_set` method.
+ pub fn with_cookie(reader: R, cookie: C) -> Self {
BufferedReaderDeflate {
- reader: BufferedReaderGeneric::new(DeflateDecoder::new(reader), None)
+ reader: BufferedReaderGeneric::with_cookie(
+ DeflateDecoder::new(reader), None, cookie),
}
}
}
-impl<R: BufferedReader> io::Read for BufferedReaderDeflate<R> {
+impl<R: BufferedReader<C>, C> io::Read for BufferedReaderDeflate<R, C> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
self.reader.read(buf)
}
}
-impl <R: BufferedReader> fmt::Debug for BufferedReaderDeflate<R> {
+impl <R: BufferedReader<C>, C> fmt::Debug for BufferedReaderDeflate<R, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BufferedReaderDeflate")
.field("reader", self.reader.reader.get_ref())
@@ -33,7 +45,8 @@ impl <R: BufferedReader> fmt::Debug for BufferedReaderDeflate<R> {
}
}
-impl<R: BufferedReader> BufferedReader for BufferedReaderDeflate<R> {
+impl<R: BufferedReader<C>, C> BufferedReader<C>
+ for BufferedReaderDeflate<R, C> {
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.reader.data(amount);
}
@@ -75,31 +88,56 @@ impl<R: BufferedReader> BufferedReader for BufferedReaderDeflate<R> {
return self.reader.steal_eof();
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>> where Self: 'b {
+ fn into_inner<'b>(self: Box<Self>)
+ -> Option<Box<BufferedReader<C> + 'b>> where Self: 'b {
// Strip the outer box.
Some(Box::new((*self).reader.reader.into_inner()))
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ self.reader.cookie_set(cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ self.reader.cookie_ref()
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ self.reader.cookie_mut()
+ }
}
-pub struct BufferedReaderZlib<R: BufferedReader> {
- reader: BufferedReaderGeneric<ZlibDecoder<R>>,
+pub struct BufferedReaderZlib<R: BufferedReader<C>, C> {
+ reader: BufferedReaderGeneric<ZlibDecoder<R>, C>,
}
-impl <R: BufferedReader> BufferedReaderZlib<R> {
- pub fn new(reader: R) -> BufferedReaderZlib<R> {
+impl <R: BufferedReader<()>> BufferedReaderZlib<R, ()> {
+ /// Instantiate a new zlib decompression reader. `reader` is
+ /// the source to wrap.
+ pub fn new(reader: R) -> Self {
+ Self::with_cookie(reader, ())
+ }
+}
+
+impl <R: BufferedReader<C>, C> BufferedReaderZlib<R, C> {
+ /// Like `new()`, but sets a cookie, which can be retrieved using
+ /// the `cookie_ref` and `cookie_mut` methods, and set using
+ /// the `cookie_set` method.
+ pub fn with_cookie(reader: R, cookie: C) -> Self {
BufferedReaderZlib {
- reader: BufferedReaderGeneric::new(ZlibDecoder::new(reader), None)
+ reader: BufferedReaderGeneric::with_cookie(
+ ZlibDecoder::new(reader), None, cookie),
}
}
}
-impl<R: BufferedReader> io::Read for BufferedReaderZlib<R> {
+impl<R: BufferedReader<C>, C> io::Read for BufferedReaderZlib<R, C> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
self.reader.read(buf)
}
}
-impl <R: BufferedReader> fmt::Debug for BufferedReaderZlib<R> {
+impl <R: BufferedReader<C>, C> fmt::Debug for BufferedReaderZlib<R, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BufferedReaderZlib")
.field("reader", self.reader.reader.get_ref())
@@ -107,7 +145,8 @@ impl <R: BufferedReader> fmt::Debug for BufferedReaderZlib<R> {
}
}
-impl<R: BufferedReader> BufferedReader for BufferedReaderZlib<R> {
+impl<R: BufferedReader<C>, C> BufferedReader<C>
+ for BufferedReaderZlib<R, C> {
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.reader.data(amount);
}
@@ -149,31 +188,56 @@ impl<R: BufferedReader> BufferedReader for BufferedReaderZlib<R> {
return self.reader.steal_eof();
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>> where Self: 'b {
+ fn into_inner<'b>(self: Box<Self>)
+ -> Option<Box<BufferedReader<C> + 'b>> where Self: 'b {
// Strip the outer box.
Some(Box::new((*self).reader.reader.into_inner()))
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ self.reader.cookie_set(cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ self.reader.cookie_ref()
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ self.reader.cookie_mut()
+ }
}
-pub struct BufferedReaderBzip<R: BufferedReader> {
- reader: BufferedReaderGeneric<BzDecoder<R>>,
+pub struct BufferedReaderBzip<R: BufferedReader<C>, C> {
+ reader: BufferedReaderGeneric<BzDecoder<R>, C>,
+}
+
+impl <R: BufferedReader<()>> BufferedReaderBzip<R, ()> {
+ /// Instantiate a new bzip decompression reader. `reader` is
+ /// the source to wrap.
+ pub fn new(reader: R) -> Self {
+ Self::with_cookie(reader, ())
+ }
}
-impl <R: BufferedReader> BufferedReaderBzip<R> {
- pub fn new(reader: R) -> BufferedReaderBzip<R> {
+impl <R: BufferedReader<C>, C> BufferedReaderBzip<R, C> {
+ /// Like `new()`, but sets a cookie, which can be retrieved using
+ /// the `cookie_ref` and `cookie_mut` methods, and set using
+ /// the `cookie_set` method.
+ pub fn with_cookie(reader: R, cookie: C) -> Self {
BufferedReaderBzip {
- reader: BufferedReaderGeneric::new(BzDecoder::new(reader), None)
+ reader: BufferedReaderGeneric::with_cookie(
+ BzDecoder::new(reader), None, cookie),
}
}
}
-impl<R: BufferedReader> io::Read for BufferedReaderBzip<R> {
+impl<R: BufferedReader<C>, C> io::Read for BufferedReaderBzip<R, C> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
self.reader.read(buf)
}
}
-impl <R: BufferedReader> fmt::Debug for BufferedReaderBzip<R> {
+impl <R: BufferedReader<C>, C> fmt::Debug for BufferedReaderBzip<R, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BufferedReaderBzip")
.field("reader", self.reader.reader.get_ref())
@@ -181,7 +245,7 @@ impl <R: BufferedReader> fmt::Debug for BufferedReaderBzip<R> {
}
}
-impl<R: BufferedReader> BufferedReader for BufferedReaderBzip<R> {
+impl<R: BufferedReader<C>, C> BufferedReader<C> for BufferedReaderBzip<R, C> {
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.reader.data(amount);
}
@@ -223,8 +287,22 @@ impl<R: BufferedReader> BufferedReader for BufferedReaderBzip<R> {
return self.reader.steal_eof();
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>> where Self: 'b {
+ fn into_inner<'b>(self: Box<Self>)
+ -> Option<Box<BufferedReader<C> + 'b>> where Self: 'b {
// Strip the outer box.
Some(Box::new((*self).reader.reader.into_inner()))
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ self.reader.cookie_set(cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ self.reader.cookie_ref()
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ self.reader.cookie_mut()
+ }
}
+
diff --git a/buffered-reader/src/generic.rs b/buffered-reader/src/generic.rs
index 92ed6151..b8a0ad25 100644
--- a/buffered-reader/src/generic.rs
+++ b/buffered-reader/src/generic.rs
@@ -9,7 +9,7 @@ use super::*;
/// source that implements the `Read` trait. This is sufficient when
/// reading from a file, and it even works with a `&[u8]` (but
/// `BufferedReaderMemory` is more efficient).
-pub struct BufferedReaderGeneric<T: io::Read> {
+pub struct BufferedReaderGeneric<T: io::Read, C> {
buffer: Option<Box<[u8]>>,
// The next byte to read in the buffer.
cursor: usize,
@@ -22,9 +22,12 @@ pub struct BufferedReaderGeneric<T: io::Read> {
saw_eof: bool,
// The last error that we encountered, but have not yet returned.
error: Option<io::Error>,
+
+ // The user settable cookie.
+ cookie: C,
}
-impl<T: io::Read> fmt::Debug for BufferedReaderGeneric<T> {
+impl<T: io::Read, C> fmt::Debug for BufferedReaderGeneric<T, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buffered_data = if let Some(ref buffer) = self.buffer {
buffer.len() - self.cursor
@@ -41,13 +44,23 @@ impl<T: io::Read> fmt::Debug for BufferedReaderGeneric<T> {
}
}
-impl<T: io::Read> BufferedReaderGeneric<T> {
+impl<T: io::Read> BufferedReaderGeneric<T, ()> {
/// Instantiate a new generic reader. `reader` is the source to
/// wrap. `preferred_chuck_size` is the preferred chuck size. If
/// None, then the default will be used, which is usually what you
/// want.
- pub fn new(reader: T, preferred_chunk_size: Option<usize>)
- -> BufferedReaderGeneric<T> {
+ pub fn new(reader: T, preferred_chunk_size: Option<usize>) -> Self {
+ Self::with_cookie(reader, preferred_chunk_size, ())
+ }
+}
+
+impl<T: io::Read, C> BufferedReaderGeneric<T, C> {
+ /// Like `new()`, but sets a cookie, which can be retrieved using
+ /// the `cookie_ref` and `cookie_mut` methods, and set using
+ /// the `cookie_set` method.
+ pub fn with_cookie(
+ reader: T, preferred_chunk_size: Option<usize>, cookie: C)
+ -> Self {
BufferedReaderGeneric {
buffer: None,
cursor: 0,
@@ -57,6 +70,7 @@ impl<T: io::Read> BufferedReaderGeneric<T> {
reader: Box::new(reader),
saw_eof: false,
error: None,
+ cookie: cookie,
}
}
@@ -172,13 +186,13 @@ impl<T: io::Read> BufferedReaderGeneric<T> {
}
}
-impl<T: io::Read> io::Read for BufferedReaderGeneric<T> {
+impl<T: io::Read, C> io::Read for BufferedReaderGeneric<T, C> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
return buffered_reader_generic_read_impl(self, buf);
}
}
-impl<T: io::Read> BufferedReader for BufferedReaderGeneric<T> {
+impl<T: io::Read, C> BufferedReader<C> for BufferedReaderGeneric<T, C> {
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.data_helper(amount, false, false);
}
@@ -198,7 +212,7 @@ impl<T: io::Read> BufferedReader for BufferedReaderGeneric<T> {
if let Some(ref buffer) = self.buffer {
assert!(self.cursor <= buffer.len());
assert!(amount <= buffer.len() - self.cursor,
- "buffer contains just {} bytes, but you are trying to
+ "buffer contains just {} bytes, but you are trying to \
consume {} bytes. Did you forget to call data()?",
buffer.len() - self.cursor, amount);
@@ -218,10 +232,24 @@ impl<T: io::Read> BufferedReader for BufferedReaderGeneric<T> {
return self.data_helper(amount, true, true);
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader<C> + 'b>>
where Self: 'b {
None
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ use std::mem;
+
+ mem::replace(&mut self.cookie, cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ &self.cookie
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ &mut self.cookie
+ }
}
#[test]
diff --git a/buffered-reader/src/lib.rs b/buffered-reader/src/lib.rs
index a8b4ee3c..4738ed2c 100644
--- a/buffered-reader/src/lib.rs
+++ b/buffered-reader/src/lib.rs
@@ -31,7 +31,7 @@ const DEFAULT_BUF_SIZE: usize = 8 * 1024;
/// to first copy it to a local buffer. However, unlike `BufRead`,
/// `BufferedReader` allows the caller to ensure that the internal
/// buffer has a certain amount of data.
-pub trait BufferedReader : io::Read + fmt::Debug {
+pub trait BufferedReader<C> : io::Read + fmt::Debug {
/// Return the data in the internal buffer. Normally, the
/// returned buffer will contain *at least* `amount` bytes worth
/// of data. Less data may be returned if (and only if) the end
@@ -169,8 +169,17 @@ pub trait BufferedReader : io::Read + fmt::Debug {
Ok(())
}
- fn into_inner<'a>(self: Box<Self>) -> Option<Box<BufferedReader + 'a>>
+ fn into_inner<'a>(self: Box<Self>) -> Option<Box<BufferedReader<C> + 'a>>
where Self: 'a;
+
+ /// Sets the `BufferedReader`'s cookie and returns the old value.
+ fn cookie_set(&mut self, cookie: C) -> C;
+
+ /// Returns a reference to the `BufferedReader`'s cookie.
+ fn cookie_ref(&self) -> &C;
+
+ /// Returns a mutable reference to the `BufferedReader`'s cookie.
+ fn cookie_mut(&mut self) -> &mut C;
}
/// This function implements the `std::io::Read::read` method in terms
@@ -196,8 +205,8 @@ pub trait BufferedReader : io::Read + fmt::Debug {
///
/// but, alas, Rust doesn't like that ("error[E0119]: conflicting
/// implementations of trait `std::io::Read` for type `&mut _`").
-pub fn buffered_reader_generic_read_impl<T: BufferedReader>
- (bio: &mut T, buf: &mut [u8]) -> Result<usize, io::Error> {
+pub fn buffered_reader_generic_read_impl<T: BufferedReader<C>, C>
+ (bio: &mut T, buf: &mut [u8]) -> Result<usize, io::Error> {
match bio.data_consume(buf.len()) {
Ok(inner) => {
let amount = cmp::min(buf.len(), inner.len());
@@ -209,7 +218,7 @@ pub fn buffered_reader_generic_read_impl<T: BufferedReader>
}
/// Make a `Box<BufferedReader>` look like a BufferedReader.
-impl <'a> BufferedReader for Box<BufferedReader + 'a> {
+impl <'a, C> BufferedReader<C> for Box<BufferedReader<C> + 'a> {
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
return self.as_mut().data(amount);
}
@@ -255,18 +264,30 @@ impl <'a> BufferedReader for Box<BufferedReader + 'a> {
return self.as_mut().drop_eof();
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader<C> + 'b>>
where Self: 'b {
// Strip the outer box.
(*self).into_inner()
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ self.as_mut().cookie_set(cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ self.as_ref().cookie_ref()
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ self.as_mut().cookie_mut()
+ }
}
// The file was created as follows:
//
// for i in $(seq 0 9999); do printf "%04d\n" $i; done > buffered-reader-test.txt
#[cfg(test)]
-fn buffered_reader_test_data_check<'a, T: BufferedReader + 'a>(bio: &mut T) {
+fn buffered_reader_test_data_check<'a, T: BufferedReader<C> + 'a, C>(bio: &mut T) {
use std::str;
for i in 0 .. 10000 {
@@ -308,7 +329,8 @@ mod test {
// Try it again with a limitor.
{
let bio = BufferedReaderMemory::new(data);
- let mut bio2 = BufferedReaderLimitor::new(bio, (data.len() / 2) as u64);
+ let mut bio2 = BufferedReaderLimitor::new(
+ bio, (data.len() / 2) as u64);
let amount = {
bio2.data_eof().unwrap().len()
};
@@ -319,7 +341,7 @@ mod test {
}
#[cfg(test)]
- fn buffered_reader_read_test_aux<'a, T: BufferedReader + 'a>
+ fn buffered_reader_read_test_aux<'a, T: BufferedReader<C> + 'a, C>
(mut bio: T, data: &[u8]) {
let mut buffer = [0; 99];
diff --git a/buffered-reader/src/limitor.rs b/buffered-reader/src/limitor.rs
index 052ceb0d..04916ef6 100644
--- a/buffered-reader/src/limitor.rs
+++ b/buffered-reader/src/limitor.rs
@@ -5,29 +5,53 @@ use super::*;
/// A `BufferedReaderLimitor` limits the amount of data that can be
/// read from a `BufferedReader`.
-#[derive(Debug)]
-pub struct BufferedReaderLimitor<T: BufferedReader> {
+pub struct BufferedReaderLimitor<T: BufferedReader<C>, C> {
reader: T,
limit: u64,
+
+ cookie: C,
+}
+
+impl<T: BufferedReader<C>, C> fmt::Debug for BufferedReaderLimitor<T, C> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("BufferedReaderLimitor")
+ .field("limit", &self.limit)
+ .field("reader", &self.reader)
+ .finish()
+ }
+}
+
+impl<T: BufferedReader<()>> BufferedReaderLimitor<T, ()> {
+ /// Instantiate a new limitor. `reader` is the source to wrap.
+ /// `limit` is the maximum number of bytes that will be returned
+ /// from the source.
+ pub fn new(reader: T, limit: u64) -> Self {
+ Self::with_cookie(reader, limit, ())
+ }
}
-impl<T: BufferedReader> BufferedReaderLimitor<T> {
- pub fn new(reader: T, limit: u64) -> BufferedReaderLimitor<T> {
+impl<T: BufferedReader<C>, C> BufferedReaderLimitor<T, C> {
+ /// Like `new()`, but sets a cookie, which can be retrieved using
+ /// the `cookie_ref` and `cookie_mut` methods, and set using
+ /// the `cookie_set` method.
+ pub fn with_cookie(reader: T, limit: u64, cookie: C)
+ -> BufferedReaderLimitor<T, C> {
BufferedReaderLimitor {
reader: reader,
limit: limit,
+ cookie: cookie,
}
}
}
-impl<T: BufferedReader> io::Read for BufferedReaderLimitor<T> {
+impl<T: BufferedReader<C>, C> io::Read for BufferedReaderLimitor<T, C> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
let len = cmp::min(self.limit, buf.len() as u64) as usize;
return self.reader.read(&mut buf[0..len]);
}
}
-impl<T: BufferedReader> BufferedReader for BufferedReaderLimitor<T> {
+impl<T: BufferedReader<C>, C> BufferedReader<C> for BufferedReaderLimitor<T, C> {
/// Return the buffer. Ensure that it contains at least `amount`
/// bytes.
fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
@@ -75,10 +99,24 @@ impl<T: BufferedReader> BufferedReader for BufferedReaderLimitor<T> {
return result;
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader<C> + 'b>>
where Self: 'b {
Some(Box::new(self.reader))
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ use std::mem;
+
+ mem::replace(&mut self.cookie, cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ &self.cookie
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ &mut self.cookie
+ }
}
#[test]
@@ -87,7 +125,7 @@ fn buffered_reader_limitor_test() {
/* Add a single limitor. */
{
- let mut bio : Box<BufferedReader>
+ let mut bio : Box<BufferedReader<()>>
= Box::new(BufferedReaderMemory::new(data));
bio = {
@@ -125,15 +163,15 @@ fn buffered_reader_limitor_test() {
/* Try with two limitors where the first one imposes the real
* limit. */
{
- let mut bio : Box<BufferedReader>
+ let mut bio : Box<BufferedReader<()>>
= Box::new(BufferedReaderMemory::new(data));
bio = {
- let bio2 : Box<BufferedReader>
+ let bio2 : Box<BufferedReader<()>>
= Box::new(BufferedReaderLimitor::new(bio, 5));
// We limit to 15 bytes, but bio2 will still limit us to 5
// bytes.
- let mut bio3 : Box<BufferedReader>
+ let mut bio3 : Box<BufferedReader<()>>
= Box::new(BufferedReaderLimitor::new(bio2, 15));
{
let result = bio3.data(100).unwrap();
diff --git a/buffered-reader/src/memory.rs b/buffered-reader/src/memory.rs
index 8d387c49..2bdc0eb2 100644
--- a/buffered-reader/src/memory.rs
+++ b/buffered-reader/src/memory.rs
@@ -7,13 +7,16 @@ use std::io::{Error,ErrorKind};
use super::*;
/// A `BufferedReader` specialized for reading from memory buffers.
-pub struct BufferedReaderMemory<'a> {
+pub struct BufferedReaderMemory<'a, C> {
buffer: &'a [u8],
// The next byte to read in the buffer.
cursor: usize,
+
+ // The user settable cookie.
+ cookie: C,
}
-impl <'a> fmt::Debug for BufferedReaderMemory<'a> {
+impl<'a, C> fmt::Debug for BufferedReaderMemory<'a, C> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("BufferedReaderMemory")
.field("buffer (bytes)", &&self.buffer.len())
@@ -22,11 +25,23 @@ impl <'a> fmt::Debug for BufferedReaderMemory<'a> {
}
}
-impl<'a> BufferedReaderMemory<'a> {
- pub fn new(buffer: &'a [u8]) -> BufferedReaderMemory<'a> {
+impl<'a> BufferedReaderMemory<'a, ()> {
+ /// Instantiate a new memory-based reader. `buffer` contains the
+ /// reader's contents.
+ pub fn new(buffer: &'a [u8]) -> Self {
+ Self::with_cookie(buffer, ())
+ }
+}
+
+impl<'a, C> BufferedReaderMemory<'a, C> {
+ /// Like `new()`, but sets a cookie, which can be retrieved using
+ /// the `cookie_ref` and `cookie_mut` methods, and set using
+ /// the `cookie_set` method.
+ pub fn with_cookie(buffer: &'a [u8], cookie: C) -> Self {
BufferedReaderMemory {
buffer: buffer,
cursor: 0,
+ cookie: cookie,
}
}
@@ -37,7 +52,7 @@ impl<'a> BufferedReaderMemory<'a> {
}
}
-impl<'a> io::Read for BufferedReaderMemory<'a> {
+impl<'a, C> io::Read for BufferedReaderMemory<'a, C> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
let amount = cmp::min(buf.len(), self.buffer.len() - self.cursor);
buf[0..amount].copy_from_slice(
@@ -47,7 +62,7 @@ impl<'a> io::Read for BufferedReaderMemory<'a> {
}
}
-impl<'a> BufferedReader for BufferedReaderMemory<'a> {
+impl<'a, C> BufferedReader<C> for BufferedReaderMemory<'a, C> {
/// Return the buffer. Ensure that it contains at least `amount`
/// bytes.
fn data(&mut self, _amount: usize) -> Result<&[u8], io::Error> {
@@ -77,10 +92,24 @@ impl<'a> BufferedReader for BufferedReaderMemory<'a> {
return Ok(self.consume(amount));
}
- fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader + 'b>>
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<BufferedReader<C> + 'b>>
where Self: 'b {
None
}
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ use std::mem;
+
+ mem::replace(&mut self.cookie, cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ &self.cookie
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ &mut self.cookie
+ }
}
#[test]