From a014f13c09996116360be16224f568372cc33289 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Fri, 15 Nov 2024 16:13:35 +0100 Subject: [PATCH] Make the output of `Env::std{out, err}` a concrete type (#27) * make the output of Env::std{out, err} a concrete type * document why the unwrap in write_fmt is okay --- src/commands/nsec3hash.rs | 3 +-- src/env/fake.rs | 9 +++++---- src/env/mod.rs | 27 +++++++++++++++++++++++---- src/env/real.rs | 9 +++++---- src/error.rs | 8 ++++---- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/commands/nsec3hash.rs b/src/commands/nsec3hash.rs index 1b175fe..50917cc 100644 --- a/src/commands/nsec3hash.rs +++ b/src/commands/nsec3hash.rs @@ -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}; @@ -136,7 +135,7 @@ impl Nsec3Hash { .to_lowercase(); let mut out = env.stdout(); - writeln!(out, "{}.", hash).unwrap(); + writeln!(out, "{}.", hash); Ok(()) } } diff --git a/src/env/fake.rs b/src/env/fake.rs index f02c66a..f9d4cde 100644 --- a/src/env/fake.rs +++ b/src/env/fake.rs @@ -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`] /// @@ -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 { + Stream(self.stdout.clone()) } - fn stderr(&self) -> impl fmt::Write { - self.stderr.clone() + fn stderr(&self) -> Stream { + Stream(self.stderr.clone()) } } diff --git a/src/env/mod.rs b/src/env/mod.rs index 717554e..b00b57d 100644 --- a/src/env/mod.rs +++ b/src/env/mod.rs @@ -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; /// Get a reference to stderr /// /// Equivalent to [`std::io::stderr`] - fn stderr(&self) -> impl fmt::Write; + fn stderr(&self) -> Stream; // /// 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); + +impl Stream { + 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 Env for &E { // fn make_connection(&self) { // todo!() @@ -47,11 +66,11 @@ impl Env for &E { (**self).args_os() } - fn stdout(&self) -> impl fmt::Write { + fn stdout(&self) -> Stream { (**self).stdout() } - fn stderr(&self) -> impl fmt::Write { + fn stderr(&self) -> Stream { (**self).stderr() } } diff --git a/src/env/real.rs b/src/env/real.rs index 69fb5e0..c854db4 100644 --- a/src/env/real.rs +++ b/src/env/real.rs @@ -3,6 +3,7 @@ use std::fmt; use std::io; use super::Env; +use super::Stream; /// Use real I/O pub struct RealEnv; @@ -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 { + Stream(FmtWriter(io::stdout())) } - fn stderr(&self) -> impl fmt::Write { - FmtWriter(io::stderr()) + fn stderr(&self) -> Stream { + Stream(FmtWriter(io::stderr())) } } diff --git a/src/error.rs b/src/error.rs index e800a59..fe9d286 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,5 @@ use crate::env::Env; -use std::fmt::{self, Write}; +use std::fmt; use std::{error, io}; //------------ Error --------------------------------------------------------- @@ -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, @@ -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}"); } }