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