1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use proc_macro::TokenStream;
use quote::format_ident;
use quote::quote;
use quote::ToTokens;
use std::cell::RefCell;
use std::collections::HashMap;
use syn::{parse_macro_input, AttributeArgs, ItemFn, Lit, LitInt, NestedMeta};
thread_local! {
static AOC_SOLVERS: RefCell<HashMap<(String, String), String>> = RefCell::new(HashMap::new());
}
#[proc_macro_attribute]
pub fn aoc(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
let attributes = parse_macro_input!(input as AttributeArgs);
let attributes: Vec<String> = attributes
.iter()
.map(|a| match a {
NestedMeta::Lit(l) => match l {
Lit::Str(s) => s.value(),
_ => panic!("Attribute is not a string"),
},
_ => panic!("Attribute is not a string"),
})
.collect();
if attributes.len() != 2 {
panic!("Number of attributes must be two");
}
let func = parse_macro_input!(annotated_item as ItemFn);
AOC_SOLVERS.with(|solvers| {
solvers.borrow_mut().insert(
(attributes[0].clone(), attributes[1].clone()),
func.sig.ident.to_string(),
);
});
func.into_token_stream().into()
}
#[proc_macro]
pub fn aoc_main(input: TokenStream) -> TokenStream {
let year = parse_macro_input!(input as LitInt);
let solvers = AOC_SOLVERS.with(|s| s.take()).into_iter();
let quote_solvers = solvers.map(|(key, value)| {
let (day, part) = key;
let id = format_ident!("{}", value);
quote! { aoc.add_solver(concat!(#day, #part), #id); }
});
quote! {
fn main() {
let mut aoc = Aoc::new(#year);
#( #quote_solvers )*
aoc.run();
}
}
.into()
}