From 73da1cd5dbf865418e1b0bc80f7afffc5a7cbf7c Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Tue, 12 Jul 2022 09:30:47 +0200 Subject: [PATCH] "Fix" preserves-tool binary output by adding a streaming write mode --- .../preserves-tools/src/bin/preserves-tool.rs | 6 ++- .../rust/preserves/src/value/packed/writer.rs | 50 ++++++++++++++++--- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/implementations/rust/preserves-tools/src/bin/preserves-tool.rs b/implementations/rust/preserves-tools/src/bin/preserves-tool.rs index 0a8d4cb..c7a5da4 100644 --- a/implementations/rust/preserves-tools/src/bin/preserves-tool.rs +++ b/implementations/rust/preserves-tools/src/bin/preserves-tool.rs @@ -417,6 +417,7 @@ fn convert(c: Convert) -> io::Result<()> { } OutputFormat::Binary => { let mut p = PackedWriter::new(io::stdout()); + p.start_sequence()?; Box::new(move |v| { if write_ann { p.write(&mut IOValueDomainCodec, v)?; @@ -467,7 +468,7 @@ impl Quote { fn output_one(q: &Quote, v: &IOValue) -> io::Result<()> { match q.output_format { OutputFormat::Binary => - PackedWriter::new(io::stdout()).write(&mut IOValueDomainCodec, v), + PackedWriter::new(io::stdout()).streaming().write(&mut IOValueDomainCodec, v), OutputFormat::Text => { TextWriter::new(io::stdout()) .set_escape_spaces(q.escape_spaces()) @@ -483,6 +484,9 @@ fn output_one(q: &Quote, v: &IOValue) -> io::Result<()> { } fn quote(q: Quote) -> io::Result<()> { + if matches!(q.output_format, OutputFormat::Text) { + PackedWriter::new(io::stdout()).start_sequence()?; + } match &q.output { QuotationOutput::ByteString => { let mut buf = Vec::new(); diff --git a/implementations/rust/preserves/src/value/packed/writer.rs b/implementations/rust/preserves/src/value/packed/writer.rs index 1066533..8933cf5 100644 --- a/implementations/rust/preserves/src/value/packed/writer.rs +++ b/implementations/rust/preserves/src/value/packed/writer.rs @@ -16,6 +16,7 @@ pub struct PackedWriter { w: W, buffer: IOList, items: Vec>, + streaming: bool, } impl PackedWriter<&mut Vec> { @@ -55,6 +56,7 @@ impl PackedWriter { w: write, buffer: IOList::new(), items: Vec::new(), + streaming: false, } } @@ -86,15 +88,29 @@ impl PackedWriter { } pub fn finish_item(&mut self) -> io::Result<()> { - let buffer = std::mem::replace(&mut self.buffer, IOList::new()); - match self.items.last_mut() { - Some(iols) => Ok(iols.push(buffer)), - None => buffer.write_to(&mut self.w), + if self.buffer.len() > 0 { + let mut buffer = std::mem::replace(&mut self.buffer, IOList::new()); + match self.items.last_mut() { + Some(iols) => iols.push(buffer), + None => { + if self.streaming { + let mut len = IOList::new(); + varint(&mut len, buffer.len()); + len.write_to(&mut self.w)?; + } + buffer.write_to(&mut self.w)?; + } + } } + Ok(()) + } + + fn at_toplevel(&self) -> bool { + self.items.is_empty() } pub fn finish_item_if_toplevel(&mut self) -> io::Result<()> { - if self.items.is_empty() { + if self.at_toplevel() { self.finish_item()?; } Ok(()) @@ -117,6 +133,14 @@ impl PackedWriter { } self.finish_item_if_toplevel() } + + pub fn streaming(mut self) -> Self { + if !self.at_toplevel() { + panic!("Attempt to enable streaming mode mid-way through serialization"); + } + self.streaming = true; + self + } } macro_rules! fits_in_bytes { @@ -338,12 +362,24 @@ impl Writer for PackedWriter #[inline(always)] fn start_sequence(&mut self) -> io::Result<()> { - self.start_seq() + if self.at_toplevel() && !self.streaming { + self.write_tag(Tag::Sequence); + self.finish_item()?; + self.streaming = true; + Ok(()) + } else { + self.start_seq() + } } #[inline(always)] fn end_sequence(&mut self) -> io::Result<()> { - self.finish_seq(Tag::Sequence, false) + if self.at_toplevel() && self.streaming { + self.streaming = false; + Ok(()) + } else { + self.finish_seq(Tag::Sequence, false) + } } #[inline(always)]