Write to stdout, stderr or file

This is the pattern I often use when writing command-line programs:

use std::env;
use std::fs::File;
use std::io::{self, Error, Write};
use std::path::PathBuf;

fn main() {
    let args = Args::from_env();

    let mut output = args.get_output().unwrap();

    writeln!(output, "Hello, World!").unwrap();
}

#[derive(Debug)]
struct Args {
    /// write to the provided file, or `stdout` when not provided
    output: Option<PathBuf>,
}

impl Args {
    // I'd usually use clap or structopt for command-line argument parsing...
    fn from_env() -> Args {
        Args {
            output: env::args().nth(1).map(PathBuf::from),
        }
    }

    fn get_output(&self) -> Result<Box<dyn Write>, Error> {
        match self.output {
            Some(ref path) => File::open(path).map(|f| Box::new(f) as Box<dyn Write>),
            None => Ok(Box::new(io::stdout())),
        }
    }
}
4 Likes