Skip to content

Commit

Permalink
remove consts::* re-export and improvements/fixes to docs
Browse files Browse the repository at this point in the history
  • Loading branch information
drmason13 committed May 7, 2021
1 parent dbfdb6d commit 61d6a90
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 28 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
3 changes: 2 additions & 1 deletion examples/without_parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ impl Solution<Day3> for AdventOfCode2020 {
impl ParseInput<Day3> 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) {}
}
25 changes: 20 additions & 5 deletions src/days.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
94 changes: 73 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//!
Expand Down Expand Up @@ -40,7 +40,7 @@
//! }
//!
//! # impl ParseInput<Day1> for AdventOfCode2020 {
//! # type Parsed = Vec<u32>; // <-- this will be the input to both part1 and part2 for Solution<Day1>
//! # type Parsed = Vec<u32>; // <-- the input to both part1 and part2 for Solution<Day1>
//! #
//! # fn parse_input(input: &str) -> Self::Parsed {
//! # input
Expand Down Expand Up @@ -82,7 +82,7 @@
//! // ..continued from above
//!
//! impl ParseInput<Day1> for AdventOfCode2020 {
//! type Parsed = Vec<u32>; // <-- this will be the input to both part1 and part2 for Solution<Day1>
//! type Parsed = Vec<u32>; // <-- the input to both part1 and part2 for Solution<Day1>
//!
//! fn parse_input(input: &str) -> Self::Parsed {
//! input
Expand All @@ -96,13 +96,13 @@
//! # assert_eq!(vec![1, 2, 3], <AdventOfCode2020 as ParseInput<Day1>>::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;
//! #
Expand All @@ -121,7 +121,7 @@
//! # }
//! # }
//! # impl ParseInput<Day1> for AdventOfCode2020 {
//! # type Parsed = Vec<u32>; // <-- this will be the input to both part1 and part2 for Solution<Day1>
//! # type Parsed = Vec<u32>; // <-- the input to both part1 and part2 for Solution<Day1>
//! #
//! # fn parse_input(input: &str) -> Self::Parsed {
//! # input
Expand All @@ -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;
///
Expand All @@ -165,14 +160,15 @@ pub mod consts {
/// // your solution to part1 here...
/// # 1
/// }
///
/// fn part2(input: &Vec<u32>) -> u32 {
/// // your solution to part2 here...
/// # 2
/// }
/// }
/// #
/// # impl ParseInput<Day1> for AdventOfCode2020 {
/// # type Parsed = Vec<u32>; // <-- this will be the input to both part1 and part2 for Solution<Day1>
/// # type Parsed = Vec<u32>; // <-- the input to both part1 and part2 for Solution<Day1>
/// #
/// # fn parse_input(input: &str) -> Self::Parsed {
/// # input
Expand All @@ -185,12 +181,61 @@ pub mod consts {
pub trait Solution<const Day: u32>:
ParseEachInput<Day, Part1> + ParseEachInput<Day, Part2>
{
/// The type output by
type Part1Output: std::fmt::Display;
type Part2Output: std::fmt::Display;

fn part1(input: &<Self as ParseEachInput<Day, Part1>>::Parsed) -> Self::Part1Output;
fn part2(input: &<Self as ParseEachInput<Day, Part2>>::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<Day1> for AdventOfCode2020 {
/// type Part1Output = u32;
/// type Part2Output = u32;
/// fn part1(input: &Vec<u32>) -> u32 {
/// // your solution to part1 here...
/// # 1
/// }
///
/// fn part2(input: &Vec<u32>) -> u32 {
/// // your solution to part2 here...
/// # 2
/// }
///
/// fn run(input: &str) {
/// let shared_parsed_input = <Self as ParseInput<Day1>>::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<Day1> for AdventOfCode2020 {
/// # type Parsed = Vec<u32>; // <-- the input to both part1 and part2 for Solution<Day1>
/// #
/// # 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 = <Self as ParseEachInput<Day, Part1>>::parse_input(input);
let part2_parsed_input = <Self as ParseEachInput<Day, Part2>>::parse_input(input);
Expand All @@ -209,9 +254,11 @@ pub trait Solution<const Day: u32>:
}
}

/// 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
///
Expand Down Expand Up @@ -250,14 +297,18 @@ pub trait Solution<const Day: u32>:
/// assert_eq!(Some(&2), part2_input.values().next());
/// ```
pub trait ParseEachInput<const Day: u32, const Part: u32> {
/// 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
///
Expand All @@ -283,11 +334,12 @@ pub trait ParseEachInput<const Day: u32, const Part: u32> {
/// assert_eq!(part1_input, part2_input);
/// ```
pub trait ParseInput<const Day: u32> {
/// 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<T, const Day: u32> ParseEachInput<Day, Part1> for T
Expand Down

0 comments on commit 61d6a90

Please sign in to comment.