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
53impl<T: DomObject> MallocSizeOf for MutDom<T> {
54 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
55 0
57 }
58}
59
60impl<T: DomObject> PartialEq for MutDom<T> {
61 fn eq(&self, other: &Self) -> bool {
62 unsafe { *self.val.get() == *other.val.get() }
63 }
64}
65
66impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
67 fn eq(&self, other: &T) -> bool {
68 unsafe { **self.val.get() == *other }
69 }
70}
71
72#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
76pub struct UnrootedDom<'a, T: DomObject> {
77 inner: Dom<T>,
78 _phantom: PhantomData<&'a ()>,
79}
80
81impl<'a, T: DomObject + std::fmt::Debug> std::fmt::Debug for UnrootedDom<'a, T> {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 self.inner.fmt(f)
84 }
85}
86
87impl<'a, T: DomObject> Clone for UnrootedDom<'a, T> {
88 fn clone(&self) -> Self {
89 Self {
90 inner: self.inner.clone(),
91 _phantom: PhantomData,
92 }
93 }
94}
95
96impl<'a, T: DomObject> UnrootedDom<'a, T> {
97 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
102 pub fn from_dom(object: Dom<T>, _no_gc: &'a NoGC) -> UnrootedDom<'a, T> {
103 UnrootedDom {
104 inner: object,
105 _phantom: PhantomData,
106 }
107 }
108}
109
110impl<'a, T: DomObject> Deref for UnrootedDom<'a, T> {
111 type Target = Dom<T>;
112
113 fn deref(&self) -> &Self::Target {
114 &self.inner
115 }
116}
117
118impl<'a, T: Castable> UnrootedDom<'a, T> {
119 pub fn upcast<U>(dom: UnrootedDom<'a, T>) -> UnrootedDom<'a, U>
121 where
122 U: Castable,
123 T: DerivedFrom<U>,
124 {
125 UnrootedDom {
126 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
127 _phantom: PhantomData,
128 }
129 }
130
131 pub fn downcast<U>(dom: UnrootedDom<'a, T>) -> Option<UnrootedDom<'a, U>>
133 where
134 U: DerivedFrom<T>,
135 {
136 if dom.is::<U>() {
137 Some(UnrootedDom {
138 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
139 _phantom: PhantomData,
140 })
141 } else {
142 None
143 }
144 }
145}
146
147impl<'a, T: DomObject> PartialEq<T> for UnrootedDom<'a, T> {
148 fn eq(&self, other: &T) -> bool {
149 self.inner == other
150 }
151}
152
153impl<'a, T: DomObject> PartialEq<UnrootedDom<'a, T>> for UnrootedDom<'a, T> {
154 fn eq(&self, other: &UnrootedDom<'a, T>) -> bool {
155 self.inner == other.inner
156 }
157}
158
159#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
166#[derive(JSTraceable)]
167pub struct MutNullableDom<T: DomObject> {
168 ptr: UnsafeCell<Option<Dom<T>>>,
169}
170
171impl<T: DomObject> MutNullableDom<T> {
172 pub fn new(initial: Option<&T>) -> MutNullableDom<T> {
174 assert_in_script();
175 MutNullableDom {
176 ptr: UnsafeCell::new(initial.map(Dom::from_ref)),
177 }
178 }
179
180 pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
183 where
184 F: FnOnce() -> DomRoot<T>,
185 {
186 assert_in_script();
187 match self.get() {
188 Some(inner) => inner,
189 None => {
190 let inner = cb();
191 self.set(Some(&inner));
192 inner
193 },
194 }
195 }
196
197 pub fn get(&self) -> Option<DomRoot<T>> {
200 assert_in_script();
201 unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
202 }
203
204 pub unsafe fn as_ref_unsafe(&self) -> Option<&Dom<T>> {
213 unsafe { (*self.ptr.get()).as_ref() }
214 }
215
216 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
220 pub fn get_unrooted<'a>(&self, _: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
221 assert_in_script();
222 let ptr = unsafe { ptr::read(self.ptr.get()) };
223 ptr.map(|traced_value| Dom::from_ref(&*traced_value))
224 .map(|dom| UnrootedDom {
225 inner: dom,
226 _phantom: PhantomData,
227 })
228 }
229
230 pub fn set(&self, val: Option<&T>) {
232 assert_in_script();
233 unsafe {
234 *self.ptr.get() = val.map(|p| Dom::from_ref(p));
235 }
236 }
237
238 pub fn take(&self) -> Option<DomRoot<T>> {
240 let value = self.get();
241 self.set(None);
242 value
243 }
244
245 pub fn clear(&self) {
247 self.set(None)
248 }
249
250 pub fn if_is_some<F, R>(&self, cb: F) -> Option<&R>
252 where
253 F: FnOnce(&T) -> &R,
254 {
255 unsafe {
256 if let Some(ref value) = *self.ptr.get() {
257 Some(cb(value))
258 } else {
259 None
260 }
261 }
262 }
263}
264
265impl<T: DomObject> PartialEq for MutNullableDom<T> {
266 fn eq(&self, other: &Self) -> bool {
267 unsafe { *self.ptr.get() == *other.ptr.get() }
268 }
269}
270
271impl<T: DomObject> PartialEq<Option<&T>> for MutNullableDom<T> {
272 fn eq(&self, other: &Option<&T>) -> bool {
273 unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
274 }
275}
276
277impl<T: DomObject> Default for MutNullableDom<T> {
278 fn default() -> MutNullableDom<T> {
279 assert_in_script();
280 MutNullableDom {
281 ptr: UnsafeCell::new(None),
282 }
283 }
284}
285
286impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
287 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
288 0
290 }
291}