diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-07-04 12:57:22 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-07-04 14:39:49 +0200 |
commit | 222016e57c31135315d643c36c9328271c3bf19c (patch) | |
tree | fe03e8a06b6707a837a2d14bb3c450b166fc8e73 /openpgp/src/serialize/writer | |
parent | 5110f999bdb76b93e8e2b10328f6c3e3c06e09ed (diff) |
openpgp: Hide the `writer::Stackable` trait.
- Do not expose the `writer::Stackable` trait in the API. Instead,
use a tuple struct to wrap boxed objects of this kind.
- Add and use `writer::Stack::finalize()` and
`writer::Stack::finalize_all()` to pop one or all writers from the
stack.
Diffstat (limited to 'openpgp/src/serialize/writer')
-rw-r--r-- | openpgp/src/serialize/writer/mod.rs | 140 | ||||
-rw-r--r-- | openpgp/src/serialize/writer/writer_bzip2.rs | 29 | ||||
-rw-r--r-- | openpgp/src/serialize/writer/writer_deflate.rs | 54 |
3 files changed, 137 insertions, 86 deletions
diff --git a/openpgp/src/serialize/writer/mod.rs b/openpgp/src/serialize/writer/mod.rs index 39d21bcd..9815fcc0 100644 --- a/openpgp/src/serialize/writer/mod.rs +++ b/openpgp/src/serialize/writer/mod.rs @@ -19,26 +19,70 @@ use { }; /// A stack of writers. -/// -/// We use trait objects as the unit of composition. This is a -/// compiler limitation, we may use impl trait in the future. -pub type Stack<'a, C> = Box<'a + Stackable<'a, C>>; +#[derive(Debug)] +pub struct Stack<'a, C>(BoxStack<'a, C>); + +impl<'a, C> Stack<'a, C> { + pub(crate) fn from(bs: BoxStack<'a, C>) -> Self { + Stack(bs) + } + + pub(crate) fn as_ref(&self) -> &BoxStack<'a, C> { + &self.0 + } + + pub(crate) fn as_mut(&mut self) -> &mut BoxStack<'a, C> { + &mut self.0 + } + + /// Finalizes this writer, returning the underlying writer. + pub fn finalize(self) -> Result<Option<Stack<'a, C>>> { + Ok(self.0.into_inner()?.map(|bs| Self::from(bs))) + } + + /// Finalizes all writers, tearing down the whole stack. + pub fn finalize_all(self) -> Result<()> { + let mut stack = self; + while let Some(s) = stack.finalize()? { + stack = s; + } + Ok(()) + } +} + +impl<'a, C> io::Write for Stack<'a, C> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } +} + +impl<'a, C> From<Stack<'a, C>> for BoxStack<'a, C> { + fn from(s: Stack<'a, C>) -> Self { + s.0 + } +} + +pub(crate) type BoxStack<'a, C> = Box<'a + Stackable<'a, C>>; /// Makes a writer stackable and provides convenience functions. -pub trait Stackable<'a, C> : io::Write + fmt::Debug { +pub(crate) trait Stackable<'a, C> : io::Write + fmt::Debug { /// Recovers the inner stackable. /// /// This can fail if the current `Stackable` has buffered data /// that hasn't been written to the underlying `Stackable`. - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>>; + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>>; /// Pops the stackable from the stack, detaching it. /// /// Returns the detached stack. - fn pop(&mut self) -> Result<Option<Stack<'a, C>>>; + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>>; /// Sets the inner stackable. - fn mount(&mut self, new: Stack<'a, C>); + fn mount(&mut self, new: BoxStack<'a, C>); /// Returns a mutable reference to the inner `Writer`, if /// any. @@ -80,16 +124,16 @@ pub trait Stackable<'a, C> : io::Write + fmt::Debug { } /// Make a `Box<Stackable>` look like a Stackable. -impl <'a, C> Stackable<'a, C> for Stack<'a, C> { - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>> { +impl <'a, C> Stackable<'a, C> for BoxStack<'a, C> { + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { (*self).into_inner() } /// Recovers the inner stackable. - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { self.as_mut().pop() } /// Sets the inner stackable. - fn mount(&mut self, new: Stack<'a, C>) { + fn mount(&mut self, new: BoxStack<'a, C>) { self.as_mut().mount(new); } fn inner_mut(&mut self) -> Option<&mut Stackable<'a, C>> { @@ -111,7 +155,7 @@ impl <'a, C> Stackable<'a, C> for Stack<'a, C> { /// Maps a function over the stack of writers. #[allow(dead_code)] -pub fn map<C, F>(head: &Stackable<C>, mut fun: F) +pub(crate) fn map<C, F>(head: &Stackable<C>, mut fun: F) where F: FnMut(&Stackable<C>) -> bool { let mut ow = Some(head); while let Some(w) = ow { @@ -124,7 +168,7 @@ pub fn map<C, F>(head: &Stackable<C>, mut fun: F) /// Maps a function over the stack of mutable writers. #[allow(dead_code)] -pub fn map_mut<C, F>(head: &mut Stackable<C>, mut fun: F) +pub(crate) fn map_mut<C, F>(head: &mut Stackable<C>, mut fun: F) where F: FnMut(&mut Stackable<C>) -> bool { let mut ow = Some(head); while let Some(w) = ow { @@ -137,7 +181,7 @@ pub fn map_mut<C, F>(head: &mut Stackable<C>, mut fun: F) /// Dumps the writer stack. #[allow(dead_code)] -pub fn dump<C>(head: &Stackable<C>) { +pub(crate) fn dump<C>(head: &Stackable<C>) { let mut depth = 0; map(head, |w| { eprintln!("{}: {:?}", depth, w); @@ -146,15 +190,17 @@ pub fn dump<C>(head: &Stackable<C>) { }); } +/// The identity writer just relays anything written. pub struct Identity<'a, C> { - inner: Option<Stack<'a, C>>, + inner: Option<BoxStack<'a, C>>, cookie: C, } impl<'a, C: 'a> Identity<'a, C> { + /// Makes an identity writer. pub fn new(inner: Stack<'a, C>, cookie: C) -> Stack<'a, C> { - Box::new(Self{inner: Some(inner), cookie: cookie}) + Stack::from(Box::new(Self{inner: Some(inner.into()), cookie: cookie})) } } @@ -184,15 +230,15 @@ impl<'a, C> io::Write for Identity<'a, C> { impl<'a, C> Stackable<'a, C> for Identity<'a, C> { /// Recovers the inner stackable. - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>> { + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { Ok(self.inner) } /// Recovers the inner stackable. - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { Ok(self.inner.take()) } /// Sets the inner stackable. - fn mount(&mut self, new: Stack<'a, C>) { + fn mount(&mut self, new: BoxStack<'a, C>) { self.inner = Some(new); } fn inner_ref(&self) -> Option<&Stackable<'a, C>> { @@ -227,8 +273,9 @@ pub struct Generic<W: io::Write, C> { } impl<'a, W: 'a + io::Write, C: 'a> Generic<W, C> { + /// Wraps an `io::Write`r. pub fn new(inner: W, cookie: C) -> Stack<'a, C> { - Box::new(Self::new_unboxed(inner, cookie)) + Stack::from(Box::new(Self::new_unboxed(inner.into(), cookie))) } fn new_unboxed(inner: W, cookie: C) -> Self { @@ -258,15 +305,15 @@ impl<W: io::Write, C> io::Write for Generic<W, C> { impl<'a, W: io::Write, C> Stackable<'a, C> for Generic<W, C> { /// Recovers the inner stackable. - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>> { + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { Ok(None) } /// Recovers the inner stackable. - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { Ok(None) } /// Sets the inner stackable. - fn mount(&mut self, _new: Stack<'a, C>) { + fn mount(&mut self, _new: BoxStack<'a, C>) { } fn inner_mut(&mut self) -> Option<&mut Stackable<'a, C>> { None @@ -287,24 +334,25 @@ impl<'a, W: io::Write, C> Stackable<'a, C> for Generic<W, C> { /// Encrypting writer. -pub struct Encryptor<'a, C> { - inner: Generic<symmetric::Encryptor<Stack<'a, C>>, C>, +pub struct Encryptor<'a, C: 'a> { + inner: Generic<symmetric::Encryptor<BoxStack<'a, C>>, C>, } -impl<'a, C> Encryptor<'a, C> { +impl<'a, C: 'a> Encryptor<'a, C> { + /// Makes an encrypting writer. pub fn new(inner: Stack<'a, C>, cookie: C, algo: SymmetricAlgorithm, key: &[u8]) - -> Result<Box<Self>> + -> Result<Stack<'a, C>> { - Ok(Box::new(Encryptor { + Ok(Stack::from(Box::new(Encryptor { inner: Generic::new_unboxed( - symmetric::Encryptor::new(algo, key, inner)?, + symmetric::Encryptor::new(algo, key, inner.into())?, cookie), - })) + }))) } } -impl<'a, C:> fmt::Debug for Encryptor<'a, C> { +impl<'a, C: 'a> fmt::Debug for Encryptor<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("writer::Encryptor") .field("inner", &self.inner) @@ -312,7 +360,7 @@ impl<'a, C:> fmt::Debug for Encryptor<'a, C> { } } -impl<'a, C> io::Write for Encryptor<'a, C> { +impl<'a, C: 'a> io::Write for Encryptor<'a, C> { fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { self.inner.write(bytes) } @@ -322,15 +370,15 @@ impl<'a, C> io::Write for Encryptor<'a, C> { } } -impl<'a, C> Stackable<'a, C> for Encryptor<'a, C> { - fn into_inner(mut self: Box<Self>) -> Result<Option<Stack<'a, C>>> { +impl<'a, C: 'a> Stackable<'a, C> for Encryptor<'a, C> { + fn into_inner(mut self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { let inner = self.inner.inner.finish()?; Ok(Some(inner)) } - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { unimplemented!() } - fn mount(&mut self, _new: Stack<'a, C>) { + fn mount(&mut self, _new: BoxStack<'a, C>) { unimplemented!() } fn inner_mut(&mut self) -> Option<&mut Stackable<'a, C>> { @@ -365,15 +413,15 @@ mod test { let mut inner = Vec::new(); { let mut w = Generic::new(&mut inner, Cookie { state: "happy" }); - assert_eq!(w.cookie_ref().state, "happy"); - dump(&w); + assert_eq!(w.as_ref().cookie_ref().state, "happy"); + dump(w.as_ref()); - w.cookie_mut().state = "sad"; - assert_eq!(w.cookie_ref().state, "sad"); + w.as_mut().cookie_mut().state = "sad"; + assert_eq!(w.as_ref().cookie_ref().state, "sad"); w.write_all(b"be happy").unwrap(); let mut count = 0; - map_mut(&mut w, |g| { + map_mut(w.as_mut(), |g| { let new = Cookie { state: "happy" }; let old = g.cookie_set(new); assert_eq!(old.state, "sad"); @@ -381,7 +429,7 @@ mod test { true }); assert_eq!(count, 1); - assert_eq!(w.cookie_ref().state, "happy"); + assert_eq!(w.as_ref().cookie_ref().state, "happy"); } assert_eq!(&inner, b"be happy"); } @@ -391,13 +439,13 @@ mod test { let mut inner = Vec::new(); { let w = Generic::new(&mut inner, Cookie { state: "happy" }); - dump(&w); + dump(w.as_ref()); let w = Identity::new(w, Cookie { state: "happy" }); - dump(&w); + dump(w.as_ref()); let mut count = 0; - map(&w, |g| { + map(w.as_ref(), |g| { assert_eq!(g.cookie_ref().state, "happy"); count += 1; true diff --git a/openpgp/src/serialize/writer/writer_bzip2.rs b/openpgp/src/serialize/writer/writer_bzip2.rs index 4411e574..d0189821 100644 --- a/openpgp/src/serialize/writer/writer_bzip2.rs +++ b/openpgp/src/serialize/writer/writer_bzip2.rs @@ -4,24 +4,25 @@ use std::fmt; use std::io; use Result; -use super::{Generic, Stack, Stackable}; +use super::{Generic, Stack, BoxStack, Stackable}; /// BZing writer. -pub struct BZ<'a, C> { - inner: Generic<BzEncoder<Stack<'a, C>>, C>, +pub struct BZ<'a, C: 'a> { + inner: Generic<BzEncoder<BoxStack<'a, C>>, C>, } -impl<'a, C> BZ<'a, C> { - pub fn new(inner: Stack<'a, C>, cookie: C) -> Box<Self> { - Box::new(BZ { +impl<'a, C: 'a> BZ<'a, C> { + /// Makes a BZ compressing writer. + pub fn new(inner: Stack<'a, C>, cookie: C) -> Stack<'a, C> { + Stack::from(Box::new(BZ { inner: Generic::new_unboxed( - BzEncoder::new(inner, BzCompression::Default), + BzEncoder::new(inner.into(), BzCompression::Default), cookie), - }) + })) } } -impl<'a, C:> fmt::Debug for BZ<'a, C> { +impl<'a, C: 'a> fmt::Debug for BZ<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("writer::BZ") .field("inner", &self.inner) @@ -29,7 +30,7 @@ impl<'a, C:> fmt::Debug for BZ<'a, C> { } } -impl<'a, C> io::Write for BZ<'a, C> { +impl<'a, C: 'a> io::Write for BZ<'a, C> { fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { self.inner.write(bytes) } @@ -39,15 +40,15 @@ impl<'a, C> io::Write for BZ<'a, C> { } } -impl<'a, C> Stackable<'a, C> for BZ<'a, C> { - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>> { +impl<'a, C: 'a> Stackable<'a, C> for BZ<'a, C> { + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { let inner = self.inner.inner.finish()?; Ok(Some(inner)) } - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { unimplemented!() } - fn mount(&mut self, _new: Stack<'a, C>) { + fn mount(&mut self, _new: BoxStack<'a, C>) { unimplemented!() } fn inner_mut(&mut self) -> Option<&mut Stackable<'a, C>> { diff --git a/openpgp/src/serialize/writer/writer_deflate.rs b/openpgp/src/serialize/writer/writer_deflate.rs index 54900dff..f5cdcb7d 100644 --- a/openpgp/src/serialize/writer/writer_deflate.rs +++ b/openpgp/src/serialize/writer/writer_deflate.rs @@ -4,24 +4,25 @@ use std::fmt; use std::io; use Result; -use super::{Generic, Stack, Stackable}; +use super::{Generic, Stack, BoxStack, Stackable}; /// ZIPing writer. -pub struct ZIP<'a, C> { - inner: Generic<DeflateEncoder<Stack<'a, C>>, C>, +pub struct ZIP<'a, C: 'a> { + inner: Generic<DeflateEncoder<BoxStack<'a, C>>, C>, } -impl<'a, C> ZIP<'a, C> { - pub fn new(inner: Stack<'a, C>, cookie: C) -> Box<Self> { - Box::new(ZIP { +impl<'a, C: 'a> ZIP<'a, C> { + /// Makes a ZIP compressing writer. + pub fn new(inner: Stack<'a, C>, cookie: C) -> Stack<'a, C> { + Stack::from(Box::new(ZIP { inner: Generic::new_unboxed( - DeflateEncoder::new(inner, FlateCompression::default()), + DeflateEncoder::new(inner.into(), FlateCompression::default()), cookie), - }) + })) } } -impl<'a, C:> fmt::Debug for ZIP<'a, C> { +impl<'a, C: 'a> fmt::Debug for ZIP<'a, C> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("writer::ZIP") .field("inner", &self.inner) @@ -29,7 +30,7 @@ impl<'a, C:> fmt::Debug for ZIP<'a, C> { } } -impl<'a, C> io::Write for ZIP<'a, C> { +impl<'a, C: 'a> io::Write for ZIP<'a, C> { fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { self.inner.write(bytes) } @@ -39,15 +40,15 @@ impl<'a, C> io::Write for ZIP<'a, C> { } } -impl<'a, C> Stackable<'a, C> for ZIP<'a, C> { - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>> { +impl<'a, C: 'a> Stackable<'a, C> for ZIP<'a, C> { + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { let inner = self.inner.inner.finish()?; Ok(Some(inner)) } - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { unimplemented!() } - fn mount(&mut self, _new: Stack<'a, C>) { + fn mount(&mut self, _new: BoxStack<'a, C>) { unimplemented!() } fn inner_mut(&mut self) -> Option<&mut Stackable<'a, C>> { @@ -68,17 +69,18 @@ impl<'a, C> Stackable<'a, C> for ZIP<'a, C> { } /// ZLIBing writer. -pub struct ZLIB<'a, C> { - inner: Generic<ZlibEncoder<Stack<'a, C>>, C>, +pub struct ZLIB<'a, C: 'a> { + inner: Generic<ZlibEncoder<BoxStack<'a, C>>, C>, } -impl<'a, C> ZLIB<'a, C> { - pub fn new(inner: Stack<'a, C>, cookie: C) -> Box<Self> { - Box::new(ZLIB { +impl<'a, C: 'a> ZLIB<'a, C> { + /// Makes a ZLIB compressing writer. + pub fn new(inner: Stack<'a, C>, cookie: C) -> Stack<'a, C> { + Stack::from(Box::new(ZLIB { inner: Generic::new_unboxed( - ZlibEncoder::new(inner, FlateCompression::default()), + ZlibEncoder::new(inner.into(), FlateCompression::default()), cookie), - }) + })) } } @@ -90,7 +92,7 @@ impl<'a, C:> fmt::Debug for ZLIB<'a, C> { } } -impl<'a, C> io::Write for ZLIB<'a, C> { +impl<'a, C: 'a> io::Write for ZLIB<'a, C> { fn write(&mut self, bytes: &[u8]) -> io::Result<usize> { self.inner.write(bytes) } @@ -100,15 +102,15 @@ impl<'a, C> io::Write for ZLIB<'a, C> { } } -impl<'a, C> Stackable<'a, C> for ZLIB<'a, C> { - fn into_inner(self: Box<Self>) -> Result<Option<Stack<'a, C>>> { +impl<'a, C: 'a> Stackable<'a, C> for ZLIB<'a, C> { + fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> { let inner = self.inner.inner.finish()?; Ok(Some(inner)) } - fn pop(&mut self) -> Result<Option<Stack<'a, C>>> { + fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> { unimplemented!() } - fn mount(&mut self, _new: Stack<'a, C>) { + fn mount(&mut self, _new: BoxStack<'a, C>) { unimplemented!() } fn inner_mut(&mut self) -> Option<&mut Stackable<'a, C>> { |