Skip to content

Commit

Permalink
Make the output of Env::std{out, err} a concrete type (#27)
Browse files Browse the repository at this point in the history
* make the output of Env::std{out, err} a concrete type

* document why the unwrap in write_fmt is okay
  • Loading branch information
tertsdiepraam authored Nov 15, 2024
1 parent 18d56a6 commit a014f13
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 18 deletions.
3 changes: 1 addition & 2 deletions src/commands/nsec3hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use lexopt::Arg;
use octseq::OctetsBuilder;
use ring::digest;
use std::ffi::OsString;
use std::fmt::Write;
use std::str::FromStr;

use super::{parse_os, parse_os_with, LdnsCommand};
Expand Down Expand Up @@ -136,7 +135,7 @@ impl Nsec3Hash {
.to_lowercase();

let mut out = env.stdout();
writeln!(out, "{}.", hash).unwrap();
writeln!(out, "{}.", hash);
Ok(())
}
}
Expand Down
9 changes: 5 additions & 4 deletions src/env/fake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::sync::Mutex;
use crate::{error::Error, parse_args, run, Args};

use super::Env;
use super::Stream;

/// A command to run in a [`FakeEnv`]
///
Expand Down Expand Up @@ -45,12 +46,12 @@ impl Env for FakeEnv {
self.cmd.cmd.iter().map(Into::into)
}

fn stdout(&self) -> impl fmt::Write {
self.stdout.clone()
fn stdout(&self) -> Stream<impl fmt::Write> {
Stream(self.stdout.clone())
}

fn stderr(&self) -> impl fmt::Write {
self.stderr.clone()
fn stderr(&self) -> Stream<impl fmt::Write> {
Stream(self.stderr.clone())
}
}

Expand Down
27 changes: 23 additions & 4 deletions src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,36 @@ pub trait Env {
/// Get a reference to stdout
///
/// Equivalent to [`std::io::stdout`]
fn stdout(&self) -> impl fmt::Write;
fn stdout(&self) -> Stream<impl fmt::Write>;

/// Get a reference to stderr
///
/// Equivalent to [`std::io::stderr`]
fn stderr(&self) -> impl fmt::Write;
fn stderr(&self) -> Stream<impl fmt::Write>;

// /// Get a reference to stdin
// fn stdin(&self) -> impl io::Read;
}

/// A type with an infallible `write_fmt` method for use with [`write!`] macros
///
/// This ensures that we don't have to `use` either [`std::fmt::Write`] or
/// [`std::io::Write`]. Additionally, this `write_fmt` does not return a
/// result. This means that we can use the [`write!`] and [`writeln`] macros
/// without handling errors.
pub struct Stream<T: fmt::Write>(T);

impl<T: fmt::Write> Stream<T> {
pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) {
// This unwrap is not _really_ safe, but we are using this as stdout.
// The `println` macro also ignores errors and `push_str` of the
// fake stream also does not return an error. If this fails, it means
// we can't write to stdout anymore so a graceful exit will be very
// hard anyway.
self.0.write_fmt(args).unwrap();
}
}

impl<E: Env> Env for &E {
// fn make_connection(&self) {
// todo!()
Expand All @@ -47,11 +66,11 @@ impl<E: Env> Env for &E {
(**self).args_os()
}

fn stdout(&self) -> impl fmt::Write {
fn stdout(&self) -> Stream<impl fmt::Write> {
(**self).stdout()
}

fn stderr(&self) -> impl fmt::Write {
fn stderr(&self) -> Stream<impl fmt::Write> {
(**self).stderr()
}
}
9 changes: 5 additions & 4 deletions src/env/real.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fmt;
use std::io;

use super::Env;
use super::Stream;

/// Use real I/O
pub struct RealEnv;
Expand All @@ -12,12 +13,12 @@ impl Env for RealEnv {
std::env::args_os()
}

fn stdout(&self) -> impl fmt::Write {
FmtWriter(io::stdout())
fn stdout(&self) -> Stream<impl fmt::Write> {
Stream(FmtWriter(io::stdout()))
}

fn stderr(&self) -> impl fmt::Write {
FmtWriter(io::stderr())
fn stderr(&self) -> Stream<impl fmt::Write> {
Stream(FmtWriter(io::stderr()))
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::env::Env;
use std::fmt::{self, Write};
use std::fmt;
use std::{error, io};

//------------ Error ---------------------------------------------------------
Expand Down Expand Up @@ -63,7 +63,7 @@ impl Error {
// line arguments either. So we just print the styled string that
// clap produces and return.
PrimaryError::Clap(e) => {
let _ = writeln!(err, "{}", e.render().ansi());
writeln!(err, "{}", e.render().ansi());
return;
}
PrimaryError::Other(error) => error,
Expand All @@ -80,9 +80,9 @@ impl Error {
"ERROR:"
};

let _ = write!(err, "[{prog}] {error_marker} {error}");
write!(err, "[{prog}] {error_marker} {error}");
for context in &self.0.context {
let _ = writeln!(err, "\n... while {context}");
writeln!(err, "\n... while {context}");
}
}

Expand Down

0 comments on commit a014f13

Please sign in to comment.