aoc_companion_codegen/
lib.rs1use proc_macro::TokenStream;
2use std::collections::HashMap;
3use syn::{
4 parse::{Parse, ParseStream},
5 Ident, LitInt, Token,
6};
7
8struct Args {
9 day: LitInt,
10 parser: Option<Ident>,
11 part1: Option<Ident>,
12 part2: Option<Ident>,
13}
14
15impl Parse for Args {
16 fn parse(input: ParseStream) -> syn::Result<Self> {
17 let day = input.parse()?;
18 let mut args = HashMap::new();
19
20 input.parse::<Token![,]>()?;
21 while let Ok(id) = input.parse::<Ident>() {
22 match id.to_string().as_str() {
23 "parser" => {
24 input.parse::<Token![=]>()?;
25 let parser: Ident = input.parse()?;
26 args.insert("parser", parser);
27 }
28 "part1" => {
29 input.parse::<Token![=]>()?;
30 let part1: Ident = input.parse()?;
31 args.insert("part1", part1);
32 }
33
34 "part2" => {
35 input.parse::<Token![=]>()?;
36 let part2: Ident = input.parse()?;
37 args.insert("part2", part2);
38 }
39 _ => return Err(syn::Error::new(id.span(), "unknown argument")),
40 }
41
42 if input.peek(Token![,]) {
43 input.parse::<Token![,]>()?;
44 } else {
45 break;
46 }
47 }
48
49 Ok(Args {
50 day,
51 parser: args.get("parser").cloned(),
52 part1: args.get("part1").cloned(),
53 part2: args.get("part2").cloned(),
54 })
55 }
56}
57
58#[proc_macro_attribute]
62pub fn day(attr: TokenStream, _item: TokenStream) -> TokenStream {
63 let args = syn::parse_macro_input!(attr as Args);
64 let day: u8 = args.day.base10_parse().unwrap();
65 let parser = args.parser;
66 let part1 = args.part1;
67 let part2 = args.part2;
68
69 quote::quote! {
70 fn main() {
71 println!("Running Advent of Code Day {}", #day);
72 _ = aoc_companion::input::apply(&format!("input-day-{:02}.txt", #day), |input| {
73 aoc_companion::timed(|| {
74 let input = #parser(&input);
75 aoc_companion::timed(|| println!("Part 1: {}", #part1(&input)));
76 aoc_companion::timed(|| println!("Part 2: {}", #part2(&input)));
77 });
78 });
79 }
80 }
81 .into()
82}