my_ecs/ds/map.rs
1use crate::ds::vec::OptVec;
2use std::{
3 collections::{hash_map::Entry, HashMap, HashSet},
4 hash::{BuildHasher, Hash},
5};
6
7/// A hash map containing *Group*s and *Item*s.
8///
9/// Conceptually, group contains items in it, and item can belong to multiple
10/// groups. They cannot exist without relationship to each other. In other
11/// words, they must be linked. See a diagram below. In this map, group has an
12/// ordered links to items, while item has an unordered links to groups.
13///
14/// ```text
15/// Groups G0 G1
16/// /\ /\
17/// Items I0 I1 I2
18/// ```
19///
20/// The map provides you some ways to access groups and items by their keys and
21/// indices. If possible, prefer to use index to key because it can be faster.
22#[derive(Debug, Clone)]
23pub struct GroupMap<GK, GV, IK, IV, S> {
24 /// Groups that can be accessed by either key or index.
25 ///
26 /// Key: Group key `GK`.
27 /// Value: Group value `GV` and indices to `items`.
28 groups: IndexedMap<GK, (GV, Vec<usize>), S>,
29
30 /// Items that can be accessed by either key or index.
31 ///
32 /// Key: Item key `IK`.
33 /// Value: Item value `IV` and indices to `groups`.
34 items: IndexedMap<IK, (IV, HashSet<usize, S>), S>,
35}
36
37impl<GK, GV, IK, IV, S> GroupMap<GK, GV, IK, IV, S>
38where
39 S: Default,
40{
41 /// Creates a new empty map.
42 pub fn new() -> Self {
43 Self {
44 groups: IndexedMap::new(),
45 items: IndexedMap::new(),
46 }
47 }
48}
49
50impl<GK, GV, IK, IV, S> GroupMap<GK, GV, IK, IV, S>
51where
52 GK: Hash + Eq + Clone,
53 IK: Hash + Eq + Clone,
54 S: BuildHasher,
55{
56 /// Returns true if the map contains a group at the given group index.
57 ///
58 /// Consider using [`GroupMap::contains_group2`] if you need to know whether
59 /// the map contains it or not by a key.
60 pub fn contains_group(&self, index: usize) -> bool {
61 self.groups.contains_index(index)
62 }
63
64 /// Returns true if the map contains a group corresponding to the given
65 /// group key.
66 ///
67 /// Consider using [`GroupMap::contains_group`] if you need to know whether
68 /// the map contains it or not by an index.
69 pub fn contains_group2<Q>(&self, key: &Q) -> bool
70 where
71 GK: std::borrow::Borrow<Q>,
72 Q: Hash + Eq + ?Sized,
73 {
74 self.groups.contains_key(key)
75 }
76
77 /// Retrieves a shared reference to a group and related item indices by the
78 /// given group index.
79 ///
80 /// Consider using [`GroupMap::get_group2`] if you need to get a group by
81 /// a key.
82 pub fn get_group(&self, index: usize) -> Option<(&GV, &Vec<usize>)> {
83 self.groups.get(index).map(|(value, links)| (value, links))
84 }
85
86 /// Retrieves a shared reference to a group and related item indices by the
87 /// given group key.
88 ///
89 /// Consider using [`GroupMap::get_group`] if you need to get a group by
90 /// an index.
91 pub fn get_group2<Q>(&self, key: &Q) -> Option<(&GV, &Vec<usize>)>
92 where
93 GK: std::borrow::Borrow<Q>,
94 Q: Hash + Eq + ?Sized,
95 {
96 self.groups.get2(key).map(|(value, links)| (value, links))
97 }
98
99 /// Retrieves a mutable reference to a group and related item indices by the
100 /// given group index.
101 ///
102 /// Consider using [`GroupMap::get_group_mut2`] if you need to get a group
103 /// by a key.
104 pub fn get_group_mut(&mut self, index: usize) -> Option<(&mut GV, &Vec<usize>)> {
105 self.groups
106 .get_mut(index)
107 .map(|(value, links)| (value, &*links))
108 }
109
110 /// Retrieves a mutable reference to a group and related item indices by the
111 /// given group key.
112 ///
113 /// Consider using [`GroupMap::get_group_mut`] if you need to get a group
114 /// by an index.
115 pub fn get_group_mut2<Q>(&mut self, key: &Q) -> Option<(&mut GV, &Vec<usize>)>
116 where
117 GK: std::borrow::Borrow<Q>,
118 Q: Hash + Eq + ?Sized,
119 {
120 self.groups
121 .get_mut2(key)
122 .map(|(value, links)| (value, &*links))
123 }
124
125 /// Retrieves group key corresponding to the given group index.
126 ///
127 /// You can also get a group index from a key using
128 /// [`GroupMap::get_group_index`].
129 pub fn get_group_key(&self, index: usize) -> Option<&GK> {
130 self.groups.get_key(index)
131 }
132
133 /// Retrieves a group index corresponding to the given group key.
134 ///
135 /// You can also get a group key from an index using
136 /// [`GroupMap::get_group_key`].
137 pub fn get_group_index<Q>(&self, key: &Q) -> Option<usize>
138 where
139 GK: std::borrow::Borrow<Q>,
140 Q: Hash + Eq + ?Sized,
141 {
142 self.groups.get_index(key)
143 }
144
145 /// Returns an iterator visiting all groups.
146 ///
147 /// The iterator yields pairs of group key, group index, and shared
148 /// reference to group value.
149 pub fn iter_group(&self) -> impl Iterator<Item = (&GK, usize, &GV)> {
150 self.groups
151 .iter()
152 .map(|(key, index, (value, _))| (key, index, value))
153 }
154
155 /// Returns true if the map contains an item at the given item index.
156 ///
157 /// Consider using [`GroupMap::contains_item2`] if you need to know whether
158 /// the map contains it or not by a key.
159 pub fn contains_item(&self, index: usize) -> bool {
160 self.items.contains_index(index)
161 }
162
163 /// Returns true if the map contains an item corresponding to the given item
164 /// key.
165 ///
166 /// Consider using [`GroupMap::contains_item`] if you need to know whether
167 /// the map contains it or not by an index.
168 pub fn contains_item2<Q>(&self, key: &Q) -> bool
169 where
170 IK: std::borrow::Borrow<Q>,
171 Q: Hash + Eq + ?Sized,
172 {
173 self.items.contains_key(key)
174 }
175
176 /// Retrieves a shared reference to an item and related group indices by the
177 /// given item index.
178 ///
179 /// Consider using [`GroupMap::get_item2`] if you need to get an item by a
180 /// key.
181 pub fn get_item(&self, index: usize) -> Option<&(IV, HashSet<usize, S>)> {
182 self.items.get(index)
183 }
184
185 /// Retrieves a shared reference to an item and related group indices by the
186 /// given item key.
187 ///
188 /// Consider using [`GroupMap::get_item`] if you need to get an item by an
189 /// index.
190 pub fn get_item2<Q>(&self, key: &Q) -> Option<&(IV, HashSet<usize, S>)>
191 where
192 IK: std::borrow::Borrow<Q>,
193 Q: Hash + Eq + ?Sized,
194 {
195 self.items.get2(key)
196 }
197
198 /// Retrieves a mutable reference to an item and related group indices by
199 /// the given item index.
200 ///
201 /// Consider using [`GroupMap::get_item_mut2`] if you need to get an item by
202 /// a key.
203 pub fn get_item_mut(&mut self, index: usize) -> Option<(&mut IV, &HashSet<usize, S>)> {
204 self.items
205 .get_mut(index)
206 .map(|(value, links)| (value, &*links))
207 }
208
209 /// Retrieves a mutable reference to an item and related group indices by
210 /// the given item key.
211 ///
212 /// Consider using [`GroupMap::get_item_mut`] if you need to get an item by
213 /// an index.
214 pub fn get_item_mut2<Q>(&mut self, key: &Q) -> Option<(&mut IV, &HashSet<usize, S>)>
215 where
216 IK: std::borrow::Borrow<Q>,
217 Q: Hash + Eq + ?Sized,
218 {
219 self.items
220 .get_mut2(key)
221 .map(|(value, links)| (value, &*links))
222 }
223
224 /// Retrieves an item key corresponding to the given item index.
225 ///
226 /// You can also get an item index from a key using
227 /// [`GroupMap::get_item_index`].
228 pub fn get_item_key(&self, index: usize) -> Option<&IK> {
229 self.items.get_key(index)
230 }
231
232 /// Retrieves an item index corresponding to the given item key.
233 ///
234 /// You can also get an item key from an index using
235 /// [`GroupMap::get_item_key`].
236 pub fn get_item_index<Q>(&self, key: &Q) -> Option<usize>
237 where
238 IK: std::borrow::Borrow<Q>,
239 Q: Hash + Eq + ?Sized,
240 {
241 self.items.get_index(key)
242 }
243
244 /// Returns an iterator visiting all items.
245 ///
246 /// The iterator yields pairs of item key, item index, and shared
247 /// reference to item value.
248 pub fn iter_item(&self) -> impl Iterator<Item = (&IK, usize, &IV)> {
249 self.items
250 .iter()
251 .map(|(key, index, (value, _))| (key, index, value))
252 }
253}
254
255impl<GK, GV, IK, IV, S> GroupMap<GK, GV, IK, IV, S>
256where
257 GK: Hash + Eq + Clone,
258 IK: Hash + Eq + Clone,
259 S: BuildHasher + Default,
260{
261 /// Returns the next index that will be returned on the next call to
262 /// either [`GroupMap::add_group`] or [`GroupMap::add_group_from_desc`].
263 pub fn next_index<Q>(&self, key: &Q) -> usize
264 where
265 GK: std::borrow::Borrow<Q>,
266 Q: Hash + Eq + ?Sized,
267 {
268 self.groups.next_index(key)
269 }
270
271 /// Inserts a group and related items into the map from the given group
272 /// descriptor.
273 ///
274 /// This method is a simple wrapper of [`GroupMap::add_group_from_desc`] for
275 /// easy use.
276 pub fn add_group(
277 &mut self,
278 desc: impl DescribeGroup<GK, GV, IK, IV>,
279 ) -> Result<usize, GroupDesc<GK, GV, IK, IV>> {
280 self.add_group_from_desc(desc.into_group_and_items())
281 }
282
283 /// Inserts a group and related items into the map from the given group
284 /// descriptor.
285 ///
286 /// Note that this method doesn't overwrite anything. Therefore, if the map
287 /// already contains the same group key, returns error. With respect to
288 /// item, only relation to the group is adapted and item value is dropped
289 /// if the map already contains the item. If you want replace, remove old
290 /// one first.
291 ///
292 /// # Panics
293 ///
294 /// Panics if the descriptor doesn't contain any items in it. Group cannot
295 /// exist without relationship with items. See [`GroupMap`] documentation
296 /// for more details.
297 pub fn add_group_from_desc(
298 &mut self,
299 desc: GroupDesc<GK, GV, IK, IV>,
300 ) -> Result<usize, GroupDesc<GK, GV, IK, IV>> {
301 // Panics: Group must contain related items.
302 assert!(!desc.items.is_empty());
303
304 // Err: This method doesn't allow overwriting.
305 if self.contains_group2(&desc.group_key) {
306 return Err(desc);
307 }
308
309 let GroupDesc {
310 group_key,
311 group_value,
312 items,
313 } = desc;
314
315 // Adds each item if the map doesn't contain it.
316 let item_indices = items
317 .into_iter()
318 .map(|(key, item)| {
319 if let Some(index) = self.items.get_index(&key) {
320 index
321 } else {
322 self.items.insert(key, (item, HashSet::default())).0
323 }
324 })
325 .collect::<Vec<_>>();
326
327 // Adds group.
328 let (group_index, old_group) = self
329 .groups
330 .insert(group_key, (group_value, item_indices.clone()));
331 debug_assert!(old_group.is_none());
332
333 // Updates items by adding new link to the group.
334 for index in item_indices {
335 let (_, links) = self.items.get_mut(index).unwrap();
336 links.insert(group_index);
337 }
338
339 Ok(group_index)
340 }
341
342 /// Removes a group at the given group index from the map.
343 ///
344 /// Related items are automatically removed as well if they don't have
345 /// relationships anymore by the removal of the group.
346 ///
347 /// Consider using [`GroupMap::remove_group2`] if you need to remove a group
348 /// by a key.
349 pub fn remove_group(&mut self, index: usize) -> Option<(GK, GV)> {
350 // Removes group.
351 let group_index = index;
352 let (group_key, (old_group, item_indices)) = self.groups.remove_entry(group_index)?;
353
354 // Removes corresponding items if it's possible.
355 for item_index in item_indices.iter().cloned() {
356 let (_, group_indices) = self.items.get_mut(item_index).unwrap();
357 group_indices.remove(&group_index);
358 if group_indices.is_empty() {
359 self.items.remove(item_index);
360 }
361 }
362
363 Some((group_key, old_group))
364 }
365
366 /// Removes a group corresponding to the given group key from the map.
367 ///
368 /// Related items are automatically removed as well if they don't have
369 /// relationships anymore by the removal of the group.
370 ///
371 /// Consider using [`GroupMap::remove_group`] if you need to remove a group
372 /// by an index.
373 pub fn remove_group2<Q>(&mut self, key: &Q) -> Option<(GK, GV)>
374 where
375 GK: std::borrow::Borrow<Q>,
376 Q: Hash + Eq + ?Sized,
377 {
378 let index = self.groups.get_index(key)?;
379 self.remove_group(index)
380 }
381}
382
383impl<GK, GV, IK, IV, S> Default for GroupMap<GK, GV, IK, IV, S>
384where
385 S: Default,
386{
387 fn default() -> Self {
388 Self::new()
389 }
390}
391
392/// A trait for creating [`GroupDesc`].
393pub trait DescribeGroup<GK, GV, IK, IV> {
394 fn into_group_and_items(self) -> GroupDesc<GK, GV, IK, IV>;
395}
396
397/// A descriptor for [`GroupMap`].
398///
399/// `GroupMap` is a map containing groups and items. This descriptor describes
400/// a group with its key, value, and associated items.
401#[derive(Debug)]
402pub struct GroupDesc<GK, GV, IK, IV> {
403 pub group_key: GK,
404 pub group_value: GV,
405 pub items: Vec<(IK, IV)>,
406}
407
408/// A hash map that you can find a value by an index as well.
409///
410/// It's encouraged to prefer accessing item by an index over using a key
411/// because it is simpler in terms of required operations. Plus, values are laid
412/// on sequential memory block, so that we can expect faster iteration as well.
413/// However, the map allocates more memory than usual hash map.
414///
415/// If you want to use an index as key interchangeably, then set `IMAP` to true.
416/// Then, the map keeps `index->key` relation as well so that the map can find
417/// a corresponding key from an index.
418#[derive(Debug, Clone)]
419pub struct IndexedMap<K, V, S, const IMAP: bool = true> {
420 /// Key -> An index to an item of [`Self::values`].
421 map: HashMap<K, usize, S>,
422
423 /// Index to item of [`Self::values`] -> Key.
424 ///
425 /// This field is used only when `IMAP = true`.
426 imap: OptVec<K, S>,
427
428 /// Values.
429 values: OptVec<V, S>,
430}
431
432impl<K, V, S> IndexedMap<K, V, S, true>
433where
434 S: BuildHasher,
435{
436 /// Retrieves a shared reference to a key corresponding to the given index.
437 ///
438 /// # Examples
439 ///
440 /// ```
441 /// use my_ecs::ds::IndexedMap;
442 /// use std::hash::RandomState;
443 ///
444 /// let mut map = IndexedMap::<_, _, RandomState>::new();
445 /// let (index, _) = map.insert('a', "alpha");
446 /// assert_eq!(map.get_key(index), Some(&'a'));
447 /// ```
448 pub fn get_key(&self, index: usize) -> Option<&K> {
449 self.imap.get(index)
450 }
451}
452
453impl<K, V, S> IndexedMap<K, V, S, true>
454where
455 K: Hash + Eq + Clone,
456 S: BuildHasher,
457{
458 /// Removes a value at the given index then returns it.
459 ///
460 /// Consider using [`IndexedMap::remove2`] if you need to remove a value
461 /// by a key.
462 ///
463 /// # Examples
464 ///
465 /// ```
466 /// use my_ecs::ds::IndexedMap;
467 /// use std::hash::RandomState;
468 ///
469 /// let mut map = IndexedMap::<_, _, RandomState>::new();
470 /// let (index, _) = map.insert('a', "alpha");
471 /// assert_eq!(map.remove(index), Some("alpha"));
472 /// ```
473 pub fn remove(&mut self, index: usize) -> Option<V> {
474 self.remove_entry(index).map(|(_key, value)| value)
475 }
476
477 /// Removes a value at the given index then returns it with the
478 /// corresponding key.
479 ///
480 /// Consider using [`IndexedMap::remove_entry2`] if you need to remove a
481 /// value by a key.
482 ///
483 /// # Examples
484 ///
485 /// ```
486 /// use my_ecs::ds::IndexedMap;
487 /// use std::hash::RandomState;
488 ///
489 /// let mut map = IndexedMap::<_, _, RandomState>::new();
490 /// let (index, _) = map.insert('a', "alpha");
491 /// assert_eq!(map.remove_entry(index), Some(('a', "alpha")));
492 /// ```
493 pub fn remove_entry(&mut self, index: usize) -> Option<(K, V)> {
494 let key = self.imap.get(index)?;
495 let must_some = self.map.remove(key);
496 debug_assert!(must_some.is_some());
497 // Safety: The entry exists, checked by `?` above.
498 unsafe {
499 let key = self.imap.take(index).unwrap_unchecked();
500 let value = self.values.take(index).unwrap_unchecked();
501 Some((key, value))
502 }
503 }
504}
505
506impl<K, V, S, const IMAP: bool> IndexedMap<K, V, S, IMAP>
507where
508 S: Default,
509{
510 /// Creates a new empty map.
511 ///
512 /// # Examples
513 ///
514 /// ```
515 /// use my_ecs::ds::IndexedMap;
516 /// use std::hash::RandomState;
517 ///
518 /// let map = IndexedMap::<char, &'static str, RandomState>::new();
519 /// ```
520 pub fn new() -> Self {
521 Self {
522 map: HashMap::default(),
523 imap: OptVec::new(),
524 values: OptVec::new(),
525 }
526 }
527}
528
529impl<K, V, S, const IMAP: bool> IndexedMap<K, V, S, IMAP>
530where
531 K: Hash + Eq + Clone,
532 S: BuildHasher,
533{
534 /// Returns number of items.
535 ///
536 /// # Examples
537 ///
538 /// ```
539 /// use my_ecs::ds::IndexedMap;
540 /// use std::hash::RandomState;
541 ///
542 /// let mut map = IndexedMap::<_, _, RandomState>::new();
543 /// map.insert('a', "alpha");
544 /// assert_eq!(map.len(), 1);
545 /// ```
546 pub fn len(&self) -> usize {
547 self.values.len()
548 }
549
550 /// Returns true if the map is empty.
551 ///
552 /// # Examples
553 ///
554 /// ```
555 /// use my_ecs::ds::IndexedMap;
556 /// use std::hash::RandomState;
557 ///
558 /// let map = IndexedMap::<char, &'static str, RandomState>::new();
559 /// assert!(map.is_empty());
560 /// ```
561 pub fn is_empty(&self) -> bool {
562 self.len() == 0
563 }
564
565 /// Returns true if the map contains the given key.
566 ///
567 /// # Examples
568 ///
569 /// ```
570 /// use my_ecs::ds::IndexedMap;
571 /// use std::hash::RandomState;
572 ///
573 /// let mut map = IndexedMap::<_, _, RandomState>::new();
574 /// map.insert('a', "alpha");
575 /// assert!(map.contains_key(&'a'));
576 /// ```
577 pub fn contains_key<Q>(&self, key: &Q) -> bool
578 where
579 K: std::borrow::Borrow<Q>,
580 Q: Hash + Eq + ?Sized,
581 {
582 self.map.contains_key(key)
583 }
584
585 /// Returns true if the map contains value corresponding to the given index.
586 ///
587 /// # Examples
588 ///
589 /// ```
590 /// use my_ecs::ds::IndexedMap;
591 /// use std::hash::RandomState;
592 ///
593 /// let mut map = IndexedMap::<_, _, RandomState>::new();
594 /// let (index, _) = map.insert('a', "alpha");
595 /// assert!(map.contains_index(index));
596 /// ```
597 pub fn contains_index(&self, index: usize) -> bool {
598 self.values.get(index).is_some()
599 }
600
601 /// Returns the next index that will be returned on the next call to
602 /// [`IndexedMap::insert`] with the given key.
603 ///
604 /// # Examples
605 ///
606 /// ```
607 /// use my_ecs::ds::IndexedMap;
608 /// use std::hash::RandomState;
609 ///
610 /// let mut map = IndexedMap::<_, _, RandomState>::new();
611 /// let next_index = map.next_index(&'a');
612 /// let (index, _) = map.insert('a', "alpha");
613 /// assert_eq!(next_index, index);
614 /// ```
615 pub fn next_index<Q>(&self, key: &Q) -> usize
616 where
617 K: std::borrow::Borrow<Q>,
618 Q: Hash + Eq + ?Sized,
619 {
620 if let Some(index) = self.map.get(key) {
621 *index
622 } else {
623 self.values.next_index()
624 }
625 }
626
627 /// Inserts the given key-value pair into the map and returns corresponding
628 /// index.
629 ///
630 /// If the map contains the key, then replaces values and returns old value.
631 ///
632 /// # Examples
633 ///
634 /// ```
635 /// use my_ecs::ds::IndexedMap;
636 /// use std::hash::RandomState;
637 ///
638 /// let mut map = IndexedMap::<_, _, RandomState>::new();
639 /// map.insert('a', "alpha");
640 /// let (_, old) = map.insert('a', "ah");
641 /// assert_eq!(old, Some("alpha"));
642 /// ```
643 pub fn insert(&mut self, key: K, value: V) -> (usize, Option<V>) {
644 match self.map.entry(key) {
645 Entry::Occupied(occupied) => {
646 let index = *occupied.get();
647 let old_value = self.values.set(index, Some(value));
648 (index, old_value)
649 }
650 Entry::Vacant(vacant) => {
651 let index = self.values.add(value);
652 if IMAP {
653 self.imap.extend_set(index, vacant.key().clone());
654 }
655 vacant.insert(index);
656 (index, None)
657 }
658 }
659 }
660
661 /// Removes a value corresponding to the given key then returns it.
662 ///
663 /// Consider using [`IndexedMap::remove`] if you need to remove a value by
664 /// an index.
665 ///
666 /// # Examples
667 ///
668 /// ```
669 /// use my_ecs::ds::IndexedMap;
670 /// use std::hash::RandomState;
671 ///
672 /// let mut map = IndexedMap::<_, _, RandomState>::new();
673 /// map.insert('a', "alpha");
674 /// assert_eq!(map.remove2(&'a'), Some("alpha"));
675 /// ```
676 pub fn remove2<Q>(&mut self, key: &Q) -> Option<V>
677 where
678 K: std::borrow::Borrow<Q>,
679 Q: Hash + Eq + ?Sized,
680 {
681 self.remove_entry2(key).map(|(_key, value)| value)
682 }
683
684 /// Removes a value corresponding to the given key then returns it with the
685 /// key.
686 ///
687 /// Consider using [`IndexedMap::remove_entry`] if you need to remove a
688 /// value by an index.
689 ///
690 /// # Examples
691 ///
692 /// ```
693 /// use my_ecs::ds::IndexedMap;
694 /// use std::hash::RandomState;
695 ///
696 /// let mut map = IndexedMap::<_, _, RandomState>::new();
697 /// map.insert('a', "alpha");
698 /// assert_eq!(map.remove_entry2(&'a'), Some(('a', "alpha")));
699 /// ```
700 pub fn remove_entry2<Q>(&mut self, key: &Q) -> Option<(K, V)>
701 where
702 K: std::borrow::Borrow<Q>,
703 Q: Hash + Eq + ?Sized,
704 {
705 let (key, index) = self.map.remove_entry(key)?;
706 if IMAP {
707 let must_some = self.imap.take(index);
708 debug_assert!(must_some.is_some());
709 }
710 // Safety: We got `index` from `self.map`, which guarantees that the
711 // slot must be occupied.
712 let value = unsafe { self.values.take(index).unwrap_unchecked() };
713 Some((key, value))
714 }
715
716 /// Retrieves an index corresponding to the given key.
717 ///
718 /// # Examples
719 ///
720 /// ```
721 /// use my_ecs::ds::IndexedMap;
722 /// use std::hash::RandomState;
723 ///
724 /// let mut map = IndexedMap::<_, _, RandomState>::new();
725 /// let (index, _) = map.insert('a', "alpha");
726 /// assert_eq!(map.get_index(&'a'), Some(index));
727 /// ```
728 pub fn get_index<Q>(&self, key: &Q) -> Option<usize>
729 where
730 K: std::borrow::Borrow<Q>,
731 Q: Hash + Eq + ?Sized,
732 {
733 self.map.get(key).cloned()
734 }
735
736 /// Retrieves a shared reference to a value at the given index.
737 ///
738 /// Consider using [`IndexedMap::get2`] if you need to get a value by a key.
739 ///
740 /// # Examples
741 ///
742 /// ```
743 /// use my_ecs::ds::IndexedMap;
744 /// use std::hash::RandomState;
745 ///
746 /// let mut map = IndexedMap::<_, _, RandomState>::new();
747 /// let (index, _) = map.insert('a', "alpha");
748 /// assert_eq!(map.get(index), Some(&"alpha"));
749 /// ```
750 pub fn get(&self, index: usize) -> Option<&V> {
751 self.values.get(index)
752 }
753
754 /// Retrieves a shared reference to a value corresponding to the given key.
755 ///
756 /// Consider using [`IndexedMap::get`] if you need to get a value by an
757 /// index.
758 ///
759 /// # Examples
760 ///
761 /// ```
762 /// use my_ecs::ds::IndexedMap;
763 /// use std::hash::RandomState;
764 ///
765 /// let mut map = IndexedMap::<_, _, RandomState>::new();
766 /// let (index, _) = map.insert('a', "alpha");
767 /// assert_eq!(map.get2(&'a'), Some(&"alpha"));
768 /// ```
769 pub fn get2<Q>(&self, key: &Q) -> Option<&V>
770 where
771 K: std::borrow::Borrow<Q>,
772 Q: Hash + Eq + ?Sized,
773 {
774 let index = self.get_index(key)?;
775 self.get(index)
776 }
777
778 /// Retrieves a mutable reference to a value at the given index.
779 ///
780 /// Consider using [`IndexedMap::get_mut2`] if you need to get a value by a
781 /// key.
782 ///
783 /// # Examples
784 ///
785 /// ```
786 /// use my_ecs::ds::IndexedMap;
787 /// use std::hash::RandomState;
788 ///
789 /// let mut map = IndexedMap::<_, _, RandomState>::new();
790 /// let (index, _) = map.insert('a', "alpha");
791 /// assert_eq!(map.get_mut(index), Some(&mut "alpha"));
792 /// ```
793 pub fn get_mut(&mut self, index: usize) -> Option<&mut V> {
794 self.values.get_mut(index)
795 }
796
797 /// Retrieves a mutable reference to a value corresponding to the given key.
798 ///
799 /// Consider using [`IndexedMap::get_mut`] if you need to get a value by an
800 /// index.
801 ///
802 /// # Examples
803 ///
804 /// ```
805 /// use my_ecs::ds::IndexedMap;
806 /// use std::hash::RandomState;
807 ///
808 /// let mut map = IndexedMap::<_, _, RandomState>::new();
809 /// let (index, _) = map.insert('a', "alpha");
810 /// assert_eq!(map.get_mut2(&'a'), Some(&mut "alpha"));
811 /// ```
812 pub fn get_mut2<Q>(&mut self, key: &Q) -> Option<&mut V>
813 where
814 K: std::borrow::Borrow<Q>,
815 Q: Hash + Eq + ?Sized,
816 {
817 let index = self.get_index(key)?;
818 self.get_mut(index)
819 }
820
821 /// Returns an iterator visiting key-index-value pairs in the map in
822 /// arbitrary order.
823 ///
824 /// # Examples
825 ///
826 /// ```
827 /// use my_ecs::ds::IndexedMap;
828 /// use std::hash::RandomState;
829 ///
830 /// let mut map = IndexedMap::<_, _, RandomState>::new();
831 /// map.insert('a', "alpha");
832 /// map.insert('b', "beta");
833 /// for (key, index, value) in map.iter() {
834 /// println!("{key}, {index}, {value}");
835 /// }
836 /// ```
837 pub fn iter(&self) -> impl Iterator<Item = (&K, usize, &V)> + Clone {
838 self.map.iter().map(|(key, &index)| {
839 let value = self.values.get(index).unwrap();
840 (key, index, value)
841 })
842 }
843
844 /// Returns a mutable iterator visiting key-index-value pairs in the map in
845 /// arbitrary order.
846 ///
847 /// You can modify values only through the iterator.
848 ///
849 /// # Examples
850 ///
851 /// ```
852 /// use my_ecs::ds::IndexedMap;
853 /// use std::hash::RandomState;
854 ///
855 /// let mut map = IndexedMap::<_, _, RandomState>::new();
856 /// map.insert('a', "alpha".to_owned());
857 /// map.insert('b', "beta".to_owned());
858 /// for (key, index, value) in map.iter_mut() {
859 /// value.push('*');
860 /// println!("{key}, {index}, {value}");
861 /// }
862 /// ```
863 // pub fn iter_mut(&mut self) -> IndexMapIterMut<K, V, S> {
864 pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, usize, &mut V)> {
865 self.map.iter().map(|(key, &index)| {
866 // Safety: We're braking borrow rules about `&mut V` by converting
867 // reference to pointer. But it's safe because the container `self`
868 // is still being borrowed.
869 let value = self.values.get_mut(index).unwrap();
870 let value = value as *mut V;
871 let value = unsafe { value.as_mut().unwrap_unchecked() };
872 (key, index, value)
873 })
874 }
875
876 /// Returns an iterator visiting all values.
877 ///
878 /// # Examples
879 ///
880 /// ```
881 /// use my_ecs::ds::IndexedMap;
882 /// use std::hash::RandomState;
883 ///
884 /// let mut map = IndexedMap::<_, _, RandomState>::new();
885 /// map.insert('a', "alpha");
886 /// map.insert('b', "beta");
887 /// for v in map.values() {
888 /// println!("{v}");
889 /// }
890 /// ```
891 pub fn values(&self) -> impl Iterator<Item = &V> + Clone {
892 self.values.iter()
893 }
894
895 /// Returns a mutable iterator visiting all values.
896 ///
897 /// # Examples
898 ///
899 /// ```
900 /// use my_ecs::ds::IndexedMap;
901 /// use std::hash::RandomState;
902 ///
903 /// let mut map = IndexedMap::<_, _, RandomState>::new();
904 /// map.insert('a', "alpha".to_owned());
905 /// map.insert('b', "beta".to_owned());
906 /// for v in map.values_mut() {
907 /// v.push('*');
908 /// println!("{v}");
909 /// }
910 /// ```
911 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
912 self.values.iter_mut()
913 }
914}
915
916impl<K, V, S, const IMAP: bool> Default for IndexedMap<K, V, S, IMAP>
917where
918 S: Default,
919{
920 fn default() -> Self {
921 Self::new()
922 }
923}
924
925// Don't implement From for &mut [Option<V>] because it can break mapping.
926impl<'a, K, V, S, const IMAP: bool> From<&'a IndexedMap<K, V, S, IMAP>> for &'a [Option<V>]
927where
928 S: BuildHasher,
929{
930 fn from(value: &'a IndexedMap<K, V, S, IMAP>) -> Self {
931 value.values.as_slice()
932 }
933}