1use std::cell::UnsafeCell;
5use std::marker::PhantomData;
6use std::ops::Deref;
7use std::{mem, ptr};
8
9use js::context::NoGC;
10use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
11
12use crate::DomObject;
13use crate::assert::assert_in_script;
14use crate::conversions::DerivedFrom;
15use crate::inheritance::Castable;
16use crate::root::{Dom, DomRoot};
17
18#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
24#[derive(JSTraceable)]
25pub struct MutDom<T: DomObject> {
26 val: UnsafeCell<Dom<T>>,
27}
28
29impl<T: DomObject> MutDom<T> {
30 pub fn new(initial: &T) -> MutDom<T> {
32 assert_in_script();
33 MutDom {
34 val: UnsafeCell::new(Dom::from_ref(initial)),
35 }
36 }
37
38 pub fn set(&self, val: &T) {
40 assert_in_script();
41 unsafe {
42 *self.val.get() = Dom::from_ref(val);
43 }
44 }
45
46 pub fn get(&self) -> DomRoot<T> {
48 assert_in_script();
49 unsafe { DomRoot::from_ref(&*ptr::read(self.val.get())) }
50 }
51
52 pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> UnrootedDom<'a, T> {
56 assert_in_script();
57 UnrootedDom {
58 inner: unsafe { ptr::read(self.val.get()) },
59 _phantom: PhantomData,
60 }
61 }
62
63 pub unsafe fn as_ref_unsafe(&self) -> &Dom<T> {
72 unsafe { &*self.val.get() }
73 }
74}
75
76impl<T: DomObject> MallocSizeOf for MutDom<T> {
77 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
78 0
80 }
81}
82
83impl<T: DomObject> PartialEq for MutDom<T> {
84 fn eq(&self, other: &Self) -> bool {
85 unsafe { *self.val.get() == *other.val.get() }
86 }
87}
88
89impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
90 fn eq(&self, other: &T) -> bool {
91 unsafe { **self.val.get() == *other }
92 }
93}
94
95#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
99pub struct UnrootedDom<'a, T: DomObject> {
100 inner: Dom<T>,
101 _phantom: PhantomData<&'a ()>,
102}
103
104impl<'a, T: DomObject + std::fmt::Debug> std::fmt::Debug for UnrootedDom<'a, T> {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 self.inner.fmt(f)
107 }
108}
109
110impl<'a, T: DomObject> Clone for UnrootedDom<'a, T> {
111 fn clone(&self) -> Self {
112 Self {
113 inner: self.inner.clone(),
114 _phantom: PhantomData,
115 }
116 }
117}
118
119impl<'a, T: DomObject> UnrootedDom<'a, T> {
120 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
125 pub fn from_dom(object: Dom<T>, _no_gc: &'a NoGC) -> UnrootedDom<'a, T> {
126 UnrootedDom {
127 inner: object,
128 _phantom: PhantomData,
129 }
130 }
131}
132
133impl<'a, T: DomObject> Deref for UnrootedDom<'a, T> {
134 type Target = Dom<T>;
135
136 fn deref(&self) -> &Self::Target {
137 &self.inner
138 }
139}
140
141impl<'a, T: Castable> UnrootedDom<'a, T> {
142 pub fn upcast<U>(dom: UnrootedDom<'a, T>) -> UnrootedDom<'a, U>
144 where
145 U: Castable,
146 T: DerivedFrom<U>,
147 {
148 UnrootedDom {
149 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
150 _phantom: PhantomData,
151 }
152 }
153
154 pub fn downcast<U>(dom: UnrootedDom<'a, T>) -> Option<UnrootedDom<'a, U>>
156 where
157 U: DerivedFrom<T>,
158 {
159 if dom.is::<U>() {
160 Some(UnrootedDom {
161 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
162 _phantom: PhantomData,
163 })
164 } else {
165 None
166 }
167 }
168}
169
170impl<'a, T: DomObject> PartialEq<T> for UnrootedDom<'a, T> {
171 fn eq(&self, other: &T) -> bool {
172 self.inner == other
173 }
174}
175
176impl<'a, 'b, T: DomObject> PartialEq<UnrootedDom<'a, T>> for UnrootedDom<'b, T> {
177 fn eq(&self, other: &UnrootedDom<'a, T>) -> bool {
178 self.inner == other.inner
179 }
180}
181
182#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
189#[derive(JSTraceable)]
190pub struct MutNullableDom<T: DomObject> {
191 ptr: UnsafeCell<Option<Dom<T>>>,
192}
193
194impl<T: DomObject> MutNullableDom<T> {
195 pub fn new(initial: Option<&T>) -> MutNullableDom<T> {
197 assert_in_script();
198 MutNullableDom {
199 ptr: UnsafeCell::new(initial.map(Dom::from_ref)),
200 }
201 }
202
203 pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
206 where
207 F: FnOnce() -> DomRoot<T>,
208 {
209 assert_in_script();
210 match self.get() {
211 Some(inner) => inner,
212 None => {
213 let inner = cb();
214 self.set(Some(&inner));
215 inner
216 },
217 }
218 }
219
220 pub fn get(&self) -> Option<DomRoot<T>> {
223 assert_in_script();
224 unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
225 }
226
227 pub unsafe fn as_ref_unsafe(&self) -> Option<&Dom<T>> {
236 unsafe { (*self.ptr.get()).as_ref() }
237 }
238
239 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
243 pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
244 assert_in_script();
245 let ptr = unsafe { ptr::read(self.ptr.get()) };
246 ptr.map(|traced_value| Dom::from_ref(&*traced_value))
247 .map(|dom| UnrootedDom {
248 inner: dom,
249 _phantom: PhantomData,
250 })
251 }
252
253 pub fn set(&self, val: Option<&T>) {
255 assert_in_script();
256 unsafe {
257 *self.ptr.get() = val.map(|p| Dom::from_ref(p));
258 }
259 }
260
261 pub fn take(&self) -> Option<DomRoot<T>> {
263 let value = self.get();
264 self.set(None);
265 value
266 }
267
268 pub fn clear(&self) {
270 self.set(None)
271 }
272
273 pub fn if_is_some<F, R>(&self, cb: F) -> Option<&R>
275 where
276 F: FnOnce(&T) -> &R,
277 {
278 unsafe {
279 if let Some(ref value) = *self.ptr.get() {
280 Some(cb(value))
281 } else {
282 None
283 }
284 }
285 }
286}
287
288impl<T: DomObject> PartialEq for MutNullableDom<T> {
289 fn eq(&self, other: &Self) -> bool {
290 unsafe { *self.ptr.get() == *other.ptr.get() }
291 }
292}
293
294impl<T: DomObject> PartialEq<Option<&T>> for MutNullableDom<T> {
295 fn eq(&self, other: &Option<&T>) -> bool {
296 unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
297 }
298}
299
300impl<T: DomObject> Default for MutNullableDom<T> {
301 fn default() -> MutNullableDom<T> {
302 assert_in_script();
303 MutNullableDom {
304 ptr: UnsafeCell::new(None),
305 }
306 }
307}
308
309impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
310 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
311 0
313 }
314}