script/dom/bindings/
weakref.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::UnsafeCell;
6use std::mem;
7use std::ops::{Deref, DerefMut, Drop};
8
9use js::jsapi::JSTracer;
10use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
11pub(crate) use script_bindings::weakref::*;
12
13use crate::dom::bindings::cell::DomRefCell;
14use crate::dom::bindings::root::DomRoot;
15use crate::dom::bindings::trace::JSTraceable;
16
17/// A mutable weak reference to a JS-managed DOM object. On tracing,
18/// the contained weak reference is dropped if the pointee was already
19/// collected.
20pub(crate) struct MutableWeakRef<T: WeakReferenceable> {
21    cell: UnsafeCell<Option<WeakRef<T>>>,
22}
23
24impl<T: WeakReferenceable> MutableWeakRef<T> {
25    /// Create a new mutable weak reference.
26    pub(crate) fn new(value: Option<&T>) -> MutableWeakRef<T> {
27        MutableWeakRef {
28            cell: UnsafeCell::new(value.map(WeakRef::new)),
29        }
30    }
31
32    /// Set the pointee of a mutable weak reference.
33    pub(crate) fn set(&self, value: Option<&T>) {
34        unsafe {
35            *self.cell.get() = value.map(WeakRef::new);
36        }
37    }
38
39    /// DomRoot a mutable weak reference. Returns `None` if the object
40    /// was already collected.
41    pub(crate) fn root(&self) -> Option<DomRoot<T>> {
42        unsafe { &*self.cell.get() }
43            .as_ref()
44            .and_then(WeakRef::root)
45    }
46}
47
48impl<T: WeakReferenceable> MallocSizeOf for MutableWeakRef<T> {
49    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
50        0
51    }
52}
53
54unsafe impl<T: WeakReferenceable> JSTraceable for MutableWeakRef<T> {
55    unsafe fn trace(&self, _: *mut JSTracer) {
56        let ptr = self.cell.get();
57        let value = unsafe { &mut *ptr };
58        if value.as_ref().is_some_and(|value| !value.is_alive()) {
59            mem::drop(value.take().unwrap());
60        }
61    }
62}
63
64/// A vector of weak references. On tracing, the vector retains
65/// only references which still point to live objects.
66#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
67#[derive(MallocSizeOf)]
68pub(crate) struct WeakRefVec<T: WeakReferenceable> {
69    vec: Vec<WeakRef<T>>,
70}
71
72impl<T: WeakReferenceable> WeakRefVec<T> {
73    /// Create a new vector of weak references.
74    pub(crate) fn new() -> Self {
75        WeakRefVec { vec: vec![] }
76    }
77
78    /// Calls a function on each reference which still points to a
79    /// live object. The order of the references isn't preserved.
80    pub(crate) fn update<F: FnMut(WeakRefEntry<T>)>(&mut self, mut f: F) {
81        let mut i = 0;
82        while i < self.vec.len() {
83            if self.vec[i].is_alive() {
84                f(WeakRefEntry {
85                    vec: self,
86                    index: &mut i,
87                });
88            } else {
89                self.vec.swap_remove(i);
90            }
91        }
92    }
93
94    /// Clears the vector of its dead references.
95    pub(crate) fn retain_alive(&mut self) {
96        self.update(|_| ());
97    }
98}
99
100impl<T: WeakReferenceable> Deref for WeakRefVec<T> {
101    type Target = Vec<WeakRef<T>>;
102
103    fn deref(&self) -> &Vec<WeakRef<T>> {
104        &self.vec
105    }
106}
107
108impl<T: WeakReferenceable> DerefMut for WeakRefVec<T> {
109    fn deref_mut(&mut self) -> &mut Vec<WeakRef<T>> {
110        &mut self.vec
111    }
112}
113
114/// An entry of a vector of weak references. Passed to the closure
115/// given to `WeakRefVec::update`.
116#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
117pub(crate) struct WeakRefEntry<'a, T: WeakReferenceable> {
118    vec: &'a mut WeakRefVec<T>,
119    index: &'a mut usize,
120}
121
122impl<'a, T: WeakReferenceable + 'a> WeakRefEntry<'a, T> {
123    /// Remove the entry from the underlying vector of weak references.
124    pub(crate) fn remove(self) -> WeakRef<T> {
125        let ref_ = self.vec.swap_remove(*self.index);
126        mem::forget(self);
127        ref_
128    }
129}
130
131impl<'a, T: WeakReferenceable + 'a> Deref for WeakRefEntry<'a, T> {
132    type Target = WeakRef<T>;
133
134    fn deref(&self) -> &WeakRef<T> {
135        &self.vec[*self.index]
136    }
137}
138
139impl<'a, T: WeakReferenceable + 'a> Drop for WeakRefEntry<'a, T> {
140    fn drop(&mut self) {
141        *self.index += 1;
142    }
143}
144
145#[derive(MallocSizeOf)]
146pub(crate) struct DOMTracker<T: WeakReferenceable> {
147    dom_objects: DomRefCell<WeakRefVec<T>>,
148}
149
150impl<T: WeakReferenceable> DOMTracker<T> {
151    pub(crate) fn new() -> Self {
152        Self {
153            dom_objects: DomRefCell::new(WeakRefVec::new()),
154        }
155    }
156
157    pub(crate) fn track(&self, dom_object: &T) {
158        self.dom_objects.borrow_mut().push(WeakRef::new(dom_object));
159    }
160
161    pub(crate) fn for_each<F: FnMut(DomRoot<T>)>(&self, mut f: F) {
162        self.dom_objects.borrow_mut().update(|weak_ref| {
163            let root = weak_ref.root().unwrap();
164            f(root);
165        });
166    }
167}
168
169#[allow(unsafe_code)]
170unsafe impl<T: WeakReferenceable> JSTraceable for DOMTracker<T> {
171    unsafe fn trace(&self, _: *mut JSTracer) {
172        self.dom_objects.borrow_mut().retain_alive();
173    }
174}