1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// constraint.rs
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
/// A type-safe, cheap-to-copy identifier for constraints, replacing String-based lookups.
/// It's a simple wrapper around a usize for performance.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ConstraintId(pub usize);
/// Manages constraint weights and the mapping between string names and integer-based ConstraintIds.
#[derive(Debug, Clone)]
pub struct ConstraintWeights {
/// Stores weights against the performant integer-based ConstraintId.
weights: Rc<RefCell<HashMap<ConstraintId, f64>>>,
/// Maps the original string names to their corresponding integer IDs.
name_to_id: Rc<RefCell<HashMap<String, ConstraintId>>>,
/// Provides a reverse mapping from an ID back to its string name, useful for reporting.
id_to_name: Rc<RefCell<HashMap<ConstraintId, String>>>,
/// A simple counter to generate new, unique IDs.
next_id: Rc<RefCell<usize>>,
}
impl ConstraintWeights {
pub fn new() -> Self {
Self {
weights: Rc::new(RefCell::new(HashMap::new())),
name_to_id: Rc::new(RefCell::new(HashMap::new())),
id_to_name: Rc::new(RefCell::new(HashMap::new())),
next_id: Rc::new(RefCell::new(0)),
}
}
/// Gets an existing ID for a name or creates a new one.
/// This is the central point for converting a string name into a performant ID.
pub fn get_or_create_id(&self, name: &str) -> ConstraintId {
// First, check if the ID already exists to avoid mutable borrow if possible.
if let Some(id) = self.name_to_id.borrow().get(name) {
return *id;
}
// If it doesn't exist, we need to create it.
let mut name_map = self.name_to_id.borrow_mut();
let mut id_map = self.id_to_name.borrow_mut();
let mut next_id_ref = self.next_id.borrow_mut();
let id = ConstraintId(*next_id_ref);
*next_id_ref += 1;
name_map.insert(name.to_string(), id);
id_map.insert(id, name.to_string());
id
}
/// Gets the `ConstraintId` for a name that is expected to already exist.
pub fn get_id(&self, name: &str) -> Option<ConstraintId> {
self.name_to_id.borrow().get(name).copied()
}
/// Gets the original string name for a given `ConstraintId`.
pub fn get_name(&self, id: ConstraintId) -> Option<String> {
self.id_to_name.borrow().get(&id).cloned()
}
/// Sets a weight for a constraint using its string name.
/// The name is resolved to an ID internally.
pub fn set_weight(&self, constraint_name: &str, weight: f64) {
let id = self.get_or_create_id(constraint_name);
self.weights.borrow_mut().insert(id, weight);
}
/// Gets a weight for a constraint using its performant `ConstraintId`.
/// This is called in the performance-critical scoring path.
pub fn get_weight(&self, constraint_id: ConstraintId) -> f64 {
self.weights.borrow().get(&constraint_id).copied().unwrap_or(1.0)
}
/// Returns a list of all registered constraint IDs and their corresponding names.
/// This is useful for iterating over all constraints for reporting and analysis.
pub fn get_all_constraints(&self) -> Vec<(ConstraintId, String)> {
self.id_to_name
.borrow()
.iter()
.map(|(id, name)| (*id, name.clone()))
.collect()
}
}
impl Default for ConstraintWeights {
fn default() -> Self {
Self::new()
}
}