mirror of
https://github.com/Noratrieb/advent-of-code.git
synced 2026-01-14 17:45:02 +01:00
binaries!
This commit is contained in:
parent
13ac9a70ce
commit
5dff963dc2
8 changed files with 286 additions and 69 deletions
101
helper/src/cmd.rs
Normal file
101
helper/src/cmd.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
use std::{borrow::Cow, process};
|
||||
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
|
||||
use crate::{Day, Variant};
|
||||
|
||||
pub fn main<D: Day>(default_input: &str) -> ! {
|
||||
let mut part1 = Command::new("part1").about("Runs the part 1 program");
|
||||
let mut part2 = Command::new("part2").about("Runs the part 2 program");
|
||||
|
||||
part1 = create_variant_subcommands(part1, &D::part1().variants);
|
||||
part2 = create_variant_subcommands(part2, &D::part2().variants);
|
||||
|
||||
let mut typename = std::any::type_name::<D>().split("::").collect::<Vec<_>>();
|
||||
let typename = typename.pop().unwrap();
|
||||
let cmd = Command::new(typename.to_lowercase())
|
||||
.about(format!(
|
||||
"Program to run the AOC answer for day {}",
|
||||
typename.strip_prefix("Day").unwrap()
|
||||
))
|
||||
.subcommand_required(true)
|
||||
.subcommand(part1)
|
||||
.subcommand(part2);
|
||||
|
||||
let matches = cmd.clone().get_matches();
|
||||
|
||||
match matches.subcommand() {
|
||||
Some(("part1", matches)) => {
|
||||
let variants = D::part1().variants;
|
||||
dispatch_root_subcommand::<D>(default_input, &variants, matches);
|
||||
}
|
||||
Some(("part2", matches)) => {
|
||||
let variants = D::part2().variants;
|
||||
dispatch_root_subcommand::<D>(default_input, &variants, matches);
|
||||
}
|
||||
_ => {
|
||||
unreachable!("subcommand_required")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_variant_subcommands(mut part: Command, variants: &[Variant]) -> Command {
|
||||
if variants.len() > 1 {
|
||||
part = part.subcommand_required(true);
|
||||
|
||||
variants
|
||||
.iter()
|
||||
.map(|v| {
|
||||
Command::new(v.name)
|
||||
.about(format!("Run the {} variant", v.name))
|
||||
.arg(Arg::new("input").short('i').long("input"))
|
||||
})
|
||||
.for_each(|cmd| part = part.clone().subcommand(cmd));
|
||||
} else {
|
||||
part = part.arg(Arg::new("input").short('i').long("input"));
|
||||
}
|
||||
|
||||
part
|
||||
}
|
||||
|
||||
fn dispatch_root_subcommand<D: Day>(
|
||||
default_input: &str,
|
||||
variants: &[Variant],
|
||||
matches: &ArgMatches,
|
||||
) -> ! {
|
||||
if variants.len() > 1 {
|
||||
let subcommand = matches.subcommand().unwrap();
|
||||
let variant = variants.iter().find(|v| v.name == subcommand.0).unwrap();
|
||||
let input = get_input(subcommand.1, default_input);
|
||||
execute::<D>(variant, &input);
|
||||
} else {
|
||||
let input = get_input(matches, default_input);
|
||||
execute::<D>(&variants[0], &input);
|
||||
}
|
||||
}
|
||||
|
||||
fn execute<D: Day>(variant: &Variant, input: &str) -> ! {
|
||||
use std::io::Write;
|
||||
let input = D::pad_input(input);
|
||||
let result = (variant.f)(&input);
|
||||
let err = write!(std::io::stdout(), "{result}\n");
|
||||
if let Err(err) = err {
|
||||
if err.kind() != std::io::ErrorKind::BrokenPipe {
|
||||
eprintln!("error: {err}");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
fn get_input<'a>(matches: &ArgMatches, default: &'a str) -> Cow<'a, str> {
|
||||
matches
|
||||
.get_one::<String>("input")
|
||||
.map(|input| {
|
||||
Cow::Owned(std::fs::read_to_string(input).unwrap_or_else(|err| {
|
||||
eprintln!("error: failed to read file {input}: {err}");
|
||||
process::exit(1);
|
||||
}))
|
||||
})
|
||||
.unwrap_or(Cow::Borrowed(default))
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
mod cmd;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use nom::{character::complete::digit1, combinator::map, IResult};
|
||||
|
||||
pub use self::cmd::main;
|
||||
|
||||
pub type Solution = fn(&str) -> u64;
|
||||
|
||||
pub trait Day {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue