solverforge_core/
handles.rs

1//! Handle types for language-specific object and function references
2//!
3//! This module defines opaque handle types that allow the core library to
4//! reference objects and functions in the host language without knowing
5//! their concrete types.
6
7use serde::{Deserialize, Serialize};
8
9/// Opaque handle to a language-specific object
10///
11/// This is used to reference objects in the host language without
12/// needing to know their concrete type in the core library. The handle
13/// is typically an index into a registry maintained by the language bridge.
14///
15/// # Example
16///
17/// ```
18/// use solverforge_core::ObjectHandle;
19///
20/// let handle = ObjectHandle::new(42);
21/// assert_eq!(handle.id(), 42);
22/// ```
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
24pub struct ObjectHandle(pub u64);
25
26impl ObjectHandle {
27    /// Create a new object handle from a raw identifier
28    pub fn new(id: u64) -> Self {
29        Self(id)
30    }
31
32    /// Get the raw identifier
33    pub fn id(&self) -> u64 {
34        self.0
35    }
36}
37
38impl From<u64> for ObjectHandle {
39    fn from(id: u64) -> Self {
40        Self::new(id)
41    }
42}
43
44/// Opaque handle to a language-specific callable (function/lambda)
45///
46/// This is used to reference functions or lambdas in the host language
47/// that can be called from the core library. Like [`ObjectHandle`], this
48/// is typically an index into a registry maintained by the language bridge.
49///
50/// # Example
51///
52/// ```
53/// use solverforge_core::FunctionHandle;
54///
55/// let handle = FunctionHandle::new(1);
56/// assert_eq!(handle.id(), 1);
57/// ```
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub struct FunctionHandle(pub u64);
60
61impl FunctionHandle {
62    /// Create a new function handle from a raw identifier
63    pub fn new(id: u64) -> Self {
64        Self(id)
65    }
66
67    /// Get the raw identifier
68    pub fn id(&self) -> u64 {
69        self.0
70    }
71}
72
73impl From<u64> for FunctionHandle {
74    fn from(id: u64) -> Self {
75        Self::new(id)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use std::collections::HashSet;
83
84    #[test]
85    fn test_object_handle_creation() {
86        let handle = ObjectHandle::new(42);
87        assert_eq!(handle.id(), 42);
88        assert_eq!(handle.0, 42);
89    }
90
91    #[test]
92    fn test_object_handle_equality() {
93        let h1 = ObjectHandle::new(1);
94        let h2 = ObjectHandle::new(1);
95        let h3 = ObjectHandle::new(2);
96
97        assert_eq!(h1, h2);
98        assert_ne!(h1, h3);
99    }
100
101    #[test]
102    fn test_object_handle_hash() {
103        let mut set = HashSet::new();
104        set.insert(ObjectHandle::new(1));
105        set.insert(ObjectHandle::new(2));
106        set.insert(ObjectHandle::new(1)); // duplicate
107
108        assert_eq!(set.len(), 2);
109        assert!(set.contains(&ObjectHandle::new(1)));
110        assert!(set.contains(&ObjectHandle::new(2)));
111    }
112
113    #[test]
114    fn test_object_handle_from_u64() {
115        let handle: ObjectHandle = 123u64.into();
116        assert_eq!(handle.id(), 123);
117    }
118
119    #[test]
120    fn test_function_handle_creation() {
121        let handle = FunctionHandle::new(42);
122        assert_eq!(handle.id(), 42);
123        assert_eq!(handle.0, 42);
124    }
125
126    #[test]
127    fn test_function_handle_equality() {
128        let h1 = FunctionHandle::new(1);
129        let h2 = FunctionHandle::new(1);
130        let h3 = FunctionHandle::new(2);
131
132        assert_eq!(h1, h2);
133        assert_ne!(h1, h3);
134    }
135
136    #[test]
137    fn test_function_handle_hash() {
138        let mut set = HashSet::new();
139        set.insert(FunctionHandle::new(1));
140        set.insert(FunctionHandle::new(2));
141        set.insert(FunctionHandle::new(1)); // duplicate
142
143        assert_eq!(set.len(), 2);
144    }
145
146    #[test]
147    fn test_function_handle_from_u64() {
148        let handle: FunctionHandle = 456u64.into();
149        assert_eq!(handle.id(), 456);
150    }
151
152    #[test]
153    fn test_handle_copy() {
154        let h1 = ObjectHandle::new(1);
155        let h2 = h1; // Copy, not move
156        assert_eq!(h1, h2); // h1 still valid
157
158        let f1 = FunctionHandle::new(1);
159        let f2 = f1;
160        assert_eq!(f1, f2);
161    }
162
163    #[test]
164    fn test_handle_debug() {
165        let obj = ObjectHandle::new(42);
166        let func = FunctionHandle::new(99);
167
168        assert_eq!(format!("{:?}", obj), "ObjectHandle(42)");
169        assert_eq!(format!("{:?}", func), "FunctionHandle(99)");
170    }
171}