solverforge_macros/
lib.rs1use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, DeriveInput, ItemStruct};
6
7mod attr_parse;
8mod list_registry;
9mod planning_entity;
10mod planning_solution;
11mod problem_fact;
12
13use attr_parse::{has_serde_flag, parse_solution_flags};
14
15#[proc_macro_attribute]
16pub fn planning_entity(attr: TokenStream, item: TokenStream) -> TokenStream {
17 let has_serde = has_serde_flag(attr);
18 let input = parse_macro_input!(item as ItemStruct);
19 let name = &input.ident;
20 let vis = &input.vis;
21 let generics = &input.generics;
22 let attrs: Vec<_> = input.attrs.iter().collect();
23 let fields = &input.fields;
24
25 let serde_derives = if has_serde {
26 quote! { ::serde::Serialize, ::serde::Deserialize, }
27 } else {
28 quote! {}
29 };
30
31 let expanded = quote! {
32 #[derive(Clone, Debug, PartialEq, Eq, Hash, #serde_derives ::solverforge::PlanningEntityImpl)]
33 #(#attrs)*
34 #vis struct #name #generics #fields
35 };
36 expanded.into()
37}
38
39#[proc_macro_attribute]
40pub fn planning_solution(attr: TokenStream, item: TokenStream) -> TokenStream {
41 let (has_serde, constraints_path, config_path, solver_toml_path) = parse_solution_flags(attr);
42 let input = parse_macro_input!(item as ItemStruct);
43 let name = &input.ident;
44 let vis = &input.vis;
45 let generics = &input.generics;
46 let attrs: Vec<_> = input.attrs.iter().collect();
47 let fields = &input.fields;
48
49 let serde_derives = if has_serde {
50 quote! { ::serde::Serialize, ::serde::Deserialize, }
51 } else {
52 quote! {}
53 };
54
55 let constraints_attr =
56 constraints_path.map(|p| quote! { #[solverforge_constraints_path = #p] });
57 let config_attr = config_path.map(|p| quote! { #[solverforge_config_path = #p] });
58 let solver_toml_attr =
59 solver_toml_path.map(|p| quote! { #[solverforge_solver_toml_path = #p] });
60
61 let expanded = quote! {
62 #[derive(Clone, Debug, #serde_derives ::solverforge::PlanningSolutionImpl)]
63 #constraints_attr
64 #config_attr
65 #solver_toml_attr
66 #(#attrs)*
67 #vis struct #name #generics #fields
68 };
69 expanded.into()
70}
71
72#[proc_macro_attribute]
73pub fn problem_fact(attr: TokenStream, item: TokenStream) -> TokenStream {
74 let has_serde = has_serde_flag(attr);
75 let input = parse_macro_input!(item as ItemStruct);
76 let name = &input.ident;
77 let vis = &input.vis;
78 let generics = &input.generics;
79 let attrs: Vec<_> = input.attrs.iter().collect();
80 let fields = &input.fields;
81
82 let serde_derives = if has_serde {
83 quote! { ::serde::Serialize, ::serde::Deserialize, }
84 } else {
85 quote! {}
86 };
87
88 let expanded = quote! {
89 #[derive(Clone, Debug, PartialEq, Eq, #serde_derives ::solverforge::ProblemFactImpl)]
90 #(#attrs)*
91 #vis struct #name #generics #fields
92 };
93 expanded.into()
94}
95
96#[proc_macro_derive(
97 PlanningEntityImpl,
98 attributes(
99 planning_id,
100 planning_variable,
101 planning_list_variable,
102 planning_pin,
103 inverse_relation_shadow_variable,
104 previous_element_shadow_variable,
105 next_element_shadow_variable,
106 cascading_update_shadow_variable
107 )
108)]
109pub fn derive_planning_entity(input: TokenStream) -> TokenStream {
110 let input = parse_macro_input!(input as DeriveInput);
111 planning_entity::expand_derive(input)
112 .unwrap_or_else(|e| e.to_compile_error())
113 .into()
114}
115
116#[proc_macro_derive(
117 PlanningSolutionImpl,
118 attributes(
119 planning_entity_collection,
120 planning_list_element_collection,
121 problem_fact_collection,
122 planning_score,
123 value_range_provider,
124 shadow_variable_updates,
125 solverforge_constraints_path,
126 solverforge_config_path,
127 solverforge_solver_toml_path
128 )
129)]
130pub fn derive_planning_solution(input: TokenStream) -> TokenStream {
131 let input = parse_macro_input!(input as DeriveInput);
132 planning_solution::expand_derive(input)
133 .unwrap_or_else(|e| e.to_compile_error())
134 .into()
135}
136
137#[proc_macro_derive(ProblemFactImpl, attributes(planning_id))]
138pub fn derive_problem_fact(input: TokenStream) -> TokenStream {
139 let input = parse_macro_input!(input as DeriveInput);
140 problem_fact::expand_derive(input)
141 .unwrap_or_else(|e| e.to_compile_error())
142 .into()
143}