type_registry/logical/
registry_ext.rs

1use std::any::Any;
2use std::ops::ControlFlow;
3use std::sync::OnceLock;
4use generic_static::StaticTypeMap;
5use crate::logical::index::Index;
6use crate::logical::Iter;
7use crate::logical::registry::Registry;
8
9/// Extension methods for [registries](Registry).
10pub trait RegistryExt: Registry {
11    /// Iterates over the entries in a [registry](Registry).
12    fn iter() -> Iter<Self>;
13
14    /// Accesses an [index](Index) associated with a [registry](Registry).
15    fn index<I: Index<Self>>() -> &'static I::Storage;
16}
17
18impl<R: Registry + ?Sized> RegistryExt for R {
19    fn iter() -> Iter<Self> {
20        Iter::new()
21    }
22    
23    fn index<I: Index<Self>>() -> &'static I::Storage {
24        static STORAGE_TYPE_MAP: OnceLock<StaticTypeMap<Box<dyn Any + Send + Sync>>> = OnceLock::new();
25        let storage_type_map = STORAGE_TYPE_MAP.get_or_init(|| StaticTypeMap::new());
26
27        let any = storage_type_map.call_once::<(fn(R), I), _>(
28            || {
29                let mut storage = I::allocate();
30                
31                for (id, entry) in R::iter() {
32                    match I::associate(&mut storage, id, entry) {
33                        ControlFlow::Continue(_) => continue,
34                        ControlFlow::Break(_) => break
35                    }
36                }
37                
38                Box::new(storage)
39            }
40        );
41
42        any.downcast_ref().expect("index storage is associated to type")
43    }
44}