diff --git a/crates/aoc/src/lib.rs b/crates/aoc/src/lib.rs index 7313548..88717b7 100644 --- a/crates/aoc/src/lib.rs +++ b/crates/aoc/src/lib.rs @@ -1,4 +1,6 @@ mod puzzles; -pub mod years; +mod years; +pub use ::utils; pub use puzzles::{PuzzleFn, PUZZLES}; +pub use years::*; diff --git a/crates/aoc/src/puzzles.rs b/crates/aoc/src/puzzles.rs index 203ab8b..3a004fe 100644 --- a/crates/aoc/src/puzzles.rs +++ b/crates/aoc/src/puzzles.rs @@ -14,21 +14,25 @@ use utils::{ pub type PuzzleFn = fn(&str) -> Result<(String, String), InputError>; macro_rules! matcher { - ($([$(::$p:ident)+])*) => { + ($( + $y:literal => $year:ident{$( + $d:literal => $day:ident, + )*} + )*) => { /// Constant containing each puzzle solution. /// /// Each puzzle is represented by a tuple of [`Year`], [`Day`] and [`PuzzleFn`], which takes /// a input string and returns the part 1 and 2 solutions as strings, or an [`InputError`]. /// /// Generated from [`all_puzzles!`]. - pub const PUZZLES: &[(Year, Day, PuzzleFn)] = &[$( - ($(::$p)+::YEAR, $(::$p)+::DAY, |input: &str| { - let solution = $(::$p)+::new(input, InputType::Real)?; + pub const PUZZLES: &[(Year, Day, PuzzleFn)] = &[$($( + (crate::$year::$day::YEAR, crate::$year::$day::DAY, |input: &str| { + let solution = crate::$year::$day::new(input, InputType::Real)?; let part1 = solution.part1(); let part2 = solution.part2(); Ok((part1.to_string(), part2.to_string())) - }) - ),*]; + }), + )*)*]; }; } all_puzzles!(matcher); diff --git a/crates/aoc/src/years.rs b/crates/aoc/src/years.rs index 38706c4..0281419 100644 --- a/crates/aoc/src/years.rs +++ b/crates/aoc/src/years.rs @@ -1,8 +1,8 @@ //! Implementation for [`all_puzzles!`](crate::all_puzzles!). //! -//! Each of the re-exported macros below is either the `puzzles!` macro from the corresponding -//! crate if the corresponding feature is enabled, or the [`utils::puzzles_noop!`] no-op macro if -//! it is not. These macros are then chained together by [`all_puzzles!`](crate::all_puzzles!). +//! Each of the year crates is re-exported below if the corresponding feature is enabled, or a +//! placeholder crate with the [`utils::puzzles_noop!`] no-op `puzzles!` macro if it is not. +//! The `puzzles!` macros are then chained together by [`all_puzzles!`](crate::all_puzzles!). //! //! This main advantage of this approach over passing `#[cfg(feature = ?)]` attributes to the //! callback is that it prevents disabled years from being expanded at all, which should speed up @@ -12,23 +12,22 @@ // xtask update re-exports #[cfg(not(feature = "year2015"))] -pub use ::utils::puzzles_noop as year2015; +pub mod year2015 { + pub use ::utils::puzzles_noop as puzzles; +} #[cfg(not(feature = "year2016"))] -pub use ::utils::puzzles_noop as year2016; +pub mod year2016 { + pub use ::utils::puzzles_noop as puzzles; +} #[cfg(feature = "year2015")] -pub use ::year2015::puzzles as year2015; +pub use ::year2015; #[cfg(feature = "year2016")] -pub use ::year2016::puzzles as year2016; +pub use ::year2016; /// Macro which invokes a callback macro with a list of all implemented puzzle solutions. /// -/// This macro chains re-exported `puzzles!` macros in [`aoc::years`](self), provided by each year -/// crate. -/// -/// The callback macro will be called once, with all solutions, which allows generation of complete -/// match statements. The paths can be matched with `$([$(::$p:ident)+])*`. `$([$p:path])*` can also -/// be used, but it has [limitations](https://github.com/rust-lang/rust/issues/48067) making it far -/// less useful. +/// This macro chains `puzzles!` macros in the re-exported year modules. The callback macro will be +/// called once with all the solutions, which makes it easy to generate match statements or arrays. /// /// Running `cargo xtask update` will automatically update the chain of year macros. /// @@ -38,24 +37,28 @@ pub use ::year2016::puzzles as year2016; /// /// ``` /// # use aoc::all_puzzles; -/// # use utils::{PuzzleExamples, Puzzle}; +/// # use utils::PuzzleExamples; /// # use utils::input::InputType; /// # /// macro_rules! callback { -/// ($([$(::$p:ident)+])*) => {$( -/// println!("{} {}", $(::$p)+::YEAR, $(::$p)+::DAY);/// -/// for (input_str, p1, p2) in $(::$p)+::EXAMPLES.iter() { -/// let solution = $(::$p)+::new(input_str, InputType::Example).unwrap(); +/// ($( +/// $y:literal => $year:ident{$( +/// $d:literal => $day:ident, +/// )*} +/// )*) => {$($( +/// println!("{} {}", $y, $d); +/// for (input_str, p1, p2) in aoc::$year::$day::EXAMPLES { +/// let solution = aoc::$year::$day::new(input_str, InputType::Example).unwrap(); /// println!(" parse({input_str}) = {solution:?}"); /// if (p1.is_some()) { println!(" part1(...) = {}", solution.part1()); } /// if (p2.is_some()) { println!(" part2(...) = {}", solution.part2()); } /// } -/// )*}; +/// )*)*}; /// } /// all_puzzles!(callback); /// ``` /// -/// Generating a match statement and passing extra arguments: +/// Generating a match statement: /// /// ``` /// # use aoc::all_puzzles; @@ -64,27 +67,31 @@ pub use ::year2016::puzzles as year2016; /// # /// fn example_count(year: Year, day: Day) -> Option { /// macro_rules! callback { -/// ($year:ident $day:ident $([$(::$p:ident)+])*) => { -/// match ($year, $day) { -/// $( -/// ($(::$p)+::YEAR, $(::$p)+::DAY) => Some($(::$p)+::EXAMPLES.len()), -/// )* +/// ($( +/// $y:literal => $year:ident{$( +/// $d:literal => $day:ident, +/// )*} +/// )*) => { +/// match (year, day) { +/// $($( +/// (aoc::$year::$day::YEAR, aoc::$year::$day::DAY) => Some(aoc::$year::$day::EXAMPLES.len()), +/// )*)* /// _ => None, /// } /// }; /// } -/// all_puzzles!{callback, year, day} +/// all_puzzles!{callback} /// } /// ``` #[allow(clippy::module_name_repetitions)] // Once exported name is aoc::all_puzzles #[macro_export] macro_rules! all_puzzles { ($callback:path $(,$arg:tt)*$(,)?) => { - ::utils::puzzles_noop!{ + $crate::utils::puzzles_noop!{ [ // xtask update all_puzzles - $crate::years::year2015, - $crate::years::year2016, + $crate::year2015::puzzles, + $crate::year2016::puzzles, $callback ] diff --git a/crates/utils/src/framework.rs b/crates/utils/src/framework.rs index 6ecb010..7f88edb 100644 --- a/crates/utils/src/framework.rs +++ b/crates/utils/src/framework.rs @@ -23,9 +23,9 @@ pub trait PuzzleExamples $crate_name{$( + $day => $day_struct, + )+} } } } diff --git a/crates/xtask/src/cmd/update.rs b/crates/xtask/src/cmd/update.rs index f5e86d3..40751dc 100644 --- a/crates/xtask/src/cmd/update.rs +++ b/crates/xtask/src/cmd/update.rs @@ -92,7 +92,7 @@ fn update_aoc_years_rs(aoc_dir: &Path, years: &[Year]) -> Result<(), Box Result<(), Box