diff --git a/src/day.rs b/src/day.rs index f1486e5..0f7325c 100644 --- a/src/day.rs +++ b/src/day.rs @@ -27,8 +27,9 @@ impl Day { Some(Self(day)) } - fn new_unchecked(day: u8) -> Self { - debug_assert!(day != 0 && day <= 25); + // Not part of the public API + #[doc(hidden)] + pub const fn __new_unchecked(day: u8) -> Self { Self(day) } @@ -99,7 +100,7 @@ impl Iterator for EveryDay { return None; } // NOTE: the iterator start at 1 and we have verified that the value is not above 25. - let day = Day::new_unchecked(self.current); + let day = Day(self.current); self.current += 1; Some(day) @@ -108,6 +109,24 @@ impl Iterator for EveryDay { /* -------------------------------------------------------------------------- */ +/// Crates a [`Day`] value in a const context. +#[macro_export] +macro_rules! day { + ($day:expr) => {{ + const _ASSERT: () = assert!( + $day != 0 && $day <= 25, + concat!( + "invalid day number `", + $day, + "`, expecting a value between 1 and 25" + ), + ); + $crate::Day::__new_unchecked($day) + }}; +} + +/* -------------------------------------------------------------------------- */ + #[cfg(feature = "test_lib")] mod tests { use super::{every_day, Day}; diff --git a/src/template/commands/scaffold.rs b/src/template/commands/scaffold.rs index d4df4b9..382283d 100644 --- a/src/template/commands/scaffold.rs +++ b/src/template/commands/scaffold.rs @@ -14,7 +14,7 @@ pub fn part_two(input: &str) -> Option { None } -advent_of_code::main!(DAY); +advent_of_code::main!(DAY_NUMBER); #[cfg(test)] mod tests { @@ -55,7 +55,11 @@ pub fn handle(day: Day) { } }; - match file.write_all(MODULE_TEMPLATE.replace("DAY", &day.to_string()).as_bytes()) { + match file.write_all( + MODULE_TEMPLATE + .replace("DAY_NUMBER", &day.into_inner().to_string()) + .as_bytes(), + ) { Ok(()) => { println!("Created module file \"{}\"", &module_path); } diff --git a/src/template/mod.rs b/src/template/mod.rs index faddf0a..215f039 100644 --- a/src/template/mod.rs +++ b/src/template/mod.rs @@ -1,3 +1,4 @@ +use crate::Day; use std::{env, fs}; pub mod aoc_cli; @@ -10,12 +11,10 @@ pub const ANSI_BOLD: &str = "\x1b[1m"; pub const ANSI_RESET: &str = "\x1b[0m"; /// Helper function that reads a text file to a string. -#[must_use] pub fn read_file(folder: &str, day: u8) -> String { +#[must_use] +pub fn read_file(folder: &str, day: Day) -> String { let cwd = env::current_dir().unwrap(); - let filepath = cwd - .join("data") - .join(folder) - .join(format!("{day:02}.txt")); + let filepath = cwd.join("data").join(folder).join(format!("{day}.txt")); let f = fs::read_to_string(filepath); f.expect("could not open input file") } @@ -24,11 +23,14 @@ pub const ANSI_RESET: &str = "\x1b[0m"; #[macro_export] macro_rules! main { ($day:expr) => { + /// The current day. + const DAY: advent_of_code::Day = advent_of_code::day!($day); + fn main() { use advent_of_code::template::runner::*; - let input = advent_of_code::template::read_file("inputs", $day); - run_part(part_one, &input, $day, 1); - run_part(part_two, &input, $day, 2); + let input = advent_of_code::template::read_file("inputs", DAY); + run_part(part_one, &input, DAY, 1); + run_part(part_two, &input, DAY, 2); } }; }