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) = 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
59 let expanded = quote! {
60 #[derive(Clone, Debug, #serde_derives ::solverforge::PlanningSolutionImpl)]
61 #constraints_attr
62 #config_attr
63 #(#attrs)*
64 #vis struct #name #generics #fields
65 };
66 expanded.into()
67}
68
69#[proc_macro_attribute]
70pub fn problem_fact(attr: TokenStream, item: TokenStream) -> TokenStream {
71 let has_serde = has_serde_flag(attr);
72 let input = parse_macro_input!(item as ItemStruct);
73 let name = &input.ident;
74 let vis = &input.vis;
75 let generics = &input.generics;
76 let attrs: Vec<_> = input.attrs.iter().collect();
77 let fields = &input.fields;
78
79 let serde_derives = if has_serde {
80 quote! { ::serde::Serialize, ::serde::Deserialize, }
81 } else {
82 quote! {}
83 };
84
85 let expanded = quote! {
86 #[derive(Clone, Debug, PartialEq, Eq, #serde_derives ::solverforge::ProblemFactImpl)]
87 #(#attrs)*
88 #vis struct #name #generics #fields
89 };
90 expanded.into()
91}
92
93#[proc_macro_derive(
94 PlanningEntityImpl,
95 attributes(
96 planning_id,
97 planning_variable,
98 planning_list_variable,
99 planning_pin,
100 inverse_relation_shadow_variable,
101 previous_element_shadow_variable,
102 next_element_shadow_variable,
103 cascading_update_shadow_variable
104 )
105)]
106pub fn derive_planning_entity(input: TokenStream) -> TokenStream {
107 let input = parse_macro_input!(input as DeriveInput);
108 planning_entity::expand_derive(input)
109 .unwrap_or_else(|e| e.to_compile_error())
110 .into()
111}
112
113#[proc_macro_derive(
114 PlanningSolutionImpl,
115 attributes(
116 planning_entity_collection,
117 planning_list_element_collection,
118 problem_fact_collection,
119 planning_score,
120 value_range_provider,
121 shadow_variable_updates,
122 solverforge_constraints_path,
123 solverforge_config_path
124 )
125)]
126pub fn derive_planning_solution(input: TokenStream) -> TokenStream {
127 let input = parse_macro_input!(input as DeriveInput);
128 planning_solution::expand_derive(input)
129 .unwrap_or_else(|e| e.to_compile_error())
130 .into()
131}
132
133#[proc_macro_derive(ProblemFactImpl, attributes(planning_id))]
134pub fn derive_problem_fact(input: TokenStream) -> TokenStream {
135 let input = parse_macro_input!(input as DeriveInput);
136 problem_fact::expand_derive(input)
137 .unwrap_or_else(|e| e.to_compile_error())
138 .into()
139}