solverforge_core/domain/
entity_ref.rs1use std::any::Any;
8use std::fmt::Debug;
9
10#[derive(Debug, Clone)]
16pub struct EntityRef {
17 pub index: usize,
19 pub type_name: &'static str,
21 pub collection_field: &'static str,
23}
24
25impl EntityRef {
26 pub fn new(index: usize, type_name: &'static str, collection_field: &'static str) -> Self {
27 Self {
28 index,
29 type_name,
30 collection_field,
31 }
32 }
33}
34
35pub trait EntityExtractor: Send + Sync {
40 fn count(&self, solution: &dyn Any) -> Option<usize>;
41
42 fn get<'a>(&self, solution: &'a dyn Any, index: usize) -> Option<&'a dyn Any>;
43
44 fn get_mut<'a>(&self, solution: &'a mut dyn Any, index: usize) -> Option<&'a mut dyn Any>;
45
46 fn entity_refs(&self, solution: &dyn Any) -> Vec<EntityRef>;
48
49 fn clone_box(&self) -> Box<dyn EntityExtractor>;
51
52 fn clone_entity_boxed(
58 &self,
59 solution: &dyn Any,
60 index: usize,
61 ) -> Option<Box<dyn Any + Send + Sync>>;
62
63 fn entity_type_id(&self) -> std::any::TypeId;
64}
65
66impl Clone for Box<dyn EntityExtractor> {
67 fn clone(&self) -> Self {
68 self.clone_box()
69 }
70}
71
72pub struct TypedEntityExtractor<S, E> {
78 type_name: &'static str,
80 collection_field: &'static str,
82 get_collection: fn(&S) -> &Vec<E>,
84 get_collection_mut: fn(&mut S) -> &mut Vec<E>,
86}
87
88impl<S, E> TypedEntityExtractor<S, E>
89where
90 S: 'static,
91 E: 'static,
92{
93 pub fn new(
94 type_name: &'static str,
95 collection_field: &'static str,
96 get_collection: fn(&S) -> &Vec<E>,
97 get_collection_mut: fn(&mut S) -> &mut Vec<E>,
98 ) -> Self {
99 Self {
100 type_name,
101 collection_field,
102 get_collection,
103 get_collection_mut,
104 }
105 }
106}
107
108impl<S, E> EntityExtractor for TypedEntityExtractor<S, E>
109where
110 S: Send + Sync + 'static,
111 E: Clone + Send + Sync + 'static,
112{
113 fn count(&self, solution: &dyn Any) -> Option<usize> {
114 let solution = solution.downcast_ref::<S>()?;
115 Some((self.get_collection)(solution).len())
116 }
117
118 fn get<'a>(&self, solution: &'a dyn Any, index: usize) -> Option<&'a dyn Any> {
119 let solution = solution.downcast_ref::<S>()?;
120 let collection = (self.get_collection)(solution);
121 collection.get(index).map(|e| e as &dyn Any)
122 }
123
124 fn get_mut<'a>(&self, solution: &'a mut dyn Any, index: usize) -> Option<&'a mut dyn Any> {
125 let solution = solution.downcast_mut::<S>()?;
126 let collection = (self.get_collection_mut)(solution);
127 collection.get_mut(index).map(|e| e as &mut dyn Any)
128 }
129
130 fn entity_refs(&self, solution: &dyn Any) -> Vec<EntityRef> {
131 let Some(solution) = solution.downcast_ref::<S>() else {
132 return Vec::new();
133 };
134 let collection = (self.get_collection)(solution);
135 (0..collection.len())
136 .map(|i| EntityRef::new(i, self.type_name, self.collection_field))
137 .collect()
138 }
139
140 fn clone_box(&self) -> Box<dyn EntityExtractor> {
141 Box::new(Self {
142 type_name: self.type_name,
143 collection_field: self.collection_field,
144 get_collection: self.get_collection,
145 get_collection_mut: self.get_collection_mut,
146 })
147 }
148
149 fn clone_entity_boxed(
150 &self,
151 solution: &dyn Any,
152 index: usize,
153 ) -> Option<Box<dyn Any + Send + Sync>> {
154 let solution = solution.downcast_ref::<S>()?;
155 let collection = (self.get_collection)(solution);
156 let entity = collection.get(index)?;
157 Some(Box::new(entity.clone()) as Box<dyn Any + Send + Sync>)
158 }
159
160 fn entity_type_id(&self) -> std::any::TypeId {
161 std::any::TypeId::of::<E>()
162 }
163}
164
165impl<S, E> Debug for TypedEntityExtractor<S, E> {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 f.debug_struct("TypedEntityExtractor")
168 .field("type_name", &self.type_name)
169 .field("collection_field", &self.collection_field)
170 .finish()
171 }
172}