broccoli_ext/
cacheable_pairs.rs

1use broccoli::{aabb::pin::HasInner, aabb::Aabb, Tree};
2
3///
4/// Used by [`CacheSession::cache_colliding_pairs()`]
5///
6/// # Safety
7///
8/// Multiple calls must return the same results while contained in [`CacheSession`]
9///
10pub unsafe trait TrustedCollisionPairs {
11    type T;
12    fn for_every_pair(&mut self, func: impl FnMut(&mut Self::T, &mut Self::T));
13}
14
15///
16/// Used by [`CacheSession::cache_elems()`]
17///
18/// # Safety
19///
20/// Multiple calls must return the same results while contained in [`CacheSession`]
21///
22pub unsafe trait TrustedIterAll {
23    type T;
24    fn for_every(&mut self, func: impl FnMut(&mut Self::T));
25}
26
27///
28/// Wrapper around a [`Tree`] that is ready to cache pairs.
29///
30pub struct IndTree<'a, 'b, T: Aabb>(pub &'b mut Tree<'a, T>);
31
32unsafe impl<T: Aabb + HasInner> TrustedCollisionPairs for IndTree<'_, '_, T> {
33    type T = T::Inner;
34    fn for_every_pair(&mut self, mut func: impl FnMut(&mut Self::T, &mut Self::T)) {
35        self.0.find_colliding_pairs(|a, b| {
36            func(a.unpack_inner(), b.unpack_inner());
37        })
38    }
39}
40
41unsafe impl<T: Aabb + HasInner> TrustedIterAll for IndTree<'_, '_, T> {
42    type T = T::Inner;
43    fn for_every(&mut self, mut func: impl FnMut(&mut Self::T)) {
44        for a in self
45            .0
46            .get_nodes_mut()
47            .iter_mut()
48            .flat_map(|x| x.into_range())
49        {
50            func(a.unpack_inner());
51        }
52    }
53}
54
55///
56/// Start a caching session.
57///
58pub struct CacheSession<'a, C> {
59    inner: &'a mut C,
60}
61
62impl<'a, C> CacheSession<'a, C> {
63    pub fn new(a: &'a mut C) -> Self {
64        CacheSession { inner: a }
65    }
66}
67
68///
69/// A set of cached elements
70///
71pub struct FilterCache<'a, C: TrustedIterAll, D> {
72    inner: *const CacheSession<'a, C>,
73    _p: std::marker::PhantomData<&'a C>,
74    data: Vec<(*mut C::T, D)>,
75}
76unsafe impl<'a, C: TrustedIterAll, D> Send for FilterCache<'a, C, D> {}
77unsafe impl<'a, C: TrustedIterAll, D> Sync for FilterCache<'a, C, D> {}
78
79impl<'a, C: TrustedIterAll, D> FilterCache<'a, C, D> {
80    pub fn handle(&mut self, c: &mut CacheSession<'a, C>) -> &mut [(&mut C::T, D)] {
81        assert_eq!(c as *const _, self.inner);
82
83        let data = self.data.as_mut_slice();
84        unsafe { &mut *(data as *mut _ as *mut _) }
85    }
86}
87
88unsafe impl<'a, C: TrustedCollisionPairs, D> Send for CollidingPairsCache<'a, C, D> {}
89unsafe impl<'a, C: TrustedCollisionPairs, D> Sync for CollidingPairsCache<'a, C, D> {}
90
91///
92/// A set of cached colliding pairs
93///
94pub struct CollidingPairsCache<'a, C: TrustedCollisionPairs, D> {
95    inner: *const CacheSession<'a, C>,
96    _p: std::marker::PhantomData<&'a C>,
97    pairs: Vec<(*mut C::T, *mut C::T, D)>,
98}
99
100impl<'a, C: TrustedCollisionPairs, D> CollidingPairsCache<'a, C, D> {
101    pub fn handle(
102        &mut self,
103        c: &mut CacheSession<'a, C>,
104        mut func: impl FnMut(&mut C::T, &mut C::T, &mut D),
105    ) {
106        assert_eq!(c as *const _, self.inner);
107
108        for (a, b, c) in self.pairs.iter_mut() {
109            let a = unsafe { &mut **a };
110            let b = unsafe { &mut **b };
111            func(a, b, c);
112        }
113    }
114}
115use std::marker::PhantomData;
116
117impl<'a, C: TrustedIterAll> CacheSession<'a, C> {
118    pub fn cache_elems<D>(
119        &mut self,
120        mut func: impl FnMut(&mut C::T) -> Option<D>,
121    ) -> FilterCache<'a, C, D> {
122        let mut data = vec![];
123        self.inner.for_every(|a| {
124            if let Some(d) = func(a) {
125                data.push((a as *mut _, d));
126            }
127        });
128        FilterCache {
129            inner: self as *const _,
130            _p: PhantomData,
131            data,
132        }
133    }
134}
135
136impl<'a, C: TrustedCollisionPairs> CacheSession<'a, C> {
137    pub fn cache_colliding_pairs<D>(
138        &mut self,
139        mut func: impl FnMut(&mut C::T, &mut C::T) -> Option<D>,
140    ) -> CollidingPairsCache<'a, C, D> {
141        let mut pairs = vec![];
142        self.inner.for_every_pair(|a, b| {
143            if let Some(res) = func(a, b) {
144                pairs.push((a as *mut _, b as *mut _, res));
145            }
146        });
147
148        CollidingPairsCache {
149            inner: self as *mut _,
150            _p: PhantomData,
151            pairs,
152        }
153    }
154
155    pub fn finish(self) -> &'a mut C {
156        self.inner
157    }
158}