aoc_solver/
lib.rs

1use std::{error, fmt};
2
3pub struct Problem {
4    year: u16,
5    day: u8,
6    title: &'static str,
7    parts: u8,
8    parse: for<'a> fn(&'a str) -> Result<Box<dyn Solver>, ParseError<'a>>,
9}
10
11impl Problem {
12    pub fn year(&self) -> u16 {
13        self.year
14    }
15    pub fn day(&self) -> u8 {
16        self.day
17    }
18    pub fn title(&self) -> &str {
19        self.title
20    }
21    pub fn parts(&self) -> u8 {
22        self.parts
23    }
24    pub fn parse<'a>(&self, input: &'a str) -> Result<Box<dyn Solver>, ParseError<'a>> {
25        (self.parse)(input)
26    }
27    pub fn solve_all<'a>(&self, input: &'a str) -> Result<Vec<String>, ParseError<'a>> {
28        let mut res = Vec::<String>::new();
29        let mut solver = self.parse(input)?;
30        for part in 1..=self.parts {
31            res.push(solver.solve(part).unwrap());
32        }
33        Ok(res)
34    }
35}
36
37impl fmt::Display for Problem {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        write!(f, "Day {}: {}", self.day, self.title)
40    }
41}
42
43#[derive(Debug)]
44pub struct ParseError<'a> {
45    msg: &'static str,
46    line: usize,
47    pos: usize,
48    source: Option<Box<dyn error::Error + 'static>>,
49    arg: &'a str,
50}
51
52impl<'a> PartialEq for ParseError<'a> {
53    fn eq(&self, rhs: &Self) -> bool {
54        let left = (self.msg, self.line, self.pos, self.arg);
55        let right = (rhs.msg, rhs.line, rhs.pos, rhs.arg);
56        left == right
57    }
58}
59
60impl<'a> fmt::Display for ParseError<'a> {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        write!(f, "{}:{} {}", self.line, self.pos, self.msg)?;
63        if let Some(inner) = &self.source {
64            write!(f, ": {}", inner)?;
65        }
66        if !self.arg.is_empty() {
67            write!(f, ": {}", self.arg)?;
68        }
69        Ok(())
70    }
71}
72
73impl<'a> error::Error for ParseError<'a> {
74    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
75        Some(self.source.as_ref()?.as_ref())
76    }
77}
78
79#[derive(Debug, PartialEq)]
80pub enum SolveError {
81    NotImplemented,
82    PartNotFound(u8),
83}
84
85impl fmt::Display for SolveError {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        match self {
88            SolveError::NotImplemented => write!(f, "Not implemented")?,
89            SolveError::PartNotFound(part) => write!(f, "Part#{part} not found")?,
90        }
91        Ok(())
92    }
93}
94
95impl error::Error for SolveError {}
96
97pub trait Solver {
98    fn solve(&mut self, part: u8) -> Result<String, SolveError>;
99}
100
101mod y2015 {
102    pub mod d1;
103    pub mod d2;
104    pub mod d3;
105    pub mod d4;
106    pub mod d5;
107}
108
109pub const PROBLEMS: [Problem; 5] = [
110    y2015::d1::PROBLEM,
111    y2015::d2::PROBLEM,
112    y2015::d3::PROBLEM,
113    y2015::d4::PROBLEM,
114    y2015::d5::PROBLEM,
115];
116
117#[cfg(test)]
118mod tests {
119    #[test]
120    fn problems_order() {
121        let mut year: u16 = 0;
122        let mut day: u8 = 0;
123        for problem in super::PROBLEMS {
124            if year < problem.year() {
125                year = problem.year();
126                day = 0;
127            }
128            assert!(year == problem.year());
129            assert!(day < problem.day());
130            day = problem.day();
131            assert!(year >= 2015 && year < 2024);
132            assert!(day >= 1 && day <= 25);
133            assert_eq!(problem.parts(), 2)
134        }
135    }
136}