Skip to content

Commit e8467a9

Browse files
committed
Implement ClearableCollection for Vec-like collections
1 parent b64e7e9 commit e8467a9

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

crates/bevy_ecs/src/system/scratch.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use alloc::{
2+
collections::{BinaryHeap, VecDeque},
3+
vec::Vec,
4+
};
15
use core::{
26
num::Saturating,
37
ops::{Deref, DerefMut},
@@ -180,3 +184,99 @@ unsafe impl<'a, T: ClearableCollection + FromWorld + Send + Sync + 'static> Read
180184
for Scratch<'a, T>
181185
{
182186
}
187+
188+
impl<T> ClearableCollection for Vec<T> {
189+
fn capacity(&self) -> usize {
190+
Vec::capacity(self)
191+
}
192+
193+
fn clear(&mut self) {
194+
Vec::clear(self);
195+
}
196+
197+
fn shrink_to(&mut self, capacity: usize) {
198+
Vec::shrink_to(self, capacity);
199+
}
200+
}
201+
202+
impl<T> ClearableCollection for VecDeque<T> {
203+
fn capacity(&self) -> usize {
204+
VecDeque::capacity(self)
205+
}
206+
207+
fn clear(&mut self) {
208+
VecDeque::clear(self);
209+
}
210+
211+
fn shrink_to(&mut self, capacity: usize) {
212+
VecDeque::shrink_to(self, capacity);
213+
}
214+
}
215+
216+
impl<I> ClearableCollection for BinaryHeap<I> {
217+
fn capacity(&self) -> usize {
218+
BinaryHeap::capacity(self)
219+
}
220+
221+
fn shrink_to(&mut self, capacity: usize) {
222+
BinaryHeap::shrink_to(self, capacity);
223+
}
224+
225+
fn clear(&mut self) {
226+
BinaryHeap::clear(self);
227+
}
228+
}
229+
230+
#[cfg(test)]
231+
mod tests {
232+
use alloc::vec::Vec;
233+
use core::sync::atomic::{AtomicU32, Ordering};
234+
235+
use crate::{
236+
system::{
237+
scratch::{Scratch, DEFAULT_SHRINK_DELAY},
238+
Local,
239+
},
240+
world::World,
241+
};
242+
243+
#[test]
244+
fn scratch_shrinks() {
245+
static UPDATE_COUNTER: AtomicU32 = AtomicU32::new(0);
246+
247+
let mut world = World::new();
248+
world.increment_change_tick();
249+
250+
fn check_system(
251+
mut item_under_test: Scratch<Vec<u32>>,
252+
mut expected_capacity: Local<usize>,
253+
) {
254+
if UPDATE_COUNTER.load(Ordering::Relaxed) == 0 {
255+
item_under_test.reserve(512);
256+
// The vec may over-reserve space so we need to store the actual capacity.
257+
*expected_capacity = item_under_test.capacity();
258+
}
259+
260+
if UPDATE_COUNTER.load(Ordering::Relaxed) == (DEFAULT_SHRINK_DELAY.0 + 1) {
261+
assert!(
262+
item_under_test.capacity() < *expected_capacity,
263+
"Scratch didn't shrink allocation, capacity was {}, expected {}, update was {}",
264+
item_under_test.capacity(),
265+
*expected_capacity,
266+
UPDATE_COUNTER.load(Ordering::Relaxed),
267+
);
268+
}
269+
}
270+
271+
let test_system = world.register_system(check_system);
272+
273+
// The first tick breaks the time calculation logic. We wait it out. We also
274+
// have to wait one for the deallocation to actually happen.
275+
for _ in 0..=(DEFAULT_SHRINK_DELAY.0 + 2) {
276+
let result = world.run_system(test_system);
277+
278+
assert!(result.is_ok(), "Test system failed to update {result:?}");
279+
UPDATE_COUNTER.fetch_add(1, Ordering::Relaxed);
280+
}
281+
}
282+
}

0 commit comments

Comments
 (0)