summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2022-06-10 10:40:00 +0200
committerJustus Winter <justus@sequoia-pgp.org>2022-06-10 11:15:40 +0200
commit323c0a3970f345bbadd96faf57c60d2b0a68ebf6 (patch)
treea31a5f2b0ddc56f832321340b3c492fcd87cce5f
parentb94042ccd52d69b7783986ac823098eda2ffe904 (diff)
buffered-reader: New buffered reader Mut.
- This is a non-owning mutable reference type for the buffered reader framework. It can be used to retain ownership of the reader when using interfaces that consume the reader.
-rw-r--r--buffered-reader/src/lib.rs2
-rw-r--r--buffered-reader/src/reference.rs208
2 files changed, 210 insertions, 0 deletions
diff --git a/buffered-reader/src/lib.rs b/buffered-reader/src/lib.rs
index 88e3fd9d..3b1736dc 100644
--- a/buffered-reader/src/lib.rs
+++ b/buffered-reader/src/lib.rs
@@ -243,6 +243,7 @@ mod reserve;
mod dup;
mod eof;
mod adapter;
+mod reference;
#[cfg(feature = "compression-deflate")]
mod decompress_deflate;
#[cfg(feature = "compression-bzip2")]
@@ -255,6 +256,7 @@ pub use self::reserve::Reserve;
pub use self::dup::Dup;
pub use self::eof::EOF;
pub use self::adapter::Adapter;
+pub use self::reference::Mut;
#[cfg(feature = "compression-deflate")]
pub use self::decompress_deflate::Deflate;
#[cfg(feature = "compression-deflate")]
diff --git a/buffered-reader/src/reference.rs b/buffered-reader/src/reference.rs
new file mode 100644
index 00000000..22d9dd89
--- /dev/null
+++ b/buffered-reader/src/reference.rs
@@ -0,0 +1,208 @@
+use std::io;
+use std::fmt;
+
+use crate::BufferedReader;
+
+/// References a `BufferedReader`.
+///
+/// This is a non-owning mutable reference type for the buffered
+/// reader framework. It can be used to retain ownership of the
+/// reader when using interfaces that consume the reader.
+#[derive(Debug)]
+pub struct Mut<'a, T, C>
+where
+ T: BufferedReader<C>,
+ C: Default + fmt::Debug + Sync + Send,
+{
+ cookie: C,
+ reader: &'a mut T,
+}
+
+// There is a bug in assert_send_and_sync that prevents us from
+// declaring multiple trait bounds on C. As a quick workaround, we
+// define a local alias that combines Default and Debug for the sole
+// benefit of the assert_send_and_sync macro.
+mod appease_macro {
+ pub(crate) trait DefaultDebug: Default + std::fmt::Debug {}
+
+ assert_send_and_sync!(super::Mut<'_, T, C>
+ where T: crate::BufferedReader<C>,
+ C: DefaultDebug);
+}
+
+impl<'a, T, C> fmt::Display for Mut<'a, T, C>
+where
+ T: BufferedReader<C>,
+ C: Default + fmt::Debug + Sync + Send,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Mut")
+ .finish()
+ }
+}
+
+impl<'a, T: BufferedReader<()>> Mut<'a, T, ()> {
+ /// Makes a new mutable reference.
+ ///
+ /// `reader` is the source to reference.
+ pub fn new(reader: &'a mut T) -> Self {
+ Self::with_cookie(reader, ())
+ }
+}
+
+impl<'a, T, C> Mut<'a, T, C>
+where
+ T: BufferedReader<C>,
+ C: Default + fmt::Debug + Sync + Send,
+{
+ /// Like [`Mut::new`], but sets a cookie.
+ ///
+ /// The cookie can be retrieved using the [`Mut::cookie_ref`] and
+ /// [`Mut::cookie_mut`] methods, and set using the
+ /// [`Mut::cookie_set`] method.
+ pub fn with_cookie(reader: &'a mut T, cookie: C)
+ -> Mut<T, C> {
+ Mut {
+ reader,
+ cookie,
+ }
+ }
+}
+
+impl<'a, T, C> io::Read for Mut<'a, T, C>
+where
+ T: BufferedReader<C>,
+ C: Default + fmt::Debug + Sync + Send,
+{
+ fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
+ self.reader.read(buf)
+ }
+}
+
+impl<'a, T, C> BufferedReader<C> for Mut<'a, T, C>
+where
+ T: BufferedReader<C>,
+ C: Default + fmt::Debug + Sync + Send,
+{
+ fn buffer(&self) -> &[u8] {
+ self.reader.buffer()
+ }
+
+ fn data(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ self.reader.data(amount)
+ }
+
+ fn data_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ self.reader.data_hard(amount)
+ }
+
+ fn data_eof(&mut self) -> Result<&[u8], io::Error> {
+ self.reader.data_eof()
+ }
+
+ fn consume(&mut self, amount: usize) -> &[u8] {
+ self.reader.consume(amount)
+ }
+
+ fn data_consume(&mut self, amount: usize)
+ -> Result<&[u8], std::io::Error> {
+ self.reader.data_consume(amount)
+ }
+
+ fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8], io::Error> {
+ self.reader.data_consume_hard(amount)
+ }
+
+ fn consummated(&mut self) -> bool {
+ self.reader.consummated()
+ }
+
+ fn read_be_u16(&mut self) -> Result<u16, std::io::Error> {
+ self.reader.read_be_u16()
+ }
+
+ fn read_be_u32(&mut self) -> Result<u32, std::io::Error> {
+ self.reader.read_be_u32()
+ }
+
+ fn read_to(&mut self, terminal: u8) -> Result<&[u8], std::io::Error>
+ {
+ self.reader.read_to(terminal)
+ }
+
+ fn steal(&mut self, amount: usize) -> Result<Vec<u8>, std::io::Error> {
+ self.reader.steal(amount)
+ }
+
+ fn steal_eof(&mut self) -> Result<Vec<u8>, std::io::Error> {
+ self.reader.steal_eof()
+ }
+
+ fn drop_eof(&mut self) -> Result<bool, std::io::Error> {
+ self.reader.drop_eof()
+ }
+
+ fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<C>> {
+ self.reader.get_mut()
+ }
+
+ fn get_ref(&self) -> Option<&dyn BufferedReader<C>> {
+ self.reader.get_ref()
+ }
+
+ /// This will always return a newly constructed [`EOF`](crate::EOF) here.
+ ///
+ /// This method cannot fail, therefore we return a dummy.
+ fn as_boxed<'b>(self) -> Box<dyn BufferedReader<C> + 'b>
+ where Self: 'b
+ {
+ // We construct an EOF here, because this operation is not
+ // fallible.
+ Box::new(crate::EOF::with_cookie(C::default()))
+ }
+
+ /// This will always return `None`.
+ 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 {
+ 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
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn mutable_reference() {
+ use crate::Memory;
+ const DATA : &[u8] = b"01234567890123456789suffix";
+ let mut mem = Memory::new(DATA);
+
+ /// 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.
+ }
+
+ parse_ten_bytes(Mut::new(&mut mem));
+ parse_ten_bytes(Mut::new(&mut mem));
+ let suffix = mem.data_eof().unwrap();
+ assert_eq!(suffix, b"suffix");
+ }
+}