wgpu_core/
weak_vec.rs

1//! Module containing the [`WeakVec`] API.
2
3use alloc::{sync::Weak, vec::Vec};
4
5/// An optimized container for `Weak` references of `T` that minimizes reallocations by
6/// dropping older elements that no longer have strong references to them.
7#[derive(Debug)]
8pub(crate) struct WeakVec<T> {
9    inner: Vec<Weak<T>>,
10}
11
12impl<T> Default for WeakVec<T> {
13    fn default() -> Self {
14        Self {
15            inner: Default::default(),
16        }
17    }
18}
19
20impl<T> WeakVec<T> {
21    pub(crate) fn new() -> Self {
22        Self { inner: Vec::new() }
23    }
24
25    /// Pushes a new element to this collection.
26    ///
27    /// If the inner Vec needs to be reallocated, we will first drop older elements that
28    /// no longer have strong references to them.
29    pub(crate) fn push(&mut self, value: Weak<T>) {
30        if self.inner.len() == self.inner.capacity() {
31            // Iterating backwards has the advantage that we don't do more work than we have to.
32            for i in (0..self.inner.len()).rev() {
33                if self.inner[i].strong_count() == 0 {
34                    self.inner.swap_remove(i);
35                }
36            }
37
38            // Make sure our capacity is twice the number of live elements.
39            // Leaving some spare capacity ensures that we won't re-scan immediately.
40            self.inner.reserve_exact(self.inner.len());
41        }
42
43        self.inner.push(value);
44    }
45}
46
47pub(crate) struct WeakVecIter<T> {
48    inner: alloc::vec::IntoIter<Weak<T>>,
49}
50
51impl<T> Iterator for WeakVecIter<T> {
52    type Item = Weak<T>;
53    fn next(&mut self) -> Option<Self::Item> {
54        self.inner.next()
55    }
56}
57
58impl<T> IntoIterator for WeakVec<T> {
59    type Item = Weak<T>;
60    type IntoIter = WeakVecIter<T>;
61    fn into_iter(self) -> Self::IntoIter {
62        WeakVecIter {
63            inner: self.inner.into_iter(),
64        }
65    }
66}