solverforge_core/domain/
variable.rs1use std::any::TypeId;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum VariableType {
8 Genuine,
10 Chained,
17 List,
19 Shadow(ShadowVariableKind),
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum ShadowVariableKind {
26 Custom,
28 InverseRelation,
30 Index,
32 NextElement,
34 PreviousElement,
36 Anchor,
38 Cascading,
40 Piggyback,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
46pub enum ValueRangeType {
47 Collection,
49 CountableRange {
51 from: i64,
53 to: i64,
55 },
56 EntityDependent,
58}
59
60impl VariableType {
61 pub fn is_genuine(&self) -> bool {
65 matches!(
66 self,
67 VariableType::Genuine | VariableType::Chained | VariableType::List
68 )
69 }
70
71 pub fn is_shadow(&self) -> bool {
73 matches!(self, VariableType::Shadow(_))
74 }
75
76 pub fn is_list(&self) -> bool {
78 matches!(self, VariableType::List)
79 }
80
81 pub fn is_chained(&self) -> bool {
85 matches!(self, VariableType::Chained)
86 }
87
88 pub fn is_basic(&self) -> bool {
90 matches!(self, VariableType::Genuine)
91 }
92}
93
94impl ShadowVariableKind {
95 pub fn requires_listener(&self) -> bool {
97 matches!(
98 self,
99 ShadowVariableKind::Custom | ShadowVariableKind::Cascading
100 )
101 }
102
103 pub fn is_automatic(&self) -> bool {
105 matches!(
106 self,
107 ShadowVariableKind::InverseRelation
108 | ShadowVariableKind::Index
109 | ShadowVariableKind::NextElement
110 | ShadowVariableKind::PreviousElement
111 | ShadowVariableKind::Anchor
112 )
113 }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq)]
121pub struct ChainedVariableInfo {
122 pub anchor_type_id: TypeId,
124 pub entity_type_id: TypeId,
126 pub has_anchor_shadow: bool,
128}
129
130impl ChainedVariableInfo {
131 pub fn new<Anchor: 'static, Entity: 'static>() -> Self {
133 Self {
134 anchor_type_id: TypeId::of::<Anchor>(),
135 entity_type_id: TypeId::of::<Entity>(),
136 has_anchor_shadow: false,
137 }
138 }
139
140 pub fn with_anchor_shadow<Anchor: 'static, Entity: 'static>() -> Self {
142 Self {
143 anchor_type_id: TypeId::of::<Anchor>(),
144 entity_type_id: TypeId::of::<Entity>(),
145 has_anchor_shadow: true,
146 }
147 }
148
149 pub fn is_anchor_type(&self, type_id: TypeId) -> bool {
151 self.anchor_type_id == type_id
152 }
153
154 pub fn is_entity_type(&self, type_id: TypeId) -> bool {
156 self.entity_type_id == type_id
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_variable_type_is_genuine() {
166 assert!(VariableType::Genuine.is_genuine());
167 assert!(VariableType::Chained.is_genuine());
168 assert!(VariableType::List.is_genuine());
169 assert!(!VariableType::Shadow(ShadowVariableKind::Custom).is_genuine());
170 }
171
172 #[test]
173 fn test_variable_type_is_shadow() {
174 assert!(!VariableType::Genuine.is_shadow());
175 assert!(!VariableType::Chained.is_shadow());
176 assert!(!VariableType::List.is_shadow());
177 assert!(VariableType::Shadow(ShadowVariableKind::Custom).is_shadow());
178 assert!(VariableType::Shadow(ShadowVariableKind::InverseRelation).is_shadow());
179 }
180
181 #[test]
182 fn test_variable_type_is_chained() {
183 assert!(!VariableType::Genuine.is_chained());
184 assert!(VariableType::Chained.is_chained());
185 assert!(!VariableType::List.is_chained());
186 assert!(!VariableType::Shadow(ShadowVariableKind::Anchor).is_chained());
187 }
188
189 #[test]
190 fn test_variable_type_is_list() {
191 assert!(!VariableType::Genuine.is_list());
192 assert!(!VariableType::Chained.is_list());
193 assert!(VariableType::List.is_list());
194 assert!(!VariableType::Shadow(ShadowVariableKind::Index).is_list());
195 }
196
197 #[test]
198 fn test_variable_type_is_basic() {
199 assert!(VariableType::Genuine.is_basic());
200 assert!(!VariableType::Chained.is_basic());
201 assert!(!VariableType::List.is_basic());
202 assert!(!VariableType::Shadow(ShadowVariableKind::Custom).is_basic());
203 }
204
205 #[test]
206 fn test_shadow_variable_kind_requires_listener() {
207 assert!(ShadowVariableKind::Custom.requires_listener());
208 assert!(ShadowVariableKind::Cascading.requires_listener());
209 assert!(!ShadowVariableKind::InverseRelation.requires_listener());
210 assert!(!ShadowVariableKind::Index.requires_listener());
211 assert!(!ShadowVariableKind::Anchor.requires_listener());
212 }
213
214 #[test]
215 fn test_shadow_variable_kind_is_automatic() {
216 assert!(!ShadowVariableKind::Custom.is_automatic());
217 assert!(!ShadowVariableKind::Cascading.is_automatic());
218 assert!(ShadowVariableKind::InverseRelation.is_automatic());
219 assert!(ShadowVariableKind::Index.is_automatic());
220 assert!(ShadowVariableKind::NextElement.is_automatic());
221 assert!(ShadowVariableKind::PreviousElement.is_automatic());
222 assert!(ShadowVariableKind::Anchor.is_automatic());
223 }
224
225 struct TestAnchor;
226 struct TestEntity;
227
228 #[test]
229 fn test_chained_variable_info_new() {
230 let info = ChainedVariableInfo::new::<TestAnchor, TestEntity>();
231
232 assert_eq!(info.anchor_type_id, TypeId::of::<TestAnchor>());
233 assert_eq!(info.entity_type_id, TypeId::of::<TestEntity>());
234 assert!(!info.has_anchor_shadow);
235 }
236
237 #[test]
238 fn test_chained_variable_info_with_anchor_shadow() {
239 let info = ChainedVariableInfo::with_anchor_shadow::<TestAnchor, TestEntity>();
240
241 assert_eq!(info.anchor_type_id, TypeId::of::<TestAnchor>());
242 assert_eq!(info.entity_type_id, TypeId::of::<TestEntity>());
243 assert!(info.has_anchor_shadow);
244 }
245
246 #[test]
247 fn test_chained_variable_info_type_checks() {
248 let info = ChainedVariableInfo::new::<TestAnchor, TestEntity>();
249
250 assert!(info.is_anchor_type(TypeId::of::<TestAnchor>()));
251 assert!(!info.is_anchor_type(TypeId::of::<TestEntity>()));
252
253 assert!(info.is_entity_type(TypeId::of::<TestEntity>()));
254 assert!(!info.is_entity_type(TypeId::of::<TestAnchor>()));
255 }
256}