Advent of Code solutions
1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4
5fn make_day_mods(days: usize) -> String {
6 (1..=days)
7 .map(|day| format!("pub mod day_{day};", day = day))
8 .collect::<Vec<_>>()
9 .join("\n")
10}
11
12fn make_use_days(days: usize) -> String {
13 (1..=days)
14 .map(|day| format!("use day_{day}::Day{day};", day = day))
15 .collect::<Vec<_>>()
16 .join("\n")
17}
18
19fn make_day_match(inner: &str, days: usize) -> String {
20 (1..=days)
21 .map(|day| format!("{day} => {},", inner.replace("{day}", &day.to_string())))
22 .collect::<Vec<_>>()
23 .join("\n")
24}
25
26fn make_day_tests(days: usize) -> String {
27 (1..=days)
28 .map(|day| {
29 format!(
30 "
31 #[test]
32 fn test_day_{day}_part_1() {{
33 Day{day}::assert_part_1();
34 }}
35
36 #[test]
37 fn test_day_{day}_part_2() {{
38 Day{day}::assert_part_2();
39 }}"
40 )
41 })
42 .collect::<Vec<_>>()
43 .join("\n")
44}
45
46fn get_solve_day(days: usize) -> String {
47 let inner = make_day_match("Day{day}::run_part(part, input)", days);
48 let inner2 = make_day_match("{Day{day}::bench_part(part, input);}", days);
49 format!(
50 "
51 fn solve_day(day: usize, part: usize, input: Option<&str>) -> Option<String> {{
52 match day {{
53 {inner}
54 _ => None,
55 }}
56 }}
57 fn bench_day(day: usize, part: usize, input: Option<&str>) {{
58 match day {{
59 {inner2}
60 _ => panic!(\"Invalid Day\"),
61 }}
62 }}"
63 )
64}
65
66fn get_solve_day_both_parts(days: usize) -> String {
67 let inner = make_day_match("Day{day}::run_all_parts(extra_indent)", days);
68 format!(
69 "
70 fn solve_day_both_parts(day: usize, extra_indent: &str) {{
71 match day {{
72 {inner}
73 _ => (),
74 }}
75 }}",
76 inner = inner
77 )
78}
79
80fn make_year_struct(year: &str, days: usize) -> String {
81 format!(
82 "
83 pub struct Year{year};
84
85 impl Year for Year{year} {{
86 const YEAR: usize = {year};
87
88 {solve_day}
89
90 {solve_day_both_parts}
91 }}",
92 solve_day = get_solve_day(days),
93 solve_day_both_parts = get_solve_day_both_parts(days)
94 )
95}
96
97fn make_tests(days: usize) -> String {
98 format!(
99 "
100 #[cfg(test)]
101 mod tests {{
102 use super::*;
103 use advent_core::{{Day, Year}};
104
105 {day_tests}
106 }}",
107 day_tests = make_day_tests(days)
108 )
109}
110
111#[proc_macro]
112pub fn year(item: TokenStream) -> TokenStream {
113 let year = item.to_string();
114
115 let days = if year == "2024" { 25 } else { 12 };
116
117 let mods = make_day_mods(days);
118 let uses = make_use_days(days);
119
120 let year_struct = make_year_struct(&year, days);
121
122 let tests = make_tests(days);
123
124 format!(
125 "
126 {mods}
127
128 use advent_core::{{Year, Day}};
129 {uses}
130
131 {year_struct}
132
133 {tests}
134 "
135 )
136 .parse::<TokenStream>()
137 .unwrap()
138}
139
140#[proc_macro]
141pub fn year_runner(item: TokenStream) -> TokenStream {
142 let year = item.to_string();
143
144 format!(
145 "
146 use advent_core::{{Year, get_dp_and_input}};
147
148 use y_{year}::Year{year};
149
150 fn main() {{
151 let (dp, input) = get_dp_and_input();
152 Year{year}::run_dp(input.as_deref(), dp);
153 }}"
154 )
155 .parse::<TokenStream>()
156 .unwrap()
157}
158
159fn make_year_match(years: &[&str], inner: &str) -> String {
160 years
161 .iter()
162 .map(|year| format!("{year} => {},", inner.replace("{year}", year.as_ref())))
163 .collect::<Vec<_>>()
164 .join("\n")
165}
166
167fn make_year_uses(years: &[&str]) -> String {
168 years
169 .iter()
170 .map(|year| format!("use y_{year}::Year{year};", year = year))
171 .collect::<Vec<_>>()
172 .join("\n")
173}
174
175fn make_run_all_years(years: &[&str]) -> String {
176 years
177 .iter()
178 .map(|year| {
179 format!(
180 "Year{year}::run_dp(input.as_deref(), dp.clone());",
181 year = year
182 )
183 })
184 .collect::<Vec<_>>()
185 .join("\n")
186}
187
188fn make_run_year(years: &[&str]) -> String {
189 let inner = make_year_match(years, "Year{year}::run_dp(input.as_deref(), dp)");
190 let inner2 = make_year_match(years, "Year{year}::bench_dp(input.as_deref(), dp)");
191 format!(
192 "
193 fn run_year(year: usize, dp: DP, input: Option<&str>) {{
194 match year {{
195 {inner}
196 _ => {{
197 println!(\"Unknown year: {{year}}\");
198 }}
199 }}
200 }}
201 fn bench_year(year: usize, dp: DP, input: Option<&str>) {{
202 match year {{
203 {inner2}
204 _ => {{
205 println!(\"Unknown year: {{year}}\");
206 }}
207 }}
208 }}"
209 )
210}
211
212#[proc_macro]
213pub fn global_runner(item: TokenStream) -> TokenStream {
214 let item = item.to_string();
215 let years = item.split(',').map(|s| s.trim()).collect::<Vec<_>>();
216
217 let year_uses = make_year_uses(&years);
218 let run_all_years = make_run_all_years(&years);
219 let run_year = make_run_year(&years);
220
221 format!(
222 "
223 {year_uses}
224
225 {run_year}
226
227 fn run_all_years(dp: &DP, input: Option<String>) {{
228 {run_all_years}
229 }}"
230 )
231 .parse::<TokenStream>()
232 .unwrap()
233}