summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@sequoia-pgp.org>2024-01-23 12:10:40 +0100
committerNeal H. Walfield <neal@sequoia-pgp.org>2024-01-23 14:37:35 +0100
commita73597bd0ae1ba251c3f3d19850083c751ef804d (patch)
tree7e25ba681b78afa50b3db442c01fb41abe2aaff9
parent04edffa4665da09e38e08ff0800a2c29e48924d1 (diff)
buffered-reader: Implement BufferedReader for &mut BufferedReader.
- Implement `BufferedReader` for `&mut T` where `T: BufferedReader`. - Implementing `BufferedReader` for `&mut T` where `T: BufferedReader` means that we can pass a mutable reference to a buffered reader where a buffered reader is required, and when the reference is dropped, we can continue to use the buffered reader.
-rw-r--r--buffered-reader/NEWS3
-rw-r--r--buffered-reader/src/lib.rs181
2 files changed, 184 insertions, 0 deletions
diff --git a/buffered-reader/NEWS b/buffered-reader/NEWS
index b115a958..1fdb6bd9 100644
--- a/buffered-reader/NEWS
+++ b/buffered-reader/NEWS
@@ -4,6 +4,9 @@
* Changes in 1.3.0
** New functionality
+ - Implement `BufferedReader` for `&mut T` where `T: BufferedReader`.
+* Changes in 1.3.0
+** New functionality
- File::new
- File::new_with_cookie
* Changes in 1.2.0
diff --git a/buffered-reader/src/lib.rs b/buffered-reader/src/lib.rs
index 4e5d167d..49e93ea3 100644
--- a/buffered-reader/src/lib.rs
+++ b/buffered-reader/src/lib.rs
@@ -940,6 +940,28 @@ pub trait BufferedReader<C> : io::Read + fmt::Debug + fmt::Display + Send + Sync
/// ```text
/// let inner = Box::new(br).into_inner();
/// ```
+ ///
+ /// Note: if `Self` is not actually owned, e.g., you passed a
+ /// reference, then this returns `None` as it is not possible to
+ /// consume the outer buffered reader. Consider:
+ ///
+ /// ```
+ /// # use buffered_reader::BufferedReader;
+ /// # use buffered_reader::Limitor;
+ /// # use buffered_reader::Memory;
+ /// #
+ /// # const DATA : &[u8] = b"01234567890123456789suffix";
+ /// #
+ /// let mut mem = Memory::new(DATA);
+ /// let mut limitor = Limitor::new(mem, 20);
+ /// let mut br = Box::new(&mut limitor);
+ /// // br doesn't owned limitor, so it can't consume it.
+ /// assert!(matches!(br.into_inner(), None));
+ ///
+ /// let mut mem = Memory::new(DATA);
+ /// let mut limitor = Limitor::new(mem, 20);
+ /// let mut br = Box::new(limitor);
+ /// assert!(matches!(br.into_inner(), Some(_)));
fn into_inner<'a>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'a>>
where Self: 'a;
@@ -1105,6 +1127,110 @@ impl <'a, C: fmt::Debug + Sync + Send> BufferedReader<C> for Box<dyn BufferedRea
}
}
+/// Make a `&mut T` where `T` implements `BufferedReader` look like a
+/// BufferedReader.
+impl <'a, T, C> BufferedReader<C> for &'a mut T
+where
+ T: BufferedReader<C>,
+ C: fmt::Debug + Sync + Send + 'a
+{
+ fn buffer(&self) -> &[u8] {
+ (**self).buffer()
+ }
+
+ fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ (**self).data(amount)
+ }
+
+ fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ (**self).data_hard(amount)
+ }
+
+ fn data_eof(&mut self) -> Result<&[u8], io::Error> {
+ (**self).data_eof()
+ }
+
+ fn consume(&mut self, amount: usize) -> &[u8] {
+ (**self).consume(amount)
+ }
+
+ fn data_consume(&mut self, amount: usize)
+ -> Result<&[u8], std::io::Error> {
+ (**self).data_consume(amount)
+ }
+
+ fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ (**self).data_consume_hard(amount)
+ }
+
+ fn consummated(&mut self) -> bool {
+ (**self).consummated()
+ }
+
+ fn read_be_u16(&mut self) -> Result<u16, std::io::Error> {
+ (**self).read_be_u16()
+ }
+
+ fn read_be_u32(&mut self) -> Result<u32, std::io::Error> {
+ (**self).read_be_u32()
+ }
+
+ fn read_to(&mut self, terminal: u8) -> Result<&[u8], std::io::Error>
+ {
+ (**self).read_to(terminal)
+ }
+
+ fn steal(&mut self, amount: usize) -> Result<Vec<u8>, std::io::Error> {
+ (**self).steal(amount)
+ }
+
+ fn steal_eof(&mut self) -> Result<Vec<u8>, std::io::Error> {
+ (**self).steal_eof()
+ }
+
+ fn drop_eof(&mut self) -> Result<bool, std::io::Error> {
+ (**self).drop_eof()
+ }
+
+ fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
+ (**self).get_mut()
+ }
+
+ fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
+ (**self).get_ref()
+ }
+
+ fn into_boxed<'b>(self) -> Box<dyn BufferedReader<C> + 'b>
+ where Self: 'b
+ {
+ Box::new(self)
+ }
+
+ fn as_boxed<'b>(self) -> Box<dyn BufferedReader<C> + 'b>
+ where Self: 'b
+ {
+ Box::new(self)
+ }
+
+ fn into_inner<'b>(self: Box<Self>) -> Option<Box<dyn BufferedReader<C> + 'b>>
+ where Self: 'b
+ {
+ None
+ }
+
+ fn cookie_set(&mut self, cookie: C) -> C {
+ (**self).cookie_set(cookie)
+ }
+
+ fn cookie_ref(&self) -> &C {
+ (**self).cookie_ref()
+ }
+
+ fn cookie_mut(&mut self) -> &mut C {
+ (**self).cookie_mut()
+ }
+}
+
// The file was created as follows:
//
// for i in $(seq 0 9999); do printf "%04d\n" $i; done > buffered-reader-test.txt
@@ -1297,4 +1423,59 @@ mod test {
assert_eq!(&sink[..], BUFFERED_READER_TEST_DATA);
Ok(())
}
+
+ #[test]
+ fn mutable_reference() {
+ use crate::Memory;
+ const DATA : &[u8] = b"01234567890123456789suffix";
+
+ /// API that consumes the memory reader.
+ fn parse_ten_bytes<B: BufferedReader<()>>(mut r: B) {
+ let d = r.data_consume_hard(10).unwrap();
+ assert!(d.len() >= 10);
+ assert_eq!(&d[..10], &DATA[..10]);
+ drop(r); // We consumed the reader.
+ }
+
+ let mut mem = Memory::new(DATA);
+ parse_ten_bytes(&mut mem);
+ parse_ten_bytes(&mut mem);
+ let suffix = mem.data_eof().unwrap();
+ assert_eq!(suffix, b"suffix");
+
+ let mut mem = Memory::new(DATA);
+ let mut limitor = Limitor::new(&mut mem, 20);
+ parse_ten_bytes(&mut limitor);
+ parse_ten_bytes(&mut limitor);
+ assert!(limitor.eof());
+ drop(limitor);
+ let suffix = mem.data_eof().unwrap();
+ assert_eq!(suffix, b"suffix");
+ }
+
+ #[test]
+ fn mutable_reference_inner() {
+ use crate::Memory;
+ const DATA : &[u8] = b"01234567890123456789suffix";
+
+ /// API that consumes the memory reader.
+ fn parse_ten_bytes<B: BufferedReader<()>>(mut r: B) {
+ let d = r.data_consume_hard(10).unwrap();
+ assert!(d.len() >= 10);
+ assert_eq!(&d[..10], &DATA[..10]);
+ drop(r); // We consumed the reader.
+ }
+
+ let mut mem = Memory::new(DATA);
+ let mut limitor = Limitor::new(&mut mem, 20);
+ parse_ten_bytes(&mut limitor);
+ parse_ten_bytes(&mut limitor);
+ assert!(limitor.eof());
+
+ // Check that get_mut returns `mem` by reading from the inner
+ // and checking that we get more data.
+ let mem = limitor.get_mut().expect("have inner");
+ let suffix = mem.data_eof().unwrap();
+ assert_eq!(suffix, b"suffix");
+ }
}