type_pools/
lib.rs

1use std::{
2    any::{Any, TypeId},
3    collections::{hash_map::RandomState, HashMap},
4};
5
6/// A collection of pools or arrays that contain values of a specific type
7pub struct TypePools<H = RandomState> {
8    pools: HashMap<TypeId, Box<dyn TypePoolTrait>, H>,
9}
10
11impl TypePools {
12    pub fn new() -> Self {
13        TypePools { pools: HashMap::new() }
14    }
15
16    /// Get a reference to a type pool
17    pub fn type_pool<T: 'static>(&self) -> Option<&TypePool<T>> {
18        self.pools.get(&TypeId::of::<T>())
19            .map(|pool| {
20                unsafe { TypePool::<T>::cast_unchecked(pool.as_ref()) } // safety: we know the type is correct
21            })
22    }
23
24    /// Get a mutable reference to a type pool
25    pub fn type_pool_mut<T: 'static>(&mut self) -> Option<&mut TypePool<T>> {
26        self.pools.get_mut(&TypeId::of::<T>())
27            .map(|pool| {
28                unsafe { TypePool::<T>::cast_mut_unchecked(pool.as_mut()) } // safety: we know the type is correct
29            })
30    }
31
32    /// Add a value to the pools. If the type pool doesn't exst yet, it will be created
33    pub fn push<T: 'static>(&mut self, value: T) {
34        let pools = self.pools.get_mut(&TypeId::of::<T>());
35        if let Some(pools) = pools {
36            unsafe { TypePool::<T>::cast_mut_unchecked(pools.as_mut()) }
37                .values.push(value);
38        } else {
39            self.pools.insert(TypeId::of::<T>(), Box::new(TypePool::<T>::new()));
40            unsafe { TypePool::<T>::cast_mut_unchecked(self.pools.get_mut(&TypeId::of::<T>()).unwrap_unchecked().as_mut()) } // safety: I litterrally just created it
41                .values.push(value)
42        }
43    }
44
45    /// Returns the popped item or `None` if the value doesn't exist
46    pub fn pop<T: 'static>(&mut self) -> Option<T> {
47        self.type_pool_mut()
48            .and_then(|p| p.values.pop())
49    }
50
51    /// Remove the value at the index in the type pool specified by `T`
52    pub fn remove<T: 'static>(&mut self, idx: usize) -> Option<T> {
53        self.type_pool_mut()
54            .and_then(|p| p.values.remove(idx))
55    }
56
57    /// Gets a value from a TypePool
58    ///
59    /// # Parameters
60    /// - idx: this is the index in the specific type `T` array
61    pub fn get<T: 'static>(&self, idx: usize) -> Option<&T> {
62        self.type_pool()
63            .and_then(|p| p.values.get(idx))
64    }
65
66    /// Get a mutable reference to a value in a TypePool
67    pub fn get_mut<T: 'static>(&mut self, idx: usize) -> Option<&mut T> {
68        self.type_pool_mut()
69            .and_then(|p| p.values.get_mut(idx))
70    }
71
72    pub fn len<T: 'static>(&self) -> Option<usize> {
73        self.type_pool()
74            .map(|f: &TypePool<T>| f.values.len())
75    }
76
77    /// The amount of types stored in pools
78    pub fn types_count(&self) -> usize {
79        self.pools.keys().len()
80    }
81
82    /// The types stored in pools
83    pub fn types(&self) -> Vec<&TypeId> {
84        self.pools.keys().collect()
85    }
86
87    /// Remove all entries for a type
88    pub fn remove_type<T: 'static>(&mut self) {
89        self.pools.remove(&TypeId::of::<T>());
90    }
91
92    /// Remove all types which do not contain any values
93    pub fn remove_empty(&mut self) {
94        let to_remove = self.pools.keys()
95            // safety: the keys exist
96            .filter(|key| unsafe{ self.pools.get(key).unwrap_unchecked() }.is_empty())
97            .map(|key| *key)
98            .collect::<Vec<TypeId>>();
99
100        for id in to_remove {
101            self.pools.remove(&id);
102        }
103    }
104
105    /// Shrink the array containing all the pools to fit
106    pub fn shrink_to_fit(&mut self) {
107        self.pools.shrink_to_fit()
108    }
109
110    
111
112    // /// Returns `None` when the type does not exist in the pools
113    // pub fn reserve<T: 'static>(&mut self, additional: usize) -> Option<()> {
114    //     self.type_pool_mut()
115    //         .map(|p: &mut TypePool<T>| p.values.reserve(additional))
116    // }
117    //
118    // pub fn reserve_exact<T: 'static>(&mut self, additional: usize) -> Option<()> {
119    //     self.type_pool_mut()
120    //         .map(|p: &mut TypePool<T>| p.values.reserve_exact(additional))
121    // }
122    //
123    // pub fn try_reserve<T: 'static>(&mut self, additional: usize) -> Option<Result<(), TryReserveError>> {
124    //     self.type_pool_mut()
125    //         .map(|p: &mut TypePool<T>| p.values.try_reserve(additional))
126    // }
127    //
128    // pub fn try_reserve_exact<T: 'static>(&mut self, additional: usize) -> Option<Result<(), TryReserveError>> {
129    //     self.type_pool_mut()
130    //         .map(|p: &mut TypePool<T>| p.values.try_reserve_exact(additional))
131    // }
132    //
133    // pub fn shrink_to_fit<T: 'static>(&mut self) -> Option<()> {
134    //     self.type_pool_mut()
135    //         .map(|p: &mut TypePool<T>| p.values.shrink_to_fit())
136    // }
137
138    // TODO: implement other vec methods
139}
140
141trait TypePoolTrait {
142    fn as_any(&self) -> &dyn Any;
143    fn as_any_mut(&mut self) -> &mut dyn Any;
144    fn is_empty(&self) -> bool;
145}
146
147pub struct TypePool<T> {
148    pub values: Vec<T>,
149}
150
151impl<T: 'static> TypePool<T> {
152    fn new() -> Self {
153        Self { values: Vec::new() }
154    }
155
156    // fn cast(pool: &dyn TypePoolTrait) -> &Self {
157    //     pool.as_any()
158    //         .downcast_ref::<TypePool<T>>()
159    //         .unwrap()
160    // }
161    //
162    // fn cast_mut(pool: &mut dyn TypePoolTrait) -> &mut Self {
163    //     pool.as_any_mut()
164    //         .downcast_mut::<TypePool<T>>()
165    //         .unwrap()
166    // }
167
168    unsafe fn cast_unchecked(pool: &dyn TypePoolTrait) -> &Self {
169        pool.as_any()
170            .downcast_ref::<TypePool<T>>()
171            .unwrap_unchecked()
172    }
173
174    unsafe fn cast_mut_unchecked(pool: &mut dyn TypePoolTrait) -> &mut Self {
175        pool.as_any_mut()
176            .downcast_mut::<TypePool<T>>()
177            .unwrap_unchecked()
178    }
179}
180
181impl<T: 'static> TypePoolTrait for TypePool<T> {
182    fn as_any(&self) -> &dyn Any {
183        self
184    }
185
186    fn as_any_mut(&mut self) -> &mut dyn Any {
187        self
188    }
189
190    fn is_empty(&self) -> bool {
191        self.values.is_empty()
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use crate::TypePools;
198
199    #[test]
200    fn test_add() {
201        let mut pools = TypePools::new();
202        pools.push(1 as u32);
203        pools.push(2 as u32);
204        pools.push("Hello");
205        pools.push("World");
206
207        assert_eq!(*pools.get::<u32>(0).unwrap(), 1);
208        assert_eq!(*pools.get::<u32>(1).unwrap(), 2);
209        assert_eq!(*pools.get::<&str>(0).unwrap(), "Hello");
210        assert_eq!(*pools.get::<&str>(1).unwrap(), "World");
211    }
212}
213