Skip to main content

jagua_rs/collision_detection/hazards/
collector.rs

1use crate::collision_detection::hazards::{BasicHazardEntity, HazKey, HazardEntity};
2use slotmap::{Key, SecondaryMap};
3
4/// Trait for structs that can track and store detected [`Hazard`](crate::collision_detection::hazards::Hazard)s.
5/// Used in 'collision collection' queries to avoid having to repeatedly check hazards induced by one that has already been detected.
6pub trait HazardCollector {
7    /// The entities the collected hazards are induced by.
8    type Entity: HazardEntity;
9
10    fn contains_key(&self, hkey: HazKey) -> bool;
11
12    fn contains_entity(&self, entity: &Self::Entity) -> bool {
13        self.iter().any(|(_, e)| e == entity)
14    }
15
16    fn insert(&mut self, hkey: HazKey, entity: Self::Entity);
17
18    fn remove_by_key(&mut self, hkey: HazKey);
19
20    fn remove_by_entity(&mut self, entity: &Self::Entity) {
21        let hkey = self
22            .iter()
23            .find(|(_, v)| *v == entity)
24            .map(|(hkey, _)| hkey)
25            .expect("entity not found in collector");
26        self.remove_by_key(hkey);
27    }
28
29    fn is_empty(&self) -> bool {
30        self.len() == 0
31    }
32
33    fn len(&self) -> usize;
34
35    fn iter(&self) -> impl Iterator<Item = (HazKey, &Self::Entity)>;
36
37    fn keys(&self) -> impl Iterator<Item = HazKey> {
38        self.iter().map(|(k, _)| k)
39    }
40
41    fn entities(&self) -> impl Iterator<Item = &Self::Entity> {
42        self.iter().map(|(_, e)| e)
43    }
44}
45
46/// A basic [`HazardCollector`] storing hazards by their [`HazKey`].
47#[derive(Clone, Debug)]
48pub struct BasicHazardCollector<E = BasicHazardEntity> {
49    detected: SecondaryMap<HazKey, E>,
50    /// Lossy negative filter for `detected`. The low six bits of each key select one of these 64
51    /// bits. An unset bit proves that the key is absent; a set bit is only a possible match and is
52    /// verified in `detected`. Bits stay set after removal because several keys may share a bit.
53    /// Stale bits only cause an extra map lookup.
54    detected_key_bits: u64,
55}
56
57impl<E: HazardEntity> BasicHazardCollector<E> {
58    #[must_use]
59    pub fn new() -> Self {
60        Self::with_capacity(0)
61    }
62
63    #[must_use]
64    pub fn with_capacity(capacity: usize) -> Self {
65        Self {
66            detected: SecondaryMap::with_capacity(capacity),
67            detected_key_bits: 0,
68        }
69    }
70
71    pub fn clear(&mut self) {
72        self.detected.clear();
73        self.detected_key_bits = 0;
74    }
75
76    #[must_use]
77    pub fn contains_key(&self, hkey: HazKey) -> bool {
78        self.detected_key_bits & Self::key_bit(hkey) != 0 && self.detected.contains_key(hkey)
79    }
80
81    pub fn insert(&mut self, hkey: HazKey, entity: E) -> Option<E> {
82        self.detected_key_bits |= Self::key_bit(hkey);
83        self.detected.insert(hkey, entity)
84    }
85
86    pub fn remove(&mut self, hkey: HazKey) -> Option<E> {
87        self.detected.remove(hkey)
88    }
89
90    pub fn retain(&mut self, mut predicate: impl FnMut(HazKey, &mut E) -> bool) {
91        self.detected.retain(|key, entity| predicate(key, entity));
92    }
93
94    #[must_use]
95    pub fn is_empty(&self) -> bool {
96        self.detected.is_empty()
97    }
98
99    #[must_use]
100    pub fn len(&self) -> usize {
101        self.detected.len()
102    }
103
104    pub fn iter(&self) -> impl Iterator<Item = (HazKey, &E)> {
105        self.detected.iter()
106    }
107
108    fn key_bit(hkey: HazKey) -> u64 {
109        1 << (hkey.data().as_ffi() & 63)
110    }
111}
112
113impl<E: HazardEntity> Default for BasicHazardCollector<E> {
114    fn default() -> Self {
115        Self::new()
116    }
117}
118
119impl<E: HazardEntity> HazardCollector for BasicHazardCollector<E> {
120    type Entity = E;
121
122    fn contains_key(&self, hkey: HazKey) -> bool {
123        self.contains_key(hkey)
124    }
125
126    fn insert(&mut self, hkey: HazKey, entity: E) {
127        self.insert(hkey, entity);
128    }
129
130    fn remove_by_key(&mut self, hkey: HazKey) {
131        self.remove(hkey);
132    }
133
134    fn len(&self) -> usize {
135        self.len()
136    }
137
138    fn iter(&self) -> impl Iterator<Item = (HazKey, &E)> {
139        self.iter()
140    }
141}
142
143impl<'a, E> IntoIterator for &'a BasicHazardCollector<E> {
144    type Item = (HazKey, &'a E);
145    type IntoIter = slotmap::secondary::Iter<'a, HazKey, E>;
146
147    fn into_iter(self) -> Self::IntoIter {
148        self.detected.iter()
149    }
150}