solverforge_core/
bridge.rs

1use crate::domain::{FieldType, PlanningAnnotation};
2use crate::{FunctionHandle, ObjectHandle, SolverForgeResult, Value};
3
4pub trait LanguageBridge: Send + Sync {
5    fn call_function(&self, func: FunctionHandle, args: &[Value]) -> SolverForgeResult<Value>;
6
7    fn get_field(&self, obj: ObjectHandle, field: &str) -> SolverForgeResult<Value>;
8
9    fn set_field(&self, obj: ObjectHandle, field: &str, value: Value) -> SolverForgeResult<()>;
10
11    fn serialize_object(&self, obj: ObjectHandle) -> SolverForgeResult<String>;
12
13    fn deserialize_object(&self, json: &str, class_name: &str) -> SolverForgeResult<ObjectHandle>;
14
15    fn get_class_info(&self, obj: ObjectHandle) -> SolverForgeResult<ClassInfo>;
16
17    fn register_function(&self, func: ObjectHandle) -> SolverForgeResult<FunctionHandle>;
18
19    fn clone_object(&self, obj: ObjectHandle) -> SolverForgeResult<ObjectHandle>;
20
21    fn get_list_size(&self, obj: ObjectHandle) -> SolverForgeResult<usize>;
22
23    fn get_list_item(&self, obj: ObjectHandle, index: usize) -> SolverForgeResult<Value>;
24}
25
26#[derive(Debug, Clone, PartialEq)]
27pub struct ClassInfo {
28    pub name: String,
29    pub fields: Vec<FieldInfo>,
30    pub annotations: Vec<PlanningAnnotation>,
31}
32
33impl ClassInfo {
34    pub fn new(name: impl Into<String>) -> Self {
35        Self {
36            name: name.into(),
37            fields: Vec::new(),
38            annotations: Vec::new(),
39        }
40    }
41
42    pub fn with_field(mut self, field: FieldInfo) -> Self {
43        self.fields.push(field);
44        self
45    }
46
47    pub fn with_annotation(mut self, annotation: PlanningAnnotation) -> Self {
48        self.annotations.push(annotation);
49        self
50    }
51}
52
53#[derive(Debug, Clone, PartialEq)]
54pub struct FieldInfo {
55    pub name: String,
56    pub field_type: FieldType,
57    pub annotations: Vec<PlanningAnnotation>,
58}
59
60impl FieldInfo {
61    pub fn new(name: impl Into<String>, field_type: FieldType) -> Self {
62        Self {
63            name: name.into(),
64            field_type,
65            annotations: Vec::new(),
66        }
67    }
68
69    pub fn with_annotation(mut self, annotation: PlanningAnnotation) -> Self {
70        self.annotations.push(annotation);
71        self
72    }
73}
74
75#[cfg(test)]
76pub mod tests {
77    use super::*;
78    use crate::domain::PrimitiveType;
79    use crate::SolverForgeError;
80    use std::collections::HashMap;
81    use std::sync::{Arc, Mutex};
82
83    pub struct MockBridge {
84        objects: Arc<Mutex<HashMap<u64, Value>>>,
85        next_handle: Arc<Mutex<u64>>,
86    }
87
88    impl MockBridge {
89        pub fn new() -> Self {
90            Self {
91                objects: Arc::new(Mutex::new(HashMap::new())),
92                next_handle: Arc::new(Mutex::new(1)),
93            }
94        }
95
96        pub fn store_object(&self, value: Value) -> ObjectHandle {
97            let mut objects = self.objects.lock().unwrap();
98            let mut next = self.next_handle.lock().unwrap();
99            let handle = *next;
100            *next += 1;
101            objects.insert(handle, value);
102            ObjectHandle::new(handle)
103        }
104
105        pub fn get_object(&self, handle: ObjectHandle) -> Option<Value> {
106            self.objects.lock().unwrap().get(&handle.id()).cloned()
107        }
108    }
109
110    impl LanguageBridge for MockBridge {
111        fn call_function(&self, _func: FunctionHandle, args: &[Value]) -> SolverForgeResult<Value> {
112            Ok(args.first().cloned().unwrap_or(Value::Null))
113        }
114
115        fn get_field(&self, obj: ObjectHandle, field: &str) -> SolverForgeResult<Value> {
116            let value = self
117                .get_object(obj)
118                .ok_or_else(|| SolverForgeError::Bridge(format!("Object not found: {:?}", obj)))?;
119
120            match value {
121                Value::Object(map) => Ok(map.get(field).cloned().unwrap_or(Value::Null)),
122                _ => Err(SolverForgeError::Bridge("Not an object".to_string())),
123            }
124        }
125
126        fn set_field(&self, obj: ObjectHandle, field: &str, value: Value) -> SolverForgeResult<()> {
127            let mut objects = self.objects.lock().unwrap();
128            let stored = objects
129                .get_mut(&obj.id())
130                .ok_or_else(|| SolverForgeError::Bridge(format!("Object not found: {:?}", obj)))?;
131
132            match stored {
133                Value::Object(map) => {
134                    map.insert(field.to_string(), value);
135                    Ok(())
136                }
137                _ => Err(SolverForgeError::Bridge("Not an object".to_string())),
138            }
139        }
140
141        fn serialize_object(&self, obj: ObjectHandle) -> SolverForgeResult<String> {
142            let value = self
143                .get_object(obj)
144                .ok_or_else(|| SolverForgeError::Bridge(format!("Object not found: {:?}", obj)))?;
145
146            serde_json::to_string(&value)
147                .map_err(|e| SolverForgeError::Serialization(e.to_string()))
148        }
149
150        fn deserialize_object(
151            &self,
152            json: &str,
153            _class_name: &str,
154        ) -> SolverForgeResult<ObjectHandle> {
155            let value: Value = serde_json::from_str(json)
156                .map_err(|e| SolverForgeError::Serialization(e.to_string()))?;
157
158            Ok(self.store_object(value))
159        }
160
161        fn get_class_info(&self, _obj: ObjectHandle) -> SolverForgeResult<ClassInfo> {
162            Ok(ClassInfo::new("MockClass")
163                .with_field(FieldInfo::new(
164                    "id",
165                    FieldType::Primitive(PrimitiveType::String),
166                ))
167                .with_annotation(PlanningAnnotation::PlanningEntity))
168        }
169
170        fn register_function(&self, func: ObjectHandle) -> SolverForgeResult<FunctionHandle> {
171            Ok(FunctionHandle::new(func.id()))
172        }
173
174        fn clone_object(&self, obj: ObjectHandle) -> SolverForgeResult<ObjectHandle> {
175            let value = self
176                .get_object(obj)
177                .ok_or_else(|| SolverForgeError::Bridge(format!("Object not found: {:?}", obj)))?;
178
179            Ok(self.store_object(value))
180        }
181
182        fn get_list_size(&self, obj: ObjectHandle) -> SolverForgeResult<usize> {
183            let value = self
184                .get_object(obj)
185                .ok_or_else(|| SolverForgeError::Bridge(format!("Object not found: {:?}", obj)))?;
186
187            match value {
188                Value::Array(arr) => Ok(arr.len()),
189                _ => Err(SolverForgeError::Bridge("Not an array".to_string())),
190            }
191        }
192
193        fn get_list_item(&self, obj: ObjectHandle, index: usize) -> SolverForgeResult<Value> {
194            let value = self
195                .get_object(obj)
196                .ok_or_else(|| SolverForgeError::Bridge(format!("Object not found: {:?}", obj)))?;
197
198            match value {
199                Value::Array(arr) => arr.get(index).cloned().ok_or_else(|| {
200                    SolverForgeError::Bridge(format!("Index out of bounds: {}", index))
201                }),
202                _ => Err(SolverForgeError::Bridge("Not an array".to_string())),
203            }
204        }
205    }
206
207    #[test]
208    fn test_class_info() {
209        let info = ClassInfo::new("Lesson")
210            .with_annotation(PlanningAnnotation::PlanningEntity)
211            .with_field(FieldInfo::new(
212                "id",
213                FieldType::Primitive(PrimitiveType::String),
214            ));
215
216        assert_eq!(info.name, "Lesson");
217        assert_eq!(info.fields.len(), 1);
218        assert_eq!(info.annotations.len(), 1);
219    }
220
221    #[test]
222    fn test_field_info() {
223        let field = FieldInfo::new("room", FieldType::object("Room")).with_annotation(
224            PlanningAnnotation::planning_variable(vec!["rooms".to_string()]),
225        );
226
227        assert_eq!(field.name, "room");
228        assert_eq!(field.annotations.len(), 1);
229    }
230
231    #[test]
232    fn test_mock_bridge_store_and_get() {
233        let bridge = MockBridge::new();
234
235        let mut map = HashMap::new();
236        map.insert("name".to_string(), Value::String("Test".to_string()));
237        let obj = bridge.store_object(Value::Object(map));
238
239        let value = bridge.get_field(obj, "name").unwrap();
240        assert_eq!(value, Value::String("Test".to_string()));
241    }
242
243    #[test]
244    fn test_mock_bridge_set_field() {
245        let bridge = MockBridge::new();
246
247        let mut map = HashMap::new();
248        map.insert("value".to_string(), Value::Int(0));
249        let obj = bridge.store_object(Value::Object(map));
250
251        bridge.set_field(obj, "value", Value::Int(42)).unwrap();
252
253        let value = bridge.get_field(obj, "value").unwrap();
254        assert_eq!(value, Value::Int(42));
255    }
256
257    #[test]
258    fn test_mock_bridge_serialize() {
259        let bridge = MockBridge::new();
260
261        let mut map = HashMap::new();
262        map.insert("x".to_string(), Value::Int(1));
263        let obj = bridge.store_object(Value::Object(map));
264
265        let json = bridge.serialize_object(obj).unwrap();
266        assert!(json.contains("\"x\":1"));
267    }
268
269    #[test]
270    fn test_mock_bridge_deserialize() {
271        let bridge = MockBridge::new();
272
273        let json = r#"{"name":"Test","value":42}"#;
274        let obj = bridge.deserialize_object(json, "TestClass").unwrap();
275
276        let name = bridge.get_field(obj, "name").unwrap();
277        assert_eq!(name, Value::String("Test".to_string()));
278    }
279
280    #[test]
281    fn test_mock_bridge_clone() {
282        let bridge = MockBridge::new();
283
284        let mut map = HashMap::new();
285        map.insert("id".to_string(), Value::Int(1));
286        let obj = bridge.store_object(Value::Object(map));
287
288        let cloned = bridge.clone_object(obj).unwrap();
289        assert_ne!(obj.id(), cloned.id());
290
291        let value = bridge.get_field(cloned, "id").unwrap();
292        assert_eq!(value, Value::Int(1));
293    }
294
295    #[test]
296    fn test_mock_bridge_list_operations() {
297        let bridge = MockBridge::new();
298
299        let arr = Value::Array(vec![Value::Int(1), Value::Int(2), Value::Int(3)]);
300        let obj = bridge.store_object(arr);
301
302        assert_eq!(bridge.get_list_size(obj).unwrap(), 3);
303        assert_eq!(bridge.get_list_item(obj, 0).unwrap(), Value::Int(1));
304        assert_eq!(bridge.get_list_item(obj, 2).unwrap(), Value::Int(3));
305    }
306
307    #[test]
308    fn test_mock_bridge_call_function() {
309        let bridge = MockBridge::new();
310
311        let func = FunctionHandle::new(1);
312        let result = bridge.call_function(func, &[Value::Int(42)]).unwrap();
313        assert_eq!(result, Value::Int(42));
314    }
315}