advent_of_utils_macros/
lib.rs1use quote::ToTokens;
2use syn::punctuated::Punctuated;
3
4#[proc_macro]
5pub fn add_days(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
6 let exprs = syn::parse_macro_input!(input with Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated);
7 let numbers = evaluate_expr(exprs);
8
9 let mut modules: Vec<proc_macro2::TokenStream> = Vec::new();
10 let mut uses: Vec<proc_macro2::TokenStream> = Vec::new();
11 let mut map: Vec<proc_macro2::TokenStream> = Vec::new();
12 for i in numbers {
13 let day: syn::Ident = quote::format_ident!("day{:02}", i);
14 let method: syn::Ident = quote::format_ident!("Day{:02}", i);
15 modules.push(quote::quote! {
16 mod #day;
17 });
18 uses.push(quote::quote! {
19 use #day::#method;
20 });
21 map.push(quote::quote! {
22 solutions.insert(#i, Box::new(#method));
23 })
24 }
25
26 let expanded = quote::quote! {
27 #(#modules)*
28
29 #(#uses)*
30
31 fn internal_create_solutions() -> std::collections::HashMap<u8, Box<dyn advent_of_utils::Solution>> {
32 let mut solutions: std::collections::HashMap<u8, Box<dyn advent_of_utils::Solution>> = std::collections::HashMap::new();
33 #(#map)*
34
35 solutions
36 }
37
38 #[repr(C)]
39 pub struct SolutionsContainer {
40 solutions: *mut std::collections::HashMap<u8, Box<dyn advent_of_utils::Solution>>,
41 }
42
43 #[no_mangle]
44 pub extern "C" fn create_solutions() -> *mut SolutionsContainer {
45 let solutions = Box::new(internal_create_solutions());
46 let container = Box::new(SolutionsContainer {
47 solutions: Box::into_raw(solutions),
48 });
49
50 Box::into_raw(container)
51 }
52
53 #[no_mangle]
54 pub unsafe extern "C" fn destroy_solutions(container: *mut SolutionsContainer) {
55 if !container.is_null() {
56 let container = Box::from_raw(container);
57 if !container.solutions.is_null() {
58 let _ = Box::from_raw(container.solutions);
59 }
60 }
61 }
62
63 };
64
65 proc_macro::TokenStream::from(expanded)
66}
67
68fn evaluate_expr(input: Punctuated<syn::Expr, syn::token::Comma>) -> Vec<u8> {
69 let mut numbers = Vec::new();
70 for expr in input {
71 match expr {
72 syn::Expr::Range(syn::ExprRange {
73 start,
74 limits: _,
75 end,
76 ..
77 }) => {
78 if let (Some(start), Some(end)) = (start, end) {
79 if let (syn::Expr::Lit(start), syn::Expr::Lit(end)) = (*start, *end) {
81 let start_num = start.to_token_stream().to_string().parse::<u8>().unwrap();
82 let end_num = end.to_token_stream().to_string().parse::<u8>().unwrap();
83 numbers.extend(start_num..=end_num);
84 }
85 }
86 }
87 syn::Expr::Lit(lit) => {
88 let num = lit.to_token_stream().to_string().parse::<u8>().unwrap();
89 numbers.push(num);
90 }
91 _ => {}
92 }
93 }
94 numbers
95}