aoc_ornaments/
lib.rs

1use std::str::FromStr;
2
3pub mod bits;
4pub mod intcode;
5pub mod linear;
6pub mod nom;
7pub mod scoring;
8pub mod spatial;
9
10/// Shared behavior amongst AOC/Everybody.codes solutions
11///
12/// [FromStr] is a supertrait because we ALWAYS have to parse string input
13pub trait Solution: FromStr {
14    /// Ensures the output can be converted to a string
15    type Output: std::fmt::Display + Default;
16
17    /// Required for AoC
18    fn part1(&mut self) -> SolutionResult<Self::Output> {
19        todo!()
20    }
21
22    /// Required for AoC
23    fn part2(&mut self) -> SolutionResult<Self::Output> {
24        todo!()
25    }
26
27    /// Optional, for everybody.codes or bonus AoC
28    fn part3(&mut self) -> SolutionResult<Self::Output> {
29        Ok(Self::Output::default())
30    }
31
32    fn solve(&mut self, which: Part) -> SolutionResult<String> {
33        Ok(match which {
34            Part::One => self.part1()?.to_string(),
35            Part::Two => self.part2()?.to_string(),
36            Part::Three => self.part3()?.to_string(),
37        })
38    }
39}
40
41/// accepts a signle argument, which may be a tuple
42pub trait ArgSolution<A>: FromStr {
43    /// Ensures the output can be converted to a string
44    type Output: std::fmt::Display + Default;
45
46    /// Required for AoC
47    fn part1(&mut self, _args: A) -> SolutionResult<Self::Output> {
48        todo!()
49    }
50
51    /// Required for AoC
52    fn part2(&mut self, _args: A) -> SolutionResult<Self::Output> {
53        todo!()
54    }
55
56    /// Optional, for everybody.codes or bonus AoC
57    fn part3(&mut self, _args: A) -> SolutionResult<Self::Output> {
58        Ok(Self::Output::default())
59    }
60
61    fn solve(&mut self, which: Part, args: A) -> SolutionResult<String> {
62        Ok(match which {
63            Part::One => ArgSolution::part1(self, args)?.to_string(),
64            Part::Two => ArgSolution::part2(self, args)?.to_string(),
65            Part::Three => ArgSolution::part3(self, args)?.to_string(),
66        })
67    }
68}
69
70/// Puzzle parts
71#[derive(Debug, Clone, Copy)]
72pub enum Part {
73    /// AoC
74    One,
75    /// AoC
76    Two,
77    /// for everybody.codes
78    Three,
79}
80
81#[cfg(feature = "miette")]
82pub type SolutionResult<T> = miette::Result<T>;
83#[cfg(not(feature = "miette"))]
84pub type SolutionResult<T> = Result<T, Box<dyn std::error::Error>>;
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    struct Day;
91
92    impl Solution for Day {
93        type Output = String;
94
95        fn part1(&mut self) -> miette::Result<Self::Output> {
96            Ok("Hello, Rudolph!".into())
97        }
98
99        fn part2(&mut self) -> miette::Result<Self::Output> {
100            Ok("Hello, Santa!".into())
101        }
102    }
103
104    impl FromStr for Day {
105        type Err = miette::Error;
106
107        fn from_str(_input: &str) -> miette::Result<Self> {
108            Ok(Self)
109        }
110    }
111
112    #[test]
113    fn test_part_1() -> miette::Result<()> {
114        let mut day = Day::from_str("")?;
115
116        let solution = day.solve(Part::One)?;
117        assert_eq!("Hello, Rudolph!".to_string(), solution);
118        Ok(())
119    }
120
121    #[test]
122    fn test_part_2() -> miette::Result<()> {
123        let mut day: Day = "".parse()?;
124
125        let solution = day.solve(Part::Two)?;
126        assert_eq!("Hello, Santa!".to_string(), solution);
127        Ok(())
128    }
129
130    #[test]
131    fn test_part_3() {
132        let mut day = Day;
133
134        let solution = day.solve(Part::Three).unwrap();
135        assert_eq!("".to_string(), solution);
136    }
137}