script/dom/bindings/
weakref.rs1use 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
17pub(crate) struct MutableWeakRef<T: WeakReferenceable> {
21 cell: UnsafeCell<Option<WeakRef<T>>>,
22}
23
24impl<T: WeakReferenceable> MutableWeakRef<T> {
25 pub(crate) fn new(value: Option<&T>) -> MutableWeakRef<T> {
27 MutableWeakRef {
28 cell: UnsafeCell::new(value.map(WeakRef::new)),
29 }
30 }
31
32 pub(crate) fn set(&self, value: Option<&T>) {
34 unsafe {
35 *self.cell.get() = value.map(WeakRef::new);
36 }
37 }
38
39 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#[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 pub(crate) fn new() -> Self {
75 WeakRefVec { vec: vec![] }
76 }
77
78 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 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#[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 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}