1
pub use linkme::distributed_slice;
2

            
3
mod rewrite_morph;
4
pub use rewrite_morph::rewrite_morph;
5

            
6
/// This procedural macro registers a decorated function with `conjure_cp_rules`' global registry, and
7
/// adds the rule to one or more `RuleSet`'s.
8
///
9
/// It may be used in any downstream crate.
10
/// For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate.
11
///
12
/// **IMPORTANT**: Since the resulting rule may not be explicitly referenced, it may be removed by the compiler's dead code elimination.
13
/// To prevent this, you must ensure that either:
14
/// 1. codegen-units is set to 1, i.e. in Cargo.toml:
15
/// ```toml
16
/// [profile.release]
17
/// codegen-units = 1
18
/// ```
19
/// 2. The function is included somewhere else in the code
20
///
21
/// <hr>
22
///
23
/// Functions must have the signature `fn(&Expr) -> ApplicationResult`.
24
/// The created rule will have the same name as the function.
25
///
26
/// Intermediary static variables are created to allow for the decentralized registry, with the prefix `CONJURE_GEN_`.
27
/// Please ensure that other variable names in the same scope do not conflict with these.
28
///
29
/// This macro must decorate a function with the given signature.
30
/// As arguments, it excepts a tuple of 2-tuples in the format:
31
/// `((<RuleSet name>, <Priority in RuleSet>), ...)`
32
///
33
/// <hr>
34
///
35
/// For example:
36
/// ```rust
37
/// use conjure_cp_core::ast::Expression;
38
/// use conjure_cp_core::ast::SymbolTable;
39
/// use conjure_cp_core::rule_engine::{ApplicationError, ApplicationResult, Reduction};
40
/// use conjure_cp_core::rule_engine::register_rule;
41
///
42
/// #[register_rule(("RuleSetName", 10))]
43
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
44
///   Ok(Reduction::pure(expr.clone()))
45
/// }
46
/// ```
47
pub use conjure_cp_rule_macros::register_rule;
48

            
49
/// This procedural macro registers a rule set with the global registry.
50
/// It may be used in any downstream crate.
51
///
52
/// For more information on linker magic, see the [`linkme`](https://docs.rs/linkme/latest/linkme/) crate.
53
///
54
/// This macro uses the following syntax:
55
///
56
/// ```text
57
/// register_rule_set!(<RuleSet name>, (<DependencyRuleSet1>, <DependencyRuleSet2>, ...), <SolverFamily>);
58
/// ```
59
///
60
/// # Example
61
///
62
/// Register a rule set with no dependencies:
63
///
64
/// ```rust
65
/// use conjure_cp_core::rule_engine::register_rule_set;
66
/// register_rule_set!("MyRuleSet");
67
/// ```
68
///
69
/// Register a rule set with dependencies:
70
///
71
/// ```rust
72
/// use conjure_cp_core::rule_engine::register_rule_set;
73
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
74
/// ```
75
///
76
/// Register a rule set for a specific solver family or families:
77
///
78
/// ```rust
79
/// use conjure_cp_core::rule_engine::register_rule_set;
80
/// use conjure_cp_core::solver::SolverFamily;
81
/// register_rule_set!("MyRuleSet", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion));
82
/// register_rule_set!("AnotherRuleSet", (), |f: &SolverFamily| matches!(f, SolverFamily::Minion | SolverFamily::Sat));
83
/// ```
84
#[doc(inline)]
85
pub use conjure_cp_rule_macros::register_rule_set;
86
pub use resolve_rules::{RuleData, get_rules, get_rules_grouped, resolve_rule_sets};
87
pub use rewrite_naive::rewrite_naive;
88
pub use rewriter_common::RewriteError;
89
pub use rule::{ApplicationError, ApplicationResult, Reduction, Rule, RuleFn};
90
pub use rule_set::RuleSet;
91

            
92
mod submodel_zipper;
93

            
94
#[doc(hidden)]
95
pub use submodel_zipper::SubmodelZipper;
96

            
97
use crate::solver::SolverFamily;
98

            
99
mod resolve_rules;
100
mod rewrite_naive;
101
mod rewriter_common;
102
mod rule;
103
mod rule_set;
104

            
105
#[doc(hidden)]
106
#[distributed_slice]
107
pub static RULES_DISTRIBUTED_SLICE: [Rule<'static>];
108

            
109
#[doc(hidden)]
110
#[distributed_slice]
111
pub static RULE_SETS_DISTRIBUTED_SLICE: [RuleSet<'static>];
112

            
113
pub mod _dependencies {
114
    pub use linkme;
115
    pub use linkme::distributed_slice;
116
}
117

            
118
/// Returns a copied `Vec` of all rules registered with the `register_rule` macro.
119
///
120
/// Rules are not guaranteed to be in any particular order.
121
///
122
/// # Example
123
/// ```rust
124
/// # use conjure_cp_core::rule_engine::{ApplicationResult, Reduction, get_all_rules};
125
/// # use conjure_cp_core::ast::Expression;
126
/// # use conjure_cp_core::ast::SymbolTable;
127
/// # use conjure_cp_core::rule_engine::register_rule;
128
///
129
/// #[register_rule]
130
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
131
///   Ok(Reduction::pure(expr.clone()))
132
/// }
133
///
134
/// fn main() {
135
///   println!("Rules: {:?}", get_all_rules());
136
/// }
137
/// ```
138
///
139
/// This will print (if no other rules are registered):
140
/// ```text
141
///   Rules: [Rule { name: "identity", application: MEM }]
142
/// ```
143
/// Where `MEM` is the memory address of the `identity` function.
144
pub fn get_all_rules() -> Vec<&'static Rule<'static>> {
145
    RULES_DISTRIBUTED_SLICE.iter().collect()
146
}
147

            
148
/// Get a rule by name.
149
/// Returns the rule with the given name or None if it doesn't exist.
150
///
151
/// # Example
152
/// ```rust
153
/// use conjure_cp_core::rule_engine::register_rule;
154
/// use conjure_cp_core::rule_engine::{Rule, ApplicationResult, Reduction, get_rule_by_name};
155
/// use conjure_cp_core::ast::Expression;
156
/// use conjure_cp_core::ast::SymbolTable;
157
///
158
/// #[register_rule]
159
/// fn identity(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
160
///  Ok(Reduction::pure(expr.clone()))
161
/// }
162
///
163
/// fn main() {
164
/// println!("Rule: {:?}", get_rule_by_name("identity"));
165
/// }
166
/// ```
167
///
168
/// This will print:
169
/// ```text
170
/// Rule: Some(Rule { name: "identity", application: MEM })
171
/// ```
172
pub fn get_rule_by_name(name: &str) -> Option<&'static Rule<'static>> {
173
    get_all_rules()
174
        .iter()
175
        .find(|rule| rule.name == name)
176
        .copied()
177
}
178

            
179
/// Get all rule sets
180
/// Returns a `Vec` of static references to all rule sets registered with the `register_rule_set` macro.
181
/// Rule sets are not guaranteed to be in any particular order.
182
///
183
/// # Example
184
/// ```rust
185
/// use conjure_cp_core::rule_engine::register_rule_set;
186
/// use conjure_cp_core::rule_engine::get_all_rule_sets;
187
///
188
/// register_rule_set!("MyRuleSet", ("AnotherRuleSet"));
189
/// register_rule_set!("AnotherRuleSet", ());
190
///
191
/// println!("Rule sets: {:?}", get_all_rule_sets());
192
/// ```
193
///
194
/// This will print (if no other rule sets are registered):
195
/// ```text
196
/// Rule sets: [
197
///   RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["AnotherRuleSet"] },
198
///   RuleSet { name: "AnotherRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: [] }
199
/// ]
200
/// ```
201
///
202
pub fn get_all_rule_sets() -> Vec<&'static RuleSet<'static>> {
203
    RULE_SETS_DISTRIBUTED_SLICE.iter().collect()
204
}
205

            
206
/// Get a rule set by name.
207
/// Returns the rule set with the given name or None if it doesn't exist.
208
///
209
/// # Example
210
/// ```rust
211
/// use conjure_cp_core::rule_engine::register_rule_set;
212
/// use conjure_cp_core::rule_engine::get_rule_set_by_name;
213
///
214
/// register_rule_set!("MyRuleSet", ("DependencyRuleSet", "AnotherRuleSet"));
215
///
216
/// println!("Rule set: {:?}", get_rule_set_by_name("MyRuleSet"));
217
/// ```
218
///
219
/// This will print:
220
/// ```text
221
/// Rule set: Some(RuleSet { name: "MyRuleSet", rules: OnceLock { state: Uninitialized }, dependencies: ["DependencyRuleSet", "AnotherRuleSet"] })
222
/// ```
223
pub fn get_rule_set_by_name(name: &str) -> Option<&'static RuleSet<'static>> {
224
    get_all_rule_sets()
225
        .iter()
226
        .find(|rule_set| rule_set.name == name)
227
        .copied()
228
}
229

            
230
/// Get all rule sets for a given solver family.
231
/// Returns a `Vec` of static references to all rule sets that are applicable to the given solver family.
232
///
233
/// # Example
234
///
235
/// ```rust
236
/// use conjure_cp_core::solver::SolverFamily;
237
/// use conjure_cp_core::rule_engine::{get_rule_sets_for_solver_family, register_rule_set};
238
///
239
/// register_rule_set!("CNF", (), |f: &SolverFamily| matches!(f, SolverFamily::Sat));
240
///
241
/// let rule_sets = get_rule_sets_for_solver_family(SolverFamily::Sat);
242
/// assert_eq!(rule_sets.len(), 2);
243
/// assert_eq!(rule_sets[0].name, "CNF");
244
/// ```
245
pub fn get_rule_sets_for_solver_family(
246
    solver_family: SolverFamily,
247
) -> Vec<&'static RuleSet<'static>> {
248
    get_all_rule_sets()
249
        .iter()
250
        .filter(|rule_set| rule_set.applies_to_family(&solver_family))
251
        .copied()
252
        .collect()
253
}