summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openpgp/examples/sign-detached.rs5
-rw-r--r--openpgp/examples/sign.rs9
-rw-r--r--openpgp/src/serialize/mod.rs2
-rw-r--r--openpgp/src/serialize/partial_body.rs14
-rw-r--r--openpgp/src/serialize/stream.rs122
-rw-r--r--openpgp/src/serialize/writer/mod.rs140
-rw-r--r--openpgp/src/serialize/writer/writer_bzip2.rs29
-rw-r--r--openpgp/src/serialize/writer/writer_deflate.rs54
8 files changed, 214 insertions, 161 deletions
diff --git a/openpgp/examples/sign-detached.rs b/openpgp/examples/sign-detached.rs
index a4052907..3bbb9abd 100644
--- a/openpgp/examples/sign-detached.rs
+++ b/openpgp/examples/sign-detached.rs
@@ -40,7 +40,6 @@ fn main() {
.expect("Failed to sign data");
// Teardown the stack to ensure all the data is written.
- let _ = signer.into_inner()
- .expect("Failed to write data")
- .unwrap();
+ signer.finalize_all()
+ .expect("Failed to write data");
}
diff --git a/openpgp/examples/sign.rs b/openpgp/examples/sign.rs
index f1b8282d..2e212c78 100644
--- a/openpgp/examples/sign.rs
+++ b/openpgp/examples/sign.rs
@@ -45,11 +45,6 @@ fn main() {
.expect("Failed to sign data");
// Teardown the stack to ensure all the data is written.
- let signer = literal.into_inner()
- .expect("Failed to write data")
- .unwrap();
-
- let _ = signer.into_inner()
- .expect("Failed to write data")
- .unwrap();
+ literal.finalize_all()
+ .expect("Failed to write data");
}
diff --git a/openpgp/src/serialize/mod.rs b/openpgp/src/serialize/mod.rs
index b336f579..ac97f150 100644
--- a/openpgp/src/serialize/mod.rs
+++ b/openpgp/src/serialize/mod.rs
@@ -16,7 +16,7 @@ use super::*;
mod partial_body;
use self::partial_body::PartialBodyFilter;
-mod writer;
+pub mod writer;
pub mod stream;
use s2k::S2K;
use subpacket::{
diff --git a/openpgp/src/serialize/partial_body.rs b/openpgp/src/serialize/partial_body.rs
index a1df796a..35c311ee 100644
--- a/openpgp/src/serialize/partial_body.rs
+++ b/openpgp/src/serialize/partial_body.rs
@@ -39,7 +39,7 @@ pub struct PartialBodyFilter<'a, C: 'a> {
// Because this writer implements `Drop`, we cannot move the inner
// writer out of this writer. We therefore wrap it with `Option`
// so that we can `take()` it.
- inner: Option<writer::Stack<'a, C>>,
+ inner: Option<writer::BoxStack<'a, C>>,
// The cookie.
cookie: C,
@@ -66,13 +66,13 @@ impl<'a, C: 'a> PartialBodyFilter<'a, C> {
pub fn new(inner: writer::Stack<'a, C>, cookie: C) -> writer::Stack<'a, C> {
let buffer_threshold = PARTIAL_BODY_FILTER_BUFFER_THRESHOLD;
let max_chunk_size = PARTIAL_BODY_FILTER_MAX_CHUNK_SIZE;
- Box::new(PartialBodyFilter {
- inner: Some(inner),
+ writer::Stack::from(Box::new(PartialBodyFilter {
+ inner: Some(inner.into()),
cookie: cookie,
buffer: Vec::with_capacity(buffer_threshold as usize),
buffer_threshold: buffer_threshold,
max_chunk_size: max_chunk_size,
- })
+ }))
}
// Writes out any full chunks between `self.buffer` and `other`.
@@ -201,15 +201,15 @@ impl<'a, C: 'a> fmt::Debug for PartialBodyFilter<'a, C> {
}
impl<'a, C: 'a> writer::Stackable<'a, C> for PartialBodyFilter<'a, C> {
- fn into_inner(mut self: Box<Self>) -> Result<Option<writer::Stack<'a, C>>> {
+ fn into_inner(mut self: Box<Self>) -> Result<Option<writer::BoxStack<'a, C>>> {
self.write_out(&b""[..], true)?;
Ok(self.inner.take())
}
- fn pop(&mut self) -> Result<Option<writer::Stack<'a, C>>> {
+ fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, C>>> {
self.write_out(&b""[..], true)?;
Ok(self.inner.take())
}
- fn mount(&mut self, new: writer::Stack<'a, C>) {
+ fn mount(&mut self, new: writer::BoxStack<'a, C>) {
self.inner = Some(new);
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, C>> {
diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs
index 67b828f2..ec605c0a 100644
--- a/openpgp/src/serialize/stream.rs
+++ b/openpgp/src/serialize/stream.rs
@@ -74,6 +74,7 @@ pub fn wrap<'a, W: 'a + io::Write>(w: W) -> writer::Stack<'a, Cookie> {
/// # Example
///
/// ```
+/// use std::io::Write;
/// use openpgp::packet::Tag;
/// use openpgp::serialize::stream::{wrap, ArbitraryWriter};
/// # use openpgp::Result;
@@ -91,18 +92,18 @@ pub fn wrap<'a, W: 'a + io::Write>(w: W) -> writer::Stack<'a, Cookie> {
/// # Ok(())
/// # }
pub struct ArbitraryWriter<'a> {
- inner: writer::Stack<'a, Cookie>,
+ inner: writer::BoxStack<'a, Cookie>,
}
impl<'a> ArbitraryWriter<'a> {
/// Creates a new writer with the given tag.
pub fn new(mut inner: writer::Stack<'a, Cookie>, tag: Tag)
-> Result<writer::Stack<'a, Cookie>> {
- let level = inner.cookie_ref().level + 1;
+ let level = inner.as_ref().cookie_ref().level + 1;
CTB::new(tag).serialize(&mut inner)?;
- Ok(Box::new(ArbitraryWriter {
- inner: PartialBodyFilter::new(inner, Cookie::new(level))
- }))
+ Ok(writer::Stack::from(Box::new(ArbitraryWriter {
+ inner: PartialBodyFilter::new(inner, Cookie::new(level)).into()
+ })))
}
}
@@ -124,14 +125,14 @@ impl<'a> Write for ArbitraryWriter<'a> {
}
impl<'a> writer::Stackable<'a, Cookie> for ArbitraryWriter<'a> {
- fn into_inner(self: Box<Self>) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn into_inner(self: Box<Self>) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Box::new(self.inner).into_inner()
}
- fn pop(&mut self) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
/// Sets the inner stackable.
- fn mount(&mut self, _new: writer::Stack<'a, Cookie>) {
+ fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
@@ -166,7 +167,7 @@ pub struct Signer<'a> {
// Furthermore, the LiteralWriter will pop us off the stack, and
// take our inner reader. If that happens, we only update the
// digests.
- inner: Option<writer::Stack<'a, Cookie>>,
+ inner: Option<writer::BoxStack<'a, Cookie>>,
keys: Vec<&'a Key>,
detached: bool,
hash: Box<Hash>,
@@ -179,6 +180,7 @@ impl<'a> Signer<'a> {
/// # Example
///
/// ```
+ /// use std::io::Write;
/// use openpgp::serialize::stream::{wrap, Signer, LiteralWriter};
/// # use openpgp::{Result, TPK};
/// # let tsk = TPK::from_bytes(include_bytes!(
@@ -191,8 +193,7 @@ impl<'a> Signer<'a> {
/// let signer = Signer::new(wrap(&mut o), &[&tsk])?;
/// let mut ls = LiteralWriter::new(signer, 't', None, 0)?;
/// ls.write_all(b"Make it so, number one!")?;
- /// let signer = ls.into_inner()?.unwrap();
- /// let _ = signer.into_inner()?.unwrap();
+ /// ls.finalize_all()?;
/// }
/// # Ok(())
/// # }
@@ -207,6 +208,7 @@ impl<'a> Signer<'a> {
/// # Example
///
/// ```
+ /// use std::io::Write;
/// use openpgp::serialize::stream::{wrap, Signer, LiteralWriter};
/// # use openpgp::{Result, TPK};
/// # let tsk = TPK::from_bytes(include_bytes!(
@@ -219,7 +221,7 @@ impl<'a> Signer<'a> {
/// let mut signer = Signer::detached(wrap(&mut o), &[&tsk])?;
/// signer.write_all(b"Make it so, number one!")?;
/// // In reality, just io::copy() the file to be signed.
- /// let _ = signer.into_inner()?.unwrap();
+ /// signer.finalize_all()?;
/// }
/// # Ok(())
/// # }
@@ -229,9 +231,10 @@ impl<'a> Signer<'a> {
Self::make(inner, signers, true)
}
- fn make(mut inner: writer::Stack<'a, Cookie>, signers: &[&'a TPK],
+ fn make(inner: writer::Stack<'a, Cookie>, signers: &[&'a TPK],
detached: bool)
-> Result<writer::Stack<'a, Cookie>> {
+ let mut inner = writer::BoxStack::from(inner);
// Just always use SHA512.
let hash_algo = HashAlgorithm::SHA512;
let mut signing_keys = Vec::new();
@@ -306,7 +309,7 @@ impl<'a> Signer<'a> {
}
let level = inner.cookie_ref().level + 1;
- Ok(Box::new(Signer {
+ Ok(writer::Stack::from(Box::new(Signer {
inner: Some(inner),
keys: signing_keys,
detached: detached,
@@ -315,7 +318,7 @@ impl<'a> Signer<'a> {
level: level,
private: Private::Signer,
},
- }))
+ })))
}
fn emit_signatures(&mut self) -> Result<()> {
@@ -400,10 +403,10 @@ impl<'a> Write for Signer<'a> {
}
impl<'a> writer::Stackable<'a, Cookie> for Signer<'a> {
- fn pop(&mut self) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Ok(self.inner.take())
}
- fn mount(&mut self, new: writer::Stack<'a, Cookie>) {
+ fn mount(&mut self, new: writer::BoxStack<'a, Cookie>) {
self.inner = Some(new);
}
fn inner_mut(&mut self) -> Option<&mut writer::Stackable<'a, Cookie>> {
@@ -421,7 +424,7 @@ impl<'a> writer::Stackable<'a, Cookie> for Signer<'a> {
}
}
fn into_inner(mut self: Box<Self>)
- -> Result<Option<writer::Stack<'a, Cookie>>> {
+ -> Result<Option<writer::BoxStack<'a, Cookie>>> {
self.emit_signatures()?;
Ok(self.inner.take())
}
@@ -445,6 +448,7 @@ impl<'a> writer::Stackable<'a, Cookie> for Signer<'a> {
/// # Example
///
/// ```
+/// use std::io::Write;
/// use openpgp::serialize::stream::{wrap, LiteralWriter};
/// # use openpgp::Result;
/// # f().unwrap();
@@ -459,15 +463,16 @@ impl<'a> writer::Stackable<'a, Cookie> for Signer<'a> {
/// # }
/// ```
pub struct LiteralWriter<'a> {
- inner: writer::Stack<'a, Cookie>,
- signature_writer: Option<writer::Stack<'a, Cookie>>,
+ inner: writer::BoxStack<'a, Cookie>,
+ signature_writer: Option<writer::BoxStack<'a, Cookie>>,
}
impl<'a> LiteralWriter<'a> {
/// Creates a new literal writer.
- pub fn new(mut inner: writer::Stack<'a, Cookie>,
+ pub fn new(inner: writer::Stack<'a, Cookie>,
format: char, filename: Option<&[u8]>, date: u32)
-> Result<writer::Stack<'a, Cookie>> {
+ let mut inner = writer::BoxStack::from(inner);
let level = inner.cookie_ref().level + 1;
let mut template = Literal::new(format).date(date);
@@ -505,15 +510,15 @@ impl<'a> LiteralWriter<'a> {
// Neither is any framing added by the PartialBodyFilter.
let mut inner
- = PartialBodyFilter::new(inner, Cookie::new(level));
+ = PartialBodyFilter::new(writer::Stack::from(inner), Cookie::new(level));
// Nor the headers.
template.serialize_headers(&mut inner, false)?;
- Ok(Box::new(Self {
- inner: inner,
+ Ok(writer::Stack::from(Box::new(Self {
+ inner: inner.into(),
signature_writer: signature_writer,
- }))
+ })))
}
}
@@ -544,7 +549,7 @@ impl<'a> Write for LiteralWriter<'a> {
impl<'a> writer::Stackable<'a, Cookie> for LiteralWriter<'a> {
fn into_inner(mut self: Box<Self>)
- -> Result<Option<writer::Stack<'a, Cookie>>> {
+ -> Result<Option<writer::BoxStack<'a, Cookie>>> {
let signer = self.signature_writer.take();
let stack = self.inner
.into_inner()?.unwrap(); // Peel off the PartialBodyFilter.
@@ -559,11 +564,11 @@ impl<'a> writer::Stackable<'a, Cookie> for LiteralWriter<'a> {
}
}
- fn pop(&mut self) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
/// Sets the inner stackable.
- fn mount(&mut self, _new: writer::Stack<'a, Cookie>) {
+ fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
@@ -591,6 +596,7 @@ impl<'a> writer::Stackable<'a, Cookie> for LiteralWriter<'a> {
/// # Example
///
/// ```
+/// use std::io::Write;
/// use openpgp::serialize::stream::{wrap, Compressor, LiteralWriter};
/// use openpgp::constants::CompressionAlgorithm;
/// # use openpgp::Result;
@@ -608,23 +614,25 @@ impl<'a> writer::Stackable<'a, Cookie> for LiteralWriter<'a> {
/// # Ok(())
/// # }
pub struct Compressor<'a> {
- inner: writer::Stack<'a, Cookie>,
+ inner: writer::BoxStack<'a, Cookie>,
}
impl<'a> Compressor<'a> {
/// Creates a new compressor using the given algorithm.
- pub fn new(mut inner: writer::Stack<'a, Cookie>, algo: CompressionAlgorithm)
+ pub fn new(inner: writer::Stack<'a, Cookie>, algo: CompressionAlgorithm)
-> Result<writer::Stack<'a, Cookie>> {
+ let mut inner = writer::BoxStack::from(inner);
let level = inner.cookie_ref().level + 1;
// Packet header.
CTB::new(Tag::CompressedData).serialize(&mut inner)?;
let mut inner: writer::Stack<'a, Cookie>
- = PartialBodyFilter::new(inner, Cookie::new(level));
+ = PartialBodyFilter::new(writer::Stack::from(inner),
+ Cookie::new(level));
// Compressed data header.
- inner.write_u8(algo.into())?;
+ inner.as_mut().write_u8(algo.into())?;
// Create an appropriate filter.
let inner: writer::Stack<'a, Cookie> = match algo {
@@ -642,7 +650,7 @@ impl<'a> Compressor<'a> {
_ => unimplemented!(),
};
- Ok(Box::new(Self{inner: inner}))
+ Ok(writer::Stack::from(Box::new(Self{inner: inner.into()})))
}
}
@@ -665,14 +673,14 @@ impl<'a> io::Write for Compressor<'a> {
}
impl<'a> writer::Stackable<'a, Cookie> for Compressor<'a> {
- fn into_inner(self: Box<Self>) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn into_inner(self: Box<Self>) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Box::new(self.inner).into_inner()?.unwrap().into_inner()
}
- fn pop(&mut self) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
/// Sets the inner stackable.
- fn mount(&mut self, _new: writer::Stack<'a, Cookie>) {
+ fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
@@ -694,7 +702,7 @@ impl<'a> writer::Stackable<'a, Cookie> for Compressor<'a> {
/// Encrypts a packet stream.
pub struct Encryptor<'a> {
- inner: Option<writer::Stack<'a, Cookie>>,
+ inner: Option<writer::BoxStack<'a, Cookie>>,
hash: Box<Hash>,
cookie: Cookie,
}
@@ -731,6 +739,7 @@ impl<'a> Encryptor<'a> {
/// # Example
///
/// ```
+ /// use std::io::Write;
/// #[macro_use] extern crate openpgp; // For armored!
/// use openpgp::serialize::stream::{
/// wrap, Encryptor, EncryptionMode, LiteralWriter,
@@ -791,7 +800,7 @@ impl<'a> Encryptor<'a> {
encryption_mode: EncryptionMode)
-> Result<writer::Stack<'a, Cookie>> {
let mut rng = Yarrow::default();
- let level = inner.cookie_ref().level + 1;
+ let level = inner.as_ref().cookie_ref().level + 1;
let algo = SymmetricAlgorithm::AES256;
// Generate a session key.
@@ -870,13 +879,12 @@ impl<'a> Encryptor<'a> {
// Write the SEIP packet.
CTB::new(Tag::SEIP).serialize(&mut inner)?;
- let mut inner: writer::Stack<'a, Cookie>
- = PartialBodyFilter::new(inner, Cookie::new(level));
+ let mut inner = PartialBodyFilter::new(inner, Cookie::new(level));
inner.write(&[1])?; // Version.
// Assuming 'algo' is good, this cannot fail.
let encryptor = writer::Encryptor::new(
- inner,
+ inner.into(),
Cookie::new(level),
algo,
&sk,
@@ -884,11 +892,11 @@ impl<'a> Encryptor<'a> {
// The hash for the MDC must include the initialization
// vector, hence we build the object here.
- let mut encryptor = Box::new(Self{
- inner: Some(encryptor),
+ let mut encryptor = writer::Stack::from(Box::new(Self{
+ inner: Some(encryptor.into()),
hash: HashAlgorithm::SHA1.context().unwrap(),
cookie: Cookie::new(level),
- });
+ }));
// Write the initialization vector, and the quick-check bytes.
let mut iv = vec![0; algo.block_size().unwrap()];
@@ -900,7 +908,7 @@ impl<'a> Encryptor<'a> {
}
/// Emits the MDC packet and recovers the original writer.
- fn emit_mdc(&mut self) -> Result<writer::Stack<'a, Cookie>> {
+ fn emit_mdc(&mut self) -> Result<writer::BoxStack<'a, Cookie>> {
if let Some(mut w) = self.inner.take() {
// Write the MDC, which must be the last packet inside the
// encrypted packet stream. The hash includes the MDC's
@@ -961,11 +969,11 @@ impl<'a> Write for Encryptor<'a> {
}
impl<'a> writer::Stackable<'a, Cookie> for Encryptor<'a> {
- fn pop(&mut self) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn pop(&mut self) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
unimplemented!()
}
/// Sets the inner stackable.
- fn mount(&mut self, _new: writer::Stack<'a, Cookie>) {
+ fn mount(&mut self, _new: writer::BoxStack<'a, Cookie>) {
unimplemented!()
}
fn inner_ref(&self) -> Option<&writer::Stackable<'a, Cookie>> {
@@ -982,7 +990,7 @@ impl<'a> writer::Stackable<'a, Cookie> for Encryptor<'a> {
None
}
}
- fn into_inner(mut self: Box<Self>) -> Result<Option<writer::Stack<'a, Cookie>>> {
+ fn into_inner(mut self: Box<Self>) -> Result<Option<writer::BoxStack<'a, Cookie>>> {
Ok(Some(self.emit_mdc()?))
}
fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
@@ -1059,11 +1067,11 @@ mod test {
wrap(&mut o), CompressionAlgorithm::Uncompressed).unwrap();
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "one").unwrap();
- let c = ls.into_inner().unwrap().unwrap(); // Pop the LiteralWriter.
+ let c = ls.finalize().unwrap().unwrap(); // Pop the LiteralWriter.
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "two").unwrap();
- let c = ls.into_inner().unwrap().unwrap(); // Pop the LiteralWriter.
- let c = c.into_inner().unwrap().unwrap(); // Pop the Compressor.
+ let c = ls.finalize().unwrap().unwrap(); // Pop the LiteralWriter.
+ let c = c.finalize().unwrap().unwrap(); // Pop the Compressor.
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "three").unwrap();
}
@@ -1111,16 +1119,16 @@ mod test {
c0, CompressionAlgorithm::Uncompressed).unwrap();
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "one").unwrap();
- let c = ls.into_inner().unwrap().unwrap();
+ let c = ls.finalize().unwrap().unwrap();
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "two").unwrap();
- let c = ls.into_inner().unwrap().unwrap();
- let c0 = c.into_inner().unwrap().unwrap();
+ let c = ls.finalize().unwrap().unwrap();
+ let c0 = c.finalize().unwrap().unwrap();
let c = Compressor::new(
c0, CompressionAlgorithm::Uncompressed).unwrap();
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "three").unwrap();
- let c = ls.into_inner().unwrap().unwrap();
+ let c = ls.finalize().unwrap().unwrap();
let mut ls = LiteralWriter::new(c, 't', None, 0).unwrap();
write!(ls, "four").unwrap();
}
@@ -1173,8 +1181,8 @@ mod test {
.unwrap();
let mut ls = LiteralWriter::new(signer, 't', None, 0).unwrap();
ls.write_all(b"Tis, tis, tis. Tis is important.").unwrap();
- let signer = ls.into_inner().unwrap().unwrap();
- let _ = signer.into_inner().unwrap().unwrap();
+ let signer = ls.finalize().unwrap().unwrap();
+ let _ = signer.finalize().unwrap().unwrap();
}
let mut ppr = PacketParser::from_bytes(&o).unwrap();
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(n