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 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
134impl<'a, T: DomObject> Deref for UnrootedDom<'a, T> {
135 type Target = Dom<T>;
136
137 fn deref(&self) -> &Self::Target {
138 &self.inner
139 }
140}
141
142impl<'a, T: Castable> UnrootedDom<'a, T> {
143 pub fn upcast<U>(dom: UnrootedDom<'a, T>) -> UnrootedDom<'a, U>
145 where
146 U: Castable,
147 T: DerivedFrom<U>,
148 {
149 UnrootedDom {
150 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
151 _phantom: PhantomData,
152 }
153 }
154
155 pub fn downcast<U>(dom: UnrootedDom<'a, T>) -> Option<UnrootedDom<'a, U>>
157 where
158 U: DerivedFrom<T>,
159 {
160 if dom.is::<U>() {
161 Some(UnrootedDom {
162 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
163 _phantom: PhantomData,
164 })
165 } else {
166 None
167 }
168 }
169}
170
171impl<'a, T: DomObject> PartialEq<T> for UnrootedDom<'a, T> {
172 fn eq(&self, other: &T) -> bool {
173 self.inner == other
174 }
175}
176
177impl<'a, 'b, T: DomObject> PartialEq<UnrootedDom<'a, T>> for UnrootedDom<'b, T> {
179 fn eq(&self, other: &UnrootedDom<'a, T>) -> bool {
180 self.inner == other.inner
181 }
182}
183
184impl<'a, T: DomObject> Eq for UnrootedDom<'a, T> {}
185
186impl<'a, T: DomObject> Hash for UnrootedDom<'a, T> {
188 fn hash<H: Hasher>(&self, state: &mut H) {
189 self.inner.hash(state);
190 }
191}
192
193#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
200#[derive(JSTraceable)]
201pub struct MutNullableDom<T: DomObject> {
202 ptr: UnsafeCell<Option<Dom<T>>>,
203}
204
205impl<T: DomObject> MutNullableDom<T> {
206 pub fn new(initial: Option<&T>) -> MutNullableDom<T> {
208 assert_in_script();
209 MutNullableDom {
210 ptr: UnsafeCell::new(initial.map(Dom::from_ref)),
211 }
212 }
213
214 pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
217 where
218 F: FnOnce() -> DomRoot<T>,
219 {
220 assert_in_script();
221 match self.get() {
222 Some(inner) => inner,
223 None => {
224 let inner = cb();
225 self.set(Some(&inner));
226 inner
227 },
228 }
229 }
230
231 pub fn get(&self) -> Option<DomRoot<T>> {
234 assert_in_script();
235 unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
236 }
237
238 pub unsafe fn as_ref_unsafe(&self) -> Option<&Dom<T>> {
247 unsafe { (*self.ptr.get()).as_ref() }
248 }
249
250 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
254 pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
255 assert_in_script();
256 let ptr = unsafe { ptr::read(self.ptr.get()) };
257 ptr.map(|traced_value| Dom::from_ref(&*traced_value))
258 .map(|dom| UnrootedDom {
259 inner: dom,
260 _phantom: PhantomData,
261 })
262 }
263
264 pub fn set(&self, val: Option<&T>) {
266 assert_in_script();
267 unsafe {
268 *self.ptr.get() = val.map(|p| Dom::from_ref(p));
269 }
270 }
271
272 pub fn take(&self) -> Option<DomRoot<T>> {
274 let value = self.get();
275 self.set(None);
276 value
277 }
278
279 pub fn clear(&self) {
281 self.set(None)
282 }
283
284 pub fn if_is_some<F, R>(&self, cb: F) -> Option<&R>
286 where
287 F: FnOnce(&T) -> &R,
288 {
289 unsafe {
290 if let Some(ref value) = *self.ptr.get() {
291 Some(cb(value))
292 } else {
293 None
294 }
295 }
296 }
297}
298
299impl<T: DomObject> PartialEq for MutNullableDom<T> {
300 fn eq(&self, other: &Self) -> bool {
301 unsafe { *self.ptr.get() == *other.ptr.get() }
302 }
303}
304
305impl<T: DomObject> PartialEq<Option<&T>> for MutNullableDom<T> {
306 fn eq(&self, other: &Option<&T>) -> bool {
307 unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
308 }
309}
310
311impl<T: DomObject> Default for MutNullableDom<T> {
312 fn default() -> MutNullableDom<T> {
313 assert_in_script();
314 MutNullableDom {
315 ptr: UnsafeCell::new(None),
316 }
317 }
318}
319
320impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
321 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
322 0
324 }
325}