Skip to content

Commit

Permalink
Introduce StreamingBuffer
Browse files Browse the repository at this point in the history
Co-authored-by: bjorn3 <bjorn3@users.noreply.github.com>
  • Loading branch information
philipc and bjorn3 committed Aug 28, 2021
1 parent c8c83b1 commit b723ffe
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
14 changes: 13 additions & 1 deletion src/write/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! Interface for writing object files.

use std::boxed::Box;
use std::collections::HashMap;
use std::string::String;
use std::vec::Vec;
use std::{error, fmt, result, str};
use std::{error, fmt, io, result, str};

use crate::endian::{Endianness, U32, U64};
use crate::{
Expand Down Expand Up @@ -530,6 +531,17 @@ impl Object {
Ok(buffer)
}

/// Write the object to a `Write` implementation.
///
/// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
/// instead of an unbuffered writer like [`File`](std::fs::File).
pub fn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> {
let mut stream = StreamingBuffer::new(w);
self.emit(&mut stream)?;
stream.result()?;
Ok(())
}

/// Write the object to a `WritableBuffer`.
pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
match self.format {
Expand Down
65 changes: 65 additions & 0 deletions src/write/util.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::io;
use std::mem;
use std::vec::Vec;

use crate::pod::{bytes_of, bytes_of_slice, Pod};
Expand Down Expand Up @@ -78,6 +80,69 @@ impl WritableBuffer for Vec<u8> {
}
}

/// A [`WritableBuffer`] that streams data to a [`Write`](std::io::Write) implementation.
///
/// [`Self::result`] must be called to determine if an I/O error occurred during writing.
///
/// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
/// instead of an unbuffered writer like [`File`](std::fs::File).
#[derive(Debug)]
pub struct StreamingBuffer<W> {
writer: W,
len: usize,
result: Result<(), io::Error>,
}

impl<W> StreamingBuffer<W> {
/// Create a new `StreamingBuffer` backed by the given writer.
pub fn new(writer: W) -> Self {
StreamingBuffer {
writer,
len: 0,
result: Ok(()),
}
}

/// Unwraps this [`StreamingBuffer`] giving back the original writer.
pub fn into_inner(self) -> W {
self.writer
}

/// Returns any error that occurred during writing.
pub fn result(&mut self) -> Result<(), io::Error> {
mem::replace(&mut self.result, Ok(()))
}
}

impl<W: io::Write> WritableBuffer for StreamingBuffer<W> {
#[inline]
fn len(&self) -> usize {
self.len
}

#[inline]
fn reserve(&mut self, _size: usize) -> Result<(), ()> {
Ok(())
}

#[inline]
fn resize(&mut self, new_len: usize) {
debug_assert!(self.len <= new_len);
while self.len < new_len {
let write_amt = (new_len - self.len - 1) % 1024 + 1;
self.write_bytes(&[0; 1024][..write_amt]);
}
}

#[inline]
fn write_bytes(&mut self, val: &[u8]) {
if self.result.is_ok() {
self.result = self.writer.write_all(val);
}
self.len += val.len();
}
}

/// A trait for mutable byte slices.
///
/// It provides convenience methods for `Pod` types.
Expand Down

0 comments on commit b723ffe

Please sign in to comment.