diff --git a/README.md b/README.md index 2e5eda6..278860c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## What is this? -This is [`advent_of_code_traits`](https://github.com/drmason13/advent_of_code_traits), a minimal, flexible framework for in implementing solutions to Advent of Code in Rust. +This is [`advent_of_code_traits`](https://github.com/drmason13/advent_of_code_traits), a minimal, flexible framework for implementing solutions to Advent of Code in Rust. It takes a trait-based approach using const-generics. diff --git a/examples/without_parsing.rs b/examples/without_parsing.rs index 6b8f7e2..b991326 100644 --- a/examples/without_parsing.rs +++ b/examples/without_parsing.rs @@ -51,5 +51,6 @@ impl Solution for AdventOfCode2020 { impl ParseInput for AdventOfCode2020 { type Parsed = (); - // we can omit the parse_input function and (not) use the default implementation + // you actually need this implementation to appease the compiler + fn parse_input(_input: &str) {} } diff --git a/src/days.rs b/src/days.rs index 360b5a0..09253c8 100644 --- a/src/days.rs +++ b/src/days.rs @@ -3,19 +3,34 @@ //! ## Examples //! //! In your module containing a solution for day 1 -//! ``` +//! ```no_run //! use advent_of_code_traits::days::Day1; //! ``` //! -//! These are just plain `u32`s. +//! They are just plain `u32`s. //! ``` //! # use advent_of_code_traits::days::Day1; //! assert_eq!(1, Day1); //! ``` //! -//! You don't have to use these consts where it doesn't make sense to -//! ``` -//! +//! You don't have to use these consts at all if you don't want to +//! ```no_run +//! # use advent_of_code_traits::{ParseInput, Solution}; +//! # pub struct AdventOfCode2020; +//! impl Solution<2> for AdventOfCode2020 { +//! # type Part1Output = u32; +//! # type Part2Output = u32; +//! // this works the same as `Day2` +//! # fn part1(input: &()) -> u32 {1} +//! # fn part2(input: &()) -> u32 {2} +//! } +//! # impl ParseInput<2> for AdventOfCode2020 { +//! # type Parsed = (); +//! # +//! # fn parse_input(input: &str) -> Self::Parsed { +//! # todo!() +//! # } +//! # } //! ``` include!(concat!(env!("OUT_DIR"), "/const_days.rs")); diff --git a/src/lib.rs b/src/lib.rs index 7eb6e8b..372dc32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! //! ## Usage //! -//! Please see also the [examples](./examples/). +//! Please see also the [examples](https://github.com/drmason13/advent_of_code_traits/tree/main/examples). //! //! Implement traits with your solutions to each Day of Advent of Code. //! @@ -40,7 +40,7 @@ //! } //! //! # impl ParseInput for AdventOfCode2020 { -//! # type Parsed = Vec; // <-- this will be the input to both part1 and part2 for Solution +//! # type Parsed = Vec; // <-- the input to both part1 and part2 for Solution //! # //! # fn parse_input(input: &str) -> Self::Parsed { //! # input @@ -82,7 +82,7 @@ //! // ..continued from above //! //! impl ParseInput for AdventOfCode2020 { -//! type Parsed = Vec; // <-- this will be the input to both part1 and part2 for Solution +//! type Parsed = Vec; // <-- the input to both part1 and part2 for Solution //! //! fn parse_input(input: &str) -> Self::Parsed { //! input @@ -96,13 +96,13 @@ //! # assert_eq!(vec![1, 2, 3], >::parse_input("1\n2\n3")); //! ``` //! -//! Please refer to the [examples](https://github.com/drmason13/advent_of_code_traits/examples) for more possibilities, +//! Please refer to the [examples](https://github.com/drmason13/advent_of_code_traits/tree/main/examples) for more possibilities, //! including parsing a different type for each Part and opting out of parsing entirely to work directly with the `&str`. //! //! ### Run from `main.rs` //! //! Here comes the ugly part. -//! ```rust,no_run +//! ```no_run //! # use advent_of_code_traits::{days::Day1, ParseInput, Solution}; //! # pub struct AdventOfCode2020; //! # @@ -121,7 +121,7 @@ //! # } //! # } //! # impl ParseInput for AdventOfCode2020 { -//! # type Parsed = Vec; // <-- this will be the input to both part1 and part2 for Solution +//! # type Parsed = Vec; // <-- the input to both part1 and part2 for Solution //! # //! # fn parse_input(input: &str) -> Self::Parsed { //! # input @@ -143,18 +143,13 @@ pub mod days; pub const Part1: u32 = 1; pub const Part2: u32 = 2; -pub mod consts { - pub use super::days::*; - pub use super::{Part1, Part2}; -} - /// Implement the [`Solution`] trait for each day of Advent of Code for your struct(s). /// /// Each day is a unique implementation, implement each on any struct you like. /// -/// ## Example Usage +/// ## Example /// -/// ```rust +/// ``` /// # use advent_of_code_traits::{days::Day1, ParseInput, Solution}; /// pub struct AdventOfCode2020; /// @@ -165,6 +160,7 @@ pub mod consts { /// // your solution to part1 here... /// # 1 /// } +/// /// fn part2(input: &Vec) -> u32 { /// // your solution to part2 here... /// # 2 @@ -172,7 +168,7 @@ pub mod consts { /// } /// # /// # impl ParseInput for AdventOfCode2020 { -/// # type Parsed = Vec; // <-- this will be the input to both part1 and part2 for Solution +/// # type Parsed = Vec; // <-- the input to both part1 and part2 for Solution /// # /// # fn parse_input(input: &str) -> Self::Parsed { /// # input @@ -185,12 +181,61 @@ pub mod consts { pub trait Solution: ParseEachInput + ParseEachInput { + /// The type output by type Part1Output: std::fmt::Display; type Part2Output: std::fmt::Display; fn part1(input: &>::Parsed) -> Self::Part1Output; fn part2(input: &>::Parsed) -> Self::Part2Output; + /// The default implementation of run will: + /// * parse your input for each part + /// * call `part1` and `part2` with their parsed inputs. + /// * Print a short summary to display the output + /// + /// You can provide your own implementation of this method to change this deafult behaviour. + /// + /// ## Example + /// + /// ``` + /// # use advent_of_code_traits::{days::Day1, ParseInput, Solution}; + /// pub struct AdventOfCode2020; + /// + /// impl Solution for AdventOfCode2020 { + /// type Part1Output = u32; + /// type Part2Output = u32; + /// fn part1(input: &Vec) -> u32 { + /// // your solution to part1 here... + /// # 1 + /// } + /// + /// fn part2(input: &Vec) -> u32 { + /// // your solution to part2 here... + /// # 2 + /// } + /// + /// fn run(input: &str) { + /// let shared_parsed_input = >::parse_input(input); + /// + /// let part1_output = Self::part1(&shared_parsed_input); + /// let part2_output = Self::part2(&shared_parsed_input); + /// + /// // maybe you prefer a single line output? + /// println!("Day{}: {} - {}", Day1, part1_output, part2_output); + /// } + /// + /// } + /// # impl ParseInput for AdventOfCode2020 { + /// # type Parsed = Vec; // <-- the input to both part1 and part2 for Solution + /// # + /// # fn parse_input(input: &str) -> Self::Parsed { + /// # input + /// # .lines() + /// # .map(|s| s.parse().expect("invalid integer")) + /// # .collect() + /// # } + /// # } + /// ``` fn run(input: &str) { let part1_parsed_input = >::parse_input(input); let part2_parsed_input = >::parse_input(input); @@ -209,9 +254,11 @@ pub trait Solution: } } -/// Implement [`ParseEachInput`] if you need a different input for each Part of a Day. +/// Implement this trait if you need a different input for each part of a day. +/// +/// This trait is generic over both day and part. /// -/// This trait is generic over both Day and Part. +/// See also [`ParseInput`] which you should prefer implementing to use the *same* input type for each part of a day. /// /// ## Example Usage /// @@ -250,14 +297,18 @@ pub trait Solution: /// assert_eq!(Some(&2), part2_input.values().next()); /// ``` pub trait ParseEachInput { + /// The type that you want your [`Solution`] code to receive for a particular part of a day. type Parsed; + /// See [`ParseInput::parse_input`] fn parse_input(input: &str) -> Self::Parsed; } -/// Implement [`ParseInput`] to parse the `&str` that is the Day's input to get a type of your choosing to work with. +/// Implement this trait to parse the the day's input into a type. +/// +/// This trait is generic over day. /// -/// This trait is generic over Day. +/// See [`ParseEachInput`] if you want to use a *different* input type for each part of a day. /// /// ## Example Usage /// @@ -283,11 +334,12 @@ pub trait ParseEachInput { /// assert_eq!(part1_input, part2_input); /// ``` pub trait ParseInput { + /// The type that you want your [`Solution`] code to receive type Parsed; - fn parse_input(_input: &str) -> Self::Parsed { - unimplemented!() - } + /// This function receives the entire input file as a &str slice + /// and must return a [`Self::Parsed`] + fn parse_input(input: &str) -> Self::Parsed; } impl ParseEachInput for T