solverforge_derive/
lib.rs

1//! Derive macros for SolverForge domain types.
2//!
3//! This crate provides derive macros for implementing `PlanningEntity` and
4//! `PlanningSolution` traits from `solverforge-core`.
5//!
6//! # Example
7//!
8//! ```ignore
9//! use solverforge_derive::{PlanningEntity, PlanningSolution};
10//!
11//! #[derive(PlanningEntity, Clone)]
12//! pub struct Lesson {
13//!     #[planning_id]
14//!     pub id: String,
15//!     pub subject: String,
16//!     #[planning_variable(value_range_provider = "rooms")]
17//!     pub room: Option<Room>,
18//! }
19//!
20//! #[derive(PlanningSolution, Clone)]
21//! #[constraint_provider = "define_constraints"]
22//! pub struct Timetable {
23//!     #[problem_fact_collection]
24//!     #[value_range_provider(id = "rooms")]
25//!     pub rooms: Vec<Room>,
26//!     #[planning_entity_collection]
27//!     pub lessons: Vec<Lesson>,
28//!     #[planning_score]
29//!     pub score: Option<HardSoftScore>,
30//! }
31//! ```
32
33use proc_macro::TokenStream;
34
35mod entity;
36mod solution;
37
38/// Derive macro for implementing the `PlanningEntity` trait.
39///
40/// # Attributes
41///
42/// ## Field Attributes
43///
44/// - `#[planning_id]` - Marks the field as the unique identifier for this entity.
45///   Required for every planning entity.
46///
47/// - `#[planning_variable(value_range_provider = "...")]` - Marks the field as a
48///   planning variable. The solver will assign values from the specified value
49///   range provider.
50///
51/// - `#[planning_variable(value_range_provider = "...", allows_unassigned = true)]` -
52///   Allows the variable to remain unassigned (null/None).
53///
54/// # Example
55///
56/// ```ignore
57/// #[derive(PlanningEntity, Clone)]
58/// pub struct Lesson {
59///     #[planning_id]
60///     pub id: String,
61///
62///     pub subject: String,
63///     pub teacher: String,
64///
65///     #[planning_variable(value_range_provider = "timeslots")]
66///     pub timeslot: Option<Timeslot>,
67///
68///     #[planning_variable(value_range_provider = "rooms", allows_unassigned = true)]
69///     pub room: Option<Room>,
70/// }
71/// ```
72#[proc_macro_derive(
73    PlanningEntity,
74    attributes(planning_id, planning_variable, planning_list_variable)
75)]
76pub fn derive_planning_entity(input: TokenStream) -> TokenStream {
77    entity::derive_planning_entity_impl(input)
78}
79
80/// Derive macro for implementing the `PlanningSolution` trait.
81///
82/// # Attributes
83///
84/// ## Struct Attributes
85///
86/// - `#[constraint_provider = "function_name"]` - Specifies the function that
87///   provides constraints for this solution. The function must have signature
88///   `fn(ConstraintFactory) -> Vec<Constraint>`.
89///
90/// ## Field Attributes
91///
92/// - `#[problem_fact_collection]` - Marks a collection field as containing
93///   immutable problem facts.
94///
95/// - `#[problem_fact]` - Marks a single field as a problem fact.
96///
97/// - `#[planning_entity_collection]` - Marks a collection field as containing
98///   planning entities that will be modified during solving.
99///
100/// - `#[planning_entity]` - Marks a single field as a planning entity.
101///
102/// - `#[value_range_provider(id = "...")]` - Marks a field as providing values
103///   for planning variables with the matching `value_range_provider` reference.
104///
105/// - `#[planning_score]` - Marks the field that will hold the solution's score.
106///
107/// # Example
108///
109/// ```ignore
110/// #[derive(PlanningSolution, Clone)]
111/// #[constraint_provider = "define_constraints"]
112/// pub struct Timetable {
113///     #[problem_fact_collection]
114///     #[value_range_provider(id = "timeslots")]
115///     pub timeslots: Vec<Timeslot>,
116///
117///     #[problem_fact_collection]
118///     #[value_range_provider(id = "rooms")]
119///     pub rooms: Vec<Room>,
120///
121///     #[planning_entity_collection]
122///     pub lessons: Vec<Lesson>,
123///
124///     #[planning_score]
125///     pub score: Option<HardSoftScore>,
126/// }
127/// ```
128#[proc_macro_derive(
129    PlanningSolution,
130    attributes(
131        constraint_provider,
132        problem_fact_collection,
133        problem_fact,
134        planning_entity_collection,
135        planning_entity,
136        value_range_provider,
137        planning_score
138    )
139)]
140pub fn derive_planning_solution(input: TokenStream) -> TokenStream {
141    solution::derive_planning_solution_impl(input)
142}