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