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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use proc_macro::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
use syn::{parse_macro_input, Expr, LitInt, Token};
struct ClientArgs {
year: u16,
day: u8,
}
impl Parse for ClientArgs {
fn parse(input: ParseStream) -> Result<Self> {
let vars = Punctuated::<LitInt, Token![,]>::parse_terminated(input)?
.into_iter()
.collect::<Vec<_>>();
assert!(
vars.len() == 2,
"Expected 2 arguments, got {}. Provide a year and a day, e.g. #[aocd({})]",
vars.len(),
chrono::Utc::now().format("%Y, %d")
);
Ok(ClientArgs {
year: vars[0].clone().base10_parse::<u16>()?,
day: vars[1].clone().base10_parse::<u8>()?,
})
}
}
struct SubmitArgs {
part: u8,
answer: Expr,
}
impl Parse for SubmitArgs {
fn parse(input: ParseStream) -> Result<Self> {
let part: u8 = input.parse::<LitInt>()?.base10_parse::<u8>()?;
assert!(part == 1 || part == 2, "Part should be 1 or 2, no {}", part);
input.parse::<Token![,]>()?;
let answer: Expr = input.parse()?;
Ok(SubmitArgs { part, answer })
}
}
#[proc_macro_attribute]
pub fn aocd(attr: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(attr as ClientArgs);
let year = args.year;
let day = args.day;
assert!(
year >= 2015,
"The first Advent of Code was in 2015, not {}.",
year
);
assert!(
day >= 1 && day <= 25,
"Chose a day from 1 to 25, not {}.",
day
);
let mut fn_item: syn::ItemFn = syn::parse(input).unwrap();
fn_item.block.stmts.insert(
0,
syn::parse(quote!(let __aocd_client = aocd::Aocd::new(#year, #day);).into()).unwrap(),
);
TokenStream::from(quote!(#fn_item))
}
#[proc_macro]
pub fn input(_: TokenStream) -> TokenStream {
TokenStream::from(quote!(__aocd_client.get_input()))
}
#[proc_macro]
pub fn submit(args: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as SubmitArgs);
let part = args.part;
let answer = args.answer;
TokenStream::from(quote!(__aocd_client.submit(#part, #answer)))
}