Skip to content

Commit

Permalink
Use buffered writer in args::parse_arguments
Browse files Browse the repository at this point in the history
To be able to decide whether to print the argparse output depending on
the result of the argument parsing, this patch wraps stdout and stderr
in a BufWriter before invoking argparse. Our BufWriter implementation
only writes to the inner Write if the flush method is called. This
allows us to decide whether the buffered data should be written or
silently dropped.
  • Loading branch information
robinkrahl authored and d-e-s-o committed Feb 18, 2019
1 parent 41f352b commit ff3c5fd
Showing 1 changed file with 52 additions and 1 deletion.
53 changes: 52 additions & 1 deletion nitrocli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@ use crate::RunCtx;

type Result<T> = result::Result<T, Error>;

/// Wraps a writer and buffers its output.
///
/// This implementation is similar to `io::BufWriter`, but:
/// - The inner writer is only written to if `flush` is called.
/// - The buffer may grow infinitely large.
struct BufWriter<'w, W: io::Write + ?Sized> {
buf: Vec<u8>,
inner: &'w mut W,
}

impl<'w, W: io::Write + ?Sized> BufWriter<'w, W> {
pub fn new(inner: &'w mut W) -> Self {
BufWriter {
buf: Vec::with_capacity(128),
inner,
}
}
}

impl<'w, W: io::Write + ?Sized> io::Write for BufWriter<'w, W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buf.extend_from_slice(buf);
Ok(buf.len())
}

fn flush(&mut self) -> io::Result<()> {
self.inner.write_all(&self.buf)?;
self.buf.clear();
self.inner.flush()
}
}

trait Stdio {
fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write);
}
Expand All @@ -39,6 +71,15 @@ impl<'io> Stdio for RunCtx<'io> {
}
}

impl<W> Stdio for (&mut W, &mut W)
where
W: io::Write,
{
fn stdio(&mut self) -> (&mut dyn io::Write, &mut dyn io::Write) {
(self.0, self.1)
}
}

/// A command execution context that captures additional data pertaining
/// the command execution.
pub struct ExecCtx<'io> {
Expand Down Expand Up @@ -827,6 +868,8 @@ fn parse_arguments<'io, 'ctx: 'io>(
ctx: &'ctx mut RunCtx<'_>,
args: Vec<String>,
) -> Result<(Command, ExecCtx<'io>, Vec<String>)> {
use std::io::Write;

let mut model: Option<DeviceModel> = None;
let model_help = format!(
"Select the device model to connect to ({})",
Expand Down Expand Up @@ -862,8 +905,16 @@ fn parse_arguments<'io, 'ctx: 'io>(
"The arguments for the command",
);
parser.stop_on_first_argument(true);
parse(ctx, parser, args)?;

let mut stdout_buf = BufWriter::new(ctx.stdout);
let mut stderr_buf = BufWriter::new(ctx.stderr);
let mut stdio_buf = (&mut stdout_buf, &mut stderr_buf);
let result = parse(&mut stdio_buf, parser, args);

stdout_buf.flush()?;
stderr_buf.flush()?;

result?;
subargs.insert(0, format!("nitrocli {}", command));

let ctx = ExecCtx {
Expand Down

0 comments on commit ff3c5fd

Please sign in to comment.