Better CLI with clap and day runner macro
This commit is contained in:
@@ -4,7 +4,7 @@ use color_eyre::{
|
||||
Result,
|
||||
eyre::{Error, eyre},
|
||||
};
|
||||
use tracing::{debug, info, instrument};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
pub const INPUT: &str = include_str!("input/input.txt");
|
||||
|
||||
@@ -98,18 +98,6 @@ pub fn part2(input: &str) -> Result<i32> {
|
||||
Ok(visited_zero_count)
|
||||
}
|
||||
|
||||
pub fn solve() -> Result<()> {
|
||||
info!("Day 1");
|
||||
{
|
||||
let _span = tracing::info_span!("day01").entered();
|
||||
let p1 = part1(INPUT)?;
|
||||
info!("Part 1: {}", p1);
|
||||
let p2 = part2(INPUT)?;
|
||||
info!("Part 2: {}", p2);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -5,7 +5,7 @@ use color_eyre::{
|
||||
eyre::{Error, OptionExt, eyre},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use tracing::{debug, debug_span, info, info_span, instrument};
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
pub const INPUT: &str = include_str!("input/input.txt");
|
||||
|
||||
@@ -141,18 +141,6 @@ pub fn part2(input: &str) -> Result<i64> {
|
||||
Ok(total_invalid)
|
||||
}
|
||||
|
||||
pub fn solve() -> Result<()> {
|
||||
info!("Day 2");
|
||||
{
|
||||
let _span = info_span!("day02").entered();
|
||||
let p1 = part1(INPUT)?;
|
||||
info!("Part 1: {}", p1);
|
||||
let p2 = part2(INPUT)?;
|
||||
info!("Part 2: {}", p2);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
32
src/main.rs
32
src/main.rs
@@ -1,6 +1,9 @@
|
||||
mod runner;
|
||||
|
||||
pub mod day01;
|
||||
pub mod day02;
|
||||
|
||||
use clap::Parser;
|
||||
use color_eyre::Result;
|
||||
use tracing::info;
|
||||
use tracing_error::ErrorLayer;
|
||||
@@ -8,6 +11,24 @@ use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::fmt::format::FmtSpan;
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "Advent of Code 2025")]
|
||||
#[command(about = "Solutions for Advent of Code 2025", long_about = None)]
|
||||
struct Args {
|
||||
/// Day to run (1-25). If not specified, runs all days.
|
||||
#[arg(short, long)]
|
||||
day: Option<u8>,
|
||||
|
||||
/// Part to run (1 or 2). If not specified, runs all parts.
|
||||
#[arg(short, long)]
|
||||
part: Option<u8>,
|
||||
}
|
||||
|
||||
runner::days! {
|
||||
1 => day01,
|
||||
2 => day02,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
@@ -21,11 +42,12 @@ fn main() -> Result<()> {
|
||||
)
|
||||
.init();
|
||||
|
||||
let args = Args::parse();
|
||||
|
||||
info!("Advent of Code 2025");
|
||||
{
|
||||
let _span = tracing::info_span!("aoc").entered();
|
||||
day01::solve()?;
|
||||
day02::solve()?;
|
||||
}
|
||||
let _span = tracing::info_span!("aoc").entered();
|
||||
|
||||
run_days(args.day, args.part)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
57
src/runner.rs
Normal file
57
src/runner.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use color_eyre::Result;
|
||||
use tracing::info;
|
||||
|
||||
macro_rules! days {
|
||||
($($day_num:literal => $day_mod:ident),* $(,)?) => {
|
||||
pub fn run_days(day: Option<u8>, part: Option<u8>) -> Result<()> {
|
||||
match day {
|
||||
$(
|
||||
Some($day_num) => $crate::runner::run_day($day_num, part, $day_mod::part1, $day_mod::part2, $day_mod::INPUT)?,
|
||||
)*
|
||||
Some(d) => color_eyre::eyre::bail!("Day {} is not yet implemented", d),
|
||||
None => {
|
||||
$(
|
||||
$crate::runner::run_day($day_num, None, $day_mod::part1, $day_mod::part2, $day_mod::INPUT)?;
|
||||
)*
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use days;
|
||||
|
||||
pub fn run_day<T1, T2>(
|
||||
day: u8,
|
||||
part: Option<u8>,
|
||||
part1_fn: fn(&str) -> Result<T1>,
|
||||
part2_fn: fn(&str) -> Result<T2>,
|
||||
input: &str,
|
||||
) -> Result<()>
|
||||
where
|
||||
T1: std::fmt::Display,
|
||||
T2: std::fmt::Display,
|
||||
{
|
||||
info!("Day {}", day);
|
||||
let day_name = format!("{:02}", day);
|
||||
let _span = tracing::info_span!("day", day = %day_name).entered();
|
||||
|
||||
if part.is_none() || part == Some(1) {
|
||||
let result = part1_fn(input)?;
|
||||
info!("Part 1: {}", result);
|
||||
}
|
||||
|
||||
if part.is_none() || part == Some(2) {
|
||||
let result = part2_fn(input)?;
|
||||
info!("Part 2: {}", result);
|
||||
}
|
||||
|
||||
if let Some(p) = part {
|
||||
if p != 1 && p != 2 {
|
||||
color_eyre::eyre::bail!("Part {} is invalid. Must be 1 or 2.", p);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user