use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::fs::File; use std::io::{BufReader, Read}; use std::str::FromStr; use clap::{App, AppSettings::ArgRequiredElseHelp, Arg}; #[derive(Debug)] enum DaysImplemented { Day1, Day2, Day3, Day4, } impl Display for DaysImplemented { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { DaysImplemented::Day1 => { write!(f, "Day 1") } DaysImplemented::Day2 => { write!(f, "Day 2") } DaysImplemented::Day3 => { write!(f, "Day 3") } DaysImplemented::Day4 => { write!(f, "Day 4") } } } } impl FromStr for DaysImplemented { type Err = &'static str; fn from_str(s: &str) -> Result { match s { "Day1" => Ok(DaysImplemented::Day1), "Day2" => Ok(DaysImplemented::Day2), "Day3" => Ok(DaysImplemented::Day3), "Day4" => Ok(DaysImplemented::Day4), _ => Err("Not any of days implemented"), } } } fn main() -> Result<(), Box> { let matches = App::new("AdventOfCode2021") .author("Anthony Cicchetti") .setting(ArgRequiredElseHelp) .arg( Arg::new("day_to_execute") .short('d') .long("day") .takes_value(true) .possible_values(vec!["Day1", "Day2", "Day3", "Day4"]) .help("Which day should be executed?"), ) .arg( Arg::new("part") .short('p') .long("part") .takes_value(true) .possible_values(vec!["1", "2"]) .help("Which part to execute?"), ) .arg( Arg::new("input_file") .short('f') .long("file") .takes_value(true) .validator(file_exists) .conflicts_with("input_string") .help("Input File"), ) .arg( Arg::new("input_string") .required_unless_present("input_file") .help("Input string"), ) .get_matches(); let day: DaysImplemented = matches.value_of_t("day_to_execute").unwrap(); // Safe unwrap because value is required let part: usize = matches.value_of_t("part").unwrap(); // Same as above let input: String = match matches.value_of("input_file") { None => matches.value_of_t("input_string").unwrap(), Some(path) => { let mut s = String::new(); let _ = BufReader::new(File::open(path)?).read_to_string(&mut s); s } }; println!("Executing {}, Part {}", day, part); match (day, part) { (DaysImplemented::Day1, 1) => println!("{}", day_01::part1(&input)), (DaysImplemented::Day1, 2) => println!("{}", day_01::part2(&input)), (DaysImplemented::Day2, 1) => println!("{}", day_02::part1(&input)), (DaysImplemented::Day2, 2) => println!("{}", day_02::part2(&input)), (DaysImplemented::Day3, 1) => println!("{}", day_03::part1(&input)), (DaysImplemented::Day3, 2) => println!("{}", day_03::part2(&input)), (DaysImplemented::Day4, 1) => println!("{}", day_04::part1(&input)), _ => { unimplemented!() } }; Ok(()) } fn file_exists(val: &str) -> Result<(), String> { if std::fs::metadata(&val).is_ok() { Ok(()) } else { Err(format!("File at {} doesn't exist", &val)) } }