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