intuicio_framework_ecs/
processor.rs

1use crate::{
2    entity::Entity,
3    world::{World, WorldError},
4    Component,
5};
6use intuicio_data::type_hash::TypeHash;
7use std::collections::HashMap;
8
9#[derive(Default)]
10pub struct WorldProcessor {
11    #[allow(clippy::type_complexity)]
12    remap_entities:
13        HashMap<TypeHash, Box<dyn Fn(*mut u8, WorldProcessorEntityMapping) + Send + Sync>>,
14    #[allow(clippy::type_complexity)]
15    related_entities: HashMap<TypeHash, Box<dyn Fn(*const u8) -> Vec<Entity> + Send + Sync>>,
16    #[allow(clippy::type_complexity)]
17    format: HashMap<
18        TypeHash,
19        Box<dyn Fn(*const u8, &mut std::fmt::Formatter) -> std::fmt::Result + Send + Sync>,
20    >,
21}
22
23impl WorldProcessor {
24    pub fn register_entity_remapping<T: Component>(
25        &mut self,
26        f: impl Fn(&mut T, WorldProcessorEntityMapping) + Send + Sync + 'static,
27    ) {
28        self.register_entity_remapping_raw(TypeHash::of::<T>(), move |pointer, mapping| {
29            f(unsafe { pointer.cast::<T>().as_mut().unwrap() }, mapping)
30        });
31    }
32
33    pub fn register_entity_remapping_raw(
34        &mut self,
35        type_hash: TypeHash,
36        f: impl Fn(*mut u8, WorldProcessorEntityMapping) + Send + Sync + 'static,
37    ) {
38        self.remap_entities.insert(type_hash, Box::new(f));
39    }
40
41    pub fn unregister_entity_remapping<T: Component>(&mut self) {
42        self.unregister_entity_remapping_raw(TypeHash::of::<T>());
43    }
44
45    pub fn unregister_entity_remapping_raw(&mut self, type_hash: TypeHash) {
46        self.remap_entities.remove(&type_hash);
47    }
48
49    pub fn remap_entities<T>(&self, data: &mut T, mappings: WorldProcessorEntityMapping) {
50        unsafe {
51            self.remap_entities_raw(TypeHash::of::<T>(), data as *mut T as *mut u8, mappings);
52        }
53    }
54
55    /// # Safety
56    pub unsafe fn remap_entities_raw(
57        &self,
58        type_hash: TypeHash,
59        pointer: *mut u8,
60        mappings: WorldProcessorEntityMapping,
61    ) {
62        if let Some(remapper) = self.remap_entities.get(&type_hash) {
63            remapper(pointer, mappings);
64        }
65    }
66
67    pub fn register_entity_inspector<T: Component>(
68        &mut self,
69        f: impl Fn(&T) -> Vec<Entity> + Send + Sync + 'static,
70    ) {
71        self.register_entity_inspector_raw(TypeHash::of::<T>(), move |pointer| {
72            f(unsafe { pointer.cast::<T>().as_ref().unwrap() })
73        });
74    }
75
76    pub fn register_entity_inspector_raw(
77        &mut self,
78        type_hash: TypeHash,
79        f: impl Fn(*const u8) -> Vec<Entity> + Send + Sync + 'static,
80    ) {
81        self.related_entities.insert(type_hash, Box::new(f));
82    }
83
84    pub fn unregister_entity_inspector<T: Component>(&mut self) {
85        self.unregister_entity_inspector_raw(TypeHash::of::<T>());
86    }
87
88    pub fn unregister_entity_inspector_raw(&mut self, type_hash: TypeHash) {
89        self.related_entities.remove(&type_hash);
90    }
91
92    pub fn related_entities<T>(&self, data: &T) -> Vec<Entity> {
93        unsafe { self.related_entities_raw(TypeHash::of::<T>(), data as *const T as *const u8) }
94    }
95
96    /// # Safety
97    pub unsafe fn related_entities_raw(
98        &self,
99        type_hash: TypeHash,
100        pointer: *const u8,
101    ) -> Vec<Entity> {
102        if let Some(inspector) = self.related_entities.get(&type_hash) {
103            inspector(pointer)
104        } else {
105            Default::default()
106        }
107    }
108
109    pub fn all_related_entities<const LOCKING: bool>(
110        &self,
111        world: &World,
112        entities: impl IntoIterator<Item = Entity>,
113        output: &mut Vec<Entity>,
114    ) -> Result<(), WorldError> {
115        let mut stack = entities.into_iter().collect::<Vec<_>>();
116        while let Some(entity) = stack.pop() {
117            if !output.contains(&entity) {
118                output.push(entity);
119                let row = world.row::<LOCKING>(entity)?;
120                for type_hash in row.types() {
121                    unsafe {
122                        let data = row.data(type_hash)?;
123                        stack.extend(self.related_entities_raw(type_hash, data));
124                    }
125                }
126            }
127        }
128        Ok(())
129    }
130
131    pub fn register_display_formatter<T: Component + std::fmt::Display>(&mut self) {
132        self.register_formatter::<T>(|data, fmt| data.fmt(fmt));
133    }
134
135    pub fn register_debug_formatter<T: Component + std::fmt::Debug>(&mut self) {
136        self.register_formatter::<T>(|data, fmt| data.fmt(fmt));
137    }
138
139    pub fn register_formatter<T: Component>(
140        &mut self,
141        f: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result + Send + Sync + 'static,
142    ) {
143        self.register_formatter_raw(TypeHash::of::<T>(), move |pointer, fmt| {
144            f(unsafe { pointer.cast::<T>().as_ref().unwrap() }, fmt)
145        });
146    }
147
148    pub fn register_formatter_raw(
149        &mut self,
150        type_hash: TypeHash,
151        f: impl Fn(*const u8, &mut std::fmt::Formatter) -> std::fmt::Result + Send + Sync + 'static,
152    ) {
153        self.format.insert(type_hash, Box::new(f));
154    }
155
156    pub fn unregister_formatter<T: Component>(&mut self) {
157        self.unregister_formatter_raw(TypeHash::of::<T>());
158    }
159
160    pub fn unregister_formatter_raw(&mut self, type_hash: TypeHash) {
161        self.format.remove(&type_hash);
162    }
163
164    pub fn format_component<'a, T: Component>(
165        &'a self,
166        data: &'a T,
167    ) -> WorldProcessorComponentFormat<'a, T> {
168        WorldProcessorComponentFormat {
169            processor: self,
170            data,
171        }
172    }
173
174    /// # Safety
175    pub unsafe fn format_component_raw(
176        &self,
177        type_hash: TypeHash,
178        pointer: *const u8,
179    ) -> WorldProcessorComponentFormatRaw<'_> {
180        WorldProcessorComponentFormatRaw {
181            processor: self,
182            type_hash,
183            pointer,
184        }
185    }
186
187    pub fn format_world<'a, const LOCKING: bool>(
188        &'a self,
189        world: &'a World,
190    ) -> WorldProcessorWorldFormat<'a, LOCKING> {
191        WorldProcessorWorldFormat {
192            processor: self,
193            world,
194        }
195    }
196}
197
198pub struct WorldProcessorEntityMapping<'a> {
199    mapping: &'a HashMap<Entity, Entity>,
200}
201
202impl<'a> WorldProcessorEntityMapping<'a> {
203    pub fn new(mapping: &'a HashMap<Entity, Entity>) -> Self {
204        Self { mapping }
205    }
206
207    pub fn remap(&self, entity: Entity) -> Entity {
208        self.mapping.get(&entity).copied().unwrap_or_default()
209    }
210}
211
212pub struct WorldProcessorComponentFormat<'a, T: Component> {
213    processor: &'a WorldProcessor,
214    data: &'a T,
215}
216
217impl<T: Component> WorldProcessorComponentFormat<'_, T> {
218    pub fn format(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
219        if let Some(formatter) = self.processor.format.get(&TypeHash::of::<T>()) {
220            formatter(self.data as *const T as *const u8, fmt)
221        } else {
222            write!(fmt, "<MISSING>")
223        }
224    }
225}
226
227impl<T: Component> std::fmt::Debug for WorldProcessorComponentFormat<'_, T> {
228    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229        self.format(f)
230    }
231}
232
233impl<T: Component> std::fmt::Display for WorldProcessorComponentFormat<'_, T> {
234    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235        self.format(f)
236    }
237}
238
239pub struct WorldProcessorComponentFormatRaw<'a> {
240    processor: &'a WorldProcessor,
241    type_hash: TypeHash,
242    pointer: *const u8,
243}
244
245impl WorldProcessorComponentFormatRaw<'_> {
246    pub fn format(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
247        if let Some(formatter) = self.processor.format.get(&self.type_hash) {
248            formatter(self.pointer, fmt)
249        } else {
250            write!(fmt, "<MISSING>")
251        }
252    }
253}
254
255impl std::fmt::Debug for WorldProcessorComponentFormatRaw<'_> {
256    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257        self.format(f)
258    }
259}
260
261impl std::fmt::Display for WorldProcessorComponentFormatRaw<'_> {
262    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263        self.format(f)
264    }
265}
266
267pub struct WorldProcessorWorldFormat<'a, const LOCKING: bool> {
268    processor: &'a WorldProcessor,
269    world: &'a World,
270}
271
272impl<const LOCKING: bool> WorldProcessorWorldFormat<'_, LOCKING> {
273    pub fn format(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
274        fmt.debug_list()
275            .entries(self.world.entities().map(|entity| {
276                let access = self.world.row::<LOCKING>(entity).unwrap();
277                WorldProcessorWorldRowFormat {
278                    entity,
279                    components: access
280                        .types()
281                        .map(|type_hash| WorldProcessorWorldColumnFormat {
282                            processor: self.processor,
283                            type_hash,
284                            data: unsafe { access.data(type_hash).unwrap() },
285                        })
286                        .collect(),
287                }
288            }))
289            .finish()
290    }
291}
292
293impl<const LOCKING: bool> std::fmt::Debug for WorldProcessorWorldFormat<'_, LOCKING> {
294    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295        self.format(f)
296    }
297}
298
299impl<const LOCKING: bool> std::fmt::Display for WorldProcessorWorldFormat<'_, LOCKING> {
300    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301        self.format(f)
302    }
303}
304
305struct WorldProcessorWorldRowFormat<'a> {
306    entity: Entity,
307    components: Vec<WorldProcessorWorldColumnFormat<'a>>,
308}
309
310impl WorldProcessorWorldRowFormat<'_> {
311    pub fn format(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
312        fmt.debug_list()
313            .entry(&self.entity)
314            .entries(self.components.iter())
315            .finish()
316    }
317}
318
319impl std::fmt::Debug for WorldProcessorWorldRowFormat<'_> {
320    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321        self.format(f)
322    }
323}
324
325impl std::fmt::Display for WorldProcessorWorldRowFormat<'_> {
326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327        self.format(f)
328    }
329}
330
331struct WorldProcessorWorldColumnFormat<'a> {
332    processor: &'a WorldProcessor,
333    type_hash: TypeHash,
334    data: *const u8,
335}
336
337impl WorldProcessorWorldColumnFormat<'_> {
338    pub fn format(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
339        fmt.debug_struct("Column")
340            .field("type_hash", &self.type_hash)
341            .field("component", unsafe {
342                &self
343                    .processor
344                    .format_component_raw(self.type_hash, self.data)
345            })
346            .finish()
347    }
348}
349
350impl std::fmt::Debug for WorldProcessorWorldColumnFormat<'_> {
351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352        self.format(f)
353    }
354}
355
356impl std::fmt::Display for WorldProcessorWorldColumnFormat<'_> {
357    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358        self.format(f)
359    }
360}
361
362#[cfg(test)]
363mod tests {
364    use super::*;
365    use crate::world::{Relation, World};
366
367    #[test]
368    fn test_world_merge() {
369        let mut world = World::default();
370        world.spawn((10usize,)).unwrap();
371
372        let mut world2 = World::default();
373        let a = world2.spawn((42usize,)).unwrap();
374        let b = world2.spawn((false, Relation::new((), a))).unwrap();
375        world2.spawn((true, Relation::new((), b))).unwrap();
376
377        let mut processor = WorldProcessor::default();
378        Relation::<()>::register_to_processor(&mut processor);
379
380        world.merge::<true>(world2, &processor).unwrap();
381        let entities = world.entities().collect::<Vec<_>>();
382        assert_eq!(entities.len(), 4);
383        assert_eq!(*world.component::<true, usize>(entities[0]).unwrap(), 10);
384        assert_eq!(*world.component::<true, usize>(entities[1]).unwrap(), 42);
385        assert!(!*world.component::<true, bool>(entities[2]).unwrap());
386        assert_eq!(
387            *world
388                .component::<true, Relation<()>>(entities[2])
389                .unwrap()
390                .iter()
391                .map(|(_, entity)| entity)
392                .collect::<Vec<_>>(),
393            vec![entities[1]]
394        );
395        assert!(*world.component::<true, bool>(entities[3]).unwrap());
396        assert_eq!(
397            *world
398                .component::<true, Relation<()>>(entities[3])
399                .unwrap()
400                .iter()
401                .map(|(_, entity)| entity)
402                .collect::<Vec<_>>(),
403            vec![entities[2]]
404        );
405    }
406}