1use std::cell::UnsafeCell;
5use std::hash::{Hash, Hasher};
6use std::marker::PhantomData;
7use std::ops::Deref;
8use std::{mem, ptr};
9
10use js::context::NoGC;
11use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
12
13use crate::DomObject;
14use crate::assert::assert_in_script;
15use crate::conversions::DerivedFrom;
16use crate::inheritance::Castable;
17use crate::root::{Dom, DomRoot};
18
19#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
25#[derive(JSTraceable)]
26pub struct MutDom<T: DomObject> {
27 val: UnsafeCell<Dom<T>>,
28}
29
30impl<T: DomObject> MutDom<T> {
31 pub fn new(initial: &T) -> MutDom<T> {
33 assert_in_script();
34 MutDom {
35 val: UnsafeCell::new(Dom::from_ref(initial)),
36 }
37 }
38
39 pub fn set(&self, val: &T) {
41 assert_in_script();
42 unsafe {
43 *self.val.get() = Dom::from_ref(val);
44 }
45 }
46
47 pub fn get(&self) -> DomRoot<T> {
49 assert_in_script();
50 unsafe { DomRoot::from_ref(&*ptr::read(self.val.get())) }
51 }
52
53 pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> UnrootedDom<'a, T> {
57 assert_in_script();
58 UnrootedDom {
59 inner: unsafe { ptr::read(self.val.get()) },
60 _phantom: PhantomData,
61 }
62 }
63
64 pub unsafe fn as_ref_unsafe(&self) -> &Dom<T> {
73 unsafe { &*self.val.get() }
74 }
75}
76
77impl<T: DomObject> MallocSizeOf for MutDom<T> {
78 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
79 0
81 }
82}
83
84impl<T: DomObject> PartialEq for MutDom<T> {
85 fn eq(&self, other: &Self) -> bool {
86 unsafe { *self.val.get() == *other.val.get() }
87 }
88}
89
90impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
91 fn eq(&self, other: &T) -> bool {
92 unsafe { **self.val.get() == *other }
93 }
94}
95
96#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
100pub struct UnrootedDom<'a, T: DomObject> {
101 inner: Dom<T>,
102 _phantom: PhantomData<&'a ()>,
103}
104
105impl<'a, T: DomObject + std::fmt::Debug> std::fmt::Debug for UnrootedDom<'a, T> {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 self.inner.fmt(f)
108 }
109}
110
111impl<'a, T: DomObject> Clone for UnrootedDom<'a, T> {
112 fn clone(&self) -> Self {
113 Self {
114 inner: self.inner.clone(),
115 _phantom: PhantomData,
116 }
117 }
118}
119
120impl<'a, T: DomObject> UnrootedDom<'a, T> {
121 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
126 pub(crate) fn from_dom(object: Dom<T>, _no_gc: &'a NoGC) -> UnrootedDom<'a, T> {
127 UnrootedDom {
128 inner: object,
129 _phantom: PhantomData,
130 }
131 }
132
133 pub fn from_ref(object: &T, _no_gc: &'a NoGC) -> UnrootedDom<'a, T> {
138 UnrootedDom {
139 inner: Dom::from_ref(object),
140 _phantom: PhantomData,
141 }
142 }
143}
144
145impl<'a, T: DomObject> Deref for UnrootedDom<'a, T> {
146 type Target = Dom<T>;
147
148 fn deref(&self) -> &Self::Target {
149 &self.inner
150 }
151}
152
153impl<'a, T: Castable> UnrootedDom<'a, T> {
154 pub fn upcast<U>(dom: UnrootedDom<'a, T>) -> UnrootedDom<'a, U>
156 where
157 U: Castable,
158 T: DerivedFrom<U>,
159 {
160 UnrootedDom {
161 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
162 _phantom: PhantomData,
163 }
164 }
165
166 pub fn downcast<U>(dom: UnrootedDom<'a, T>) -> Option<UnrootedDom<'a, U>>
168 where
169 U: DerivedFrom<T>,
170 {
171 if dom.is::<U>() {
172 Some(UnrootedDom {
173 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
174 _phantom: PhantomData,
175 })
176 } else {
177 None
178 }
179 }
180}
181
182impl<'a, T: DomObject> PartialEq<T> for UnrootedDom<'a, T> {
183 fn eq(&self, other: &T) -> bool {
184 self.inner == other
185 }
186}
187
188impl<'a, 'b, T: DomObject> PartialEq<UnrootedDom<'a, T>> for UnrootedDom<'b, T> {
190 fn eq(&self, other: &UnrootedDom<'a, T>) -> bool {
191 self.inner == other.inner
192 }
193}
194
195impl<'a, T: DomObject> Eq for UnrootedDom<'a, T> {}
196
197impl<'a, T: DomObject> Hash for UnrootedDom<'a, T> {
199 fn hash<H: Hasher>(&self, state: &mut H) {
200 self.inner.hash(state);
201 }
202}
203
204#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
211#[derive(JSTraceable)]
212pub struct MutNullableDom<T: DomObject> {
213 ptr: UnsafeCell<Option<Dom<T>>>,
214}
215
216impl<T: DomObject> MutNullableDom<T> {
217 pub fn new(initial: Option<&T>) -> MutNullableDom<T> {
219 assert_in_script();
220 MutNullableDom {
221 ptr: UnsafeCell::new(initial.map(Dom::from_ref)),
222 }
223 }
224
225 pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
228 where
229 F: FnOnce() -> DomRoot<T>,
230 {
231 assert_in_script();
232 match self.get() {
233 Some(inner) => inner,
234 None => {
235 let inner = cb();
236 self.set(Some(&inner));
237 inner
238 },
239 }
240 }
241
242 pub fn get(&self) -> Option<DomRoot<T>> {
245 assert_in_script();
246 unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
247 }
248
249 pub unsafe fn as_ref_unsafe(&self) -> Option<&Dom<T>> {
258 unsafe { (*self.ptr.get()).as_ref() }
259 }
260
261 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
265 pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
266 assert_in_script();
267 let ptr = unsafe { ptr::read(self.ptr.get()) };
268 ptr.map(|traced_value| Dom::from_ref(&*traced_value))
269 .map(|dom| UnrootedDom {
270 inner: dom,
271 _phantom: PhantomData,
272 })
273 }
274
275 pub fn set(&self, val: Option<&T>) {
277 assert_in_script();
278 unsafe {
279 *self.ptr.get() = val.map(|p| Dom::from_ref(p));
280 }
281 }
282
283 pub fn take(&self) -> Option<DomRoot<T>> {
285 let value = self.get();
286 self.set(None);
287 value
288 }
289
290 pub fn clear(&self) {
292 self.set(None)
293 }
294
295 pub fn if_is_some<F, R>(&self, cb: F) -> Option<&R>
297 where
298 F: FnOnce(&T) -> &R,
299 {
300 unsafe {
301 if let Some(ref value) = *self.ptr.get() {
302 Some(cb(value))
303 } else {
304 None
305 }
306 }
307 }
308}
309
310impl<T: DomObject> PartialEq for MutNullableDom<T> {
311 fn eq(&self, other: &Self) -> bool {
312 unsafe { *self.ptr.get() == *other.ptr.get() }
313 }
314}
315
316impl<T: DomObject> PartialEq<Option<&T>> for MutNullableDom<T> {
317 fn eq(&self, other: &Option<&T>) -> bool {
318 unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
319 }
320}
321
322impl<T: DomObject> Default for MutNullableDom<T> {
323 fn default() -> MutNullableDom<T> {
324 assert_in_script();
325 MutNullableDom {
326 ptr: UnsafeCell::new(None),
327 }
328 }
329}
330
331impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
332 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
333 0
335 }
336}