1use std::cell::UnsafeCell;
5use std::ops::Deref;
6use std::{mem, ptr};
7
8use js::context::NoGC;
9use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
10
11use crate::DomObject;
12use crate::assert::{assert_in_layout, assert_in_script};
13use crate::conversions::DerivedFrom;
14use crate::inheritance::Castable;
15use crate::root::{Dom, DomRoot};
16
17pub trait ToLayout<'dom, T: DomObject, L: LayoutFromRaw<'dom, T>> {
18 unsafe fn to_layout(&self) -> L;
24}
25
26impl<'dom, T: DomObject, L: LayoutFromRaw<'dom, T>> ToLayout<'dom, T, L> for Dom<T> {
27 unsafe fn to_layout(&self) -> L {
28 assert_in_layout();
29 L::from_raw(unsafe { self.as_ptr().as_ref().unwrap() })
30 }
31}
32
33#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
39#[derive(JSTraceable)]
40pub struct MutDom<T: DomObject> {
41 val: UnsafeCell<Dom<T>>,
42}
43
44impl<T: DomObject> MutDom<T> {
45 pub fn new(initial: &T) -> MutDom<T> {
47 assert_in_script();
48 MutDom {
49 val: UnsafeCell::new(Dom::from_ref(initial)),
50 }
51 }
52
53 pub fn set(&self, val: &T) {
55 assert_in_script();
56 unsafe {
57 *self.val.get() = Dom::from_ref(val);
58 }
59 }
60
61 pub fn get(&self) -> DomRoot<T> {
63 assert_in_script();
64 unsafe { DomRoot::from_ref(&*ptr::read(self.val.get())) }
65 }
66}
67
68impl<T: DomObject> MallocSizeOf for MutDom<T> {
69 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
70 0
72 }
73}
74
75impl<T: DomObject> PartialEq for MutDom<T> {
76 fn eq(&self, other: &Self) -> bool {
77 unsafe { *self.val.get() == *other.val.get() }
78 }
79}
80
81impl<T: DomObject + PartialEq> PartialEq<T> for MutDom<T> {
82 fn eq(&self, other: &T) -> bool {
83 unsafe { **self.val.get() == *other }
84 }
85}
86
87#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
90pub struct UnrootedDom<'a, T: DomObject> {
91 inner: Dom<T>,
92 no_gc: &'a NoGC,
93}
94
95impl<'a, T: DomObject> UnrootedDom<'a, T> {
96 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
98 pub fn from_dom(object: Dom<T>, no_gc: &'a NoGC) -> UnrootedDom<'a, T> {
99 UnrootedDom {
100 inner: object,
101 no_gc,
102 }
103 }
104}
105
106impl<'a, T: DomObject> Deref for UnrootedDom<'a, T> {
107 type Target = Dom<T>;
108
109 fn deref(&self) -> &Self::Target {
110 &self.inner
111 }
112}
113
114impl<'a, T: Castable> UnrootedDom<'a, T> {
118 pub fn upcast<U>(dom: UnrootedDom<'a, T>) -> UnrootedDom<'a, U>
120 where
121 U: Castable,
122 T: DerivedFrom<U>,
123 {
124 UnrootedDom {
125 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
126 no_gc: dom.no_gc,
127 }
128 }
129
130 pub fn downcast<U>(dom: UnrootedDom<'a, T>) -> Option<UnrootedDom<'a, U>>
132 where
133 U: DerivedFrom<T>,
134 {
135 if dom.is::<U>() {
136 Some(UnrootedDom {
137 inner: unsafe { mem::transmute::<Dom<T>, Dom<U>>(dom.inner) },
138 no_gc: dom.no_gc,
139 })
140 } else {
141 None
142 }
143 }
144}
145
146impl<'a, T: DomObject> PartialEq<&T> for UnrootedDom<'a, T> {
147 fn eq(&self, other: &&T) -> bool {
148 self.inner == Dom::from_ref(*other)
149 }
150}
151
152pub unsafe trait LayoutFromRaw<'dom, T: DomObject> {
158 fn from_raw(d: &'dom T) -> Self;
159}
160
161#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
168#[derive(JSTraceable)]
169pub struct MutNullableDom<T: DomObject> {
170 ptr: UnsafeCell<Option<Dom<T>>>,
171}
172
173impl<T: DomObject> MutNullableDom<T> {
174 pub fn new(initial: Option<&T>) -> MutNullableDom<T> {
176 assert_in_script();
177 MutNullableDom {
178 ptr: UnsafeCell::new(initial.map(Dom::from_ref)),
179 }
180 }
181
182 pub fn or_init<F>(&self, cb: F) -> DomRoot<T>
185 where
186 F: FnOnce() -> DomRoot<T>,
187 {
188 assert_in_script();
189 match self.get() {
190 Some(inner) => inner,
191 None => {
192 let inner = cb();
193 self.set(Some(&inner));
194 inner
195 },
196 }
197 }
198
199 pub unsafe fn get_inner_as_layout<'dom, L: LayoutFromRaw<'dom, T>>(&'dom self) -> Option<L> {
204 assert_in_layout();
205 unsafe { (*self.ptr.get()).as_ref().map(|js| js.to_layout()) }
206 }
207
208 pub fn get(&self) -> Option<DomRoot<T>> {
210 assert_in_script();
211 unsafe { ptr::read(self.ptr.get()).map(|o| DomRoot::from_ref(&*o)) }
212 }
213
214 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
218 pub fn get_unrooted<'a>(&self, no_gc: &'a NoGC) -> Option<UnrootedDom<'a, T>> {
219 assert_in_script();
220 let ptr = unsafe { ptr::read(self.ptr.get()) };
221 ptr.map(|o| Dom::from_ref(&*o))
222 .map(|dom| UnrootedDom { inner: dom, no_gc })
223 }
224
225 pub fn set(&self, val: Option<&T>) {
227 assert_in_script();
228 unsafe {
229 *self.ptr.get() = val.map(|p| Dom::from_ref(p));
230 }
231 }
232
233 pub fn take(&self) -> Option<DomRoot<T>> {
235 let value = self.get();
236 self.set(None);
237 value
238 }
239
240 pub fn clear(&self) {
242 self.set(None)
243 }
244
245 pub fn if_is_some<F, R>(&self, cb: F) -> Option<&R>
247 where
248 F: FnOnce(&T) -> &R,
249 {
250 unsafe {
251 if let Some(ref value) = *self.ptr.get() {
252 Some(cb(value))
253 } else {
254 None
255 }
256 }
257 }
258}
259
260impl<T: DomObject> PartialEq for MutNullableDom<T> {
261 fn eq(&self, other: &Self) -> bool {
262 unsafe { *self.ptr.get() == *other.ptr.get() }
263 }
264}
265
266impl<T: DomObject> PartialEq<Option<&T>> for MutNullableDom<T> {
267 fn eq(&self, other: &Option<&T>) -> bool {
268 unsafe { *self.ptr.get() == other.map(Dom::from_ref) }
269 }
270}
271
272impl<T: DomObject> Default for MutNullableDom<T> {
273 fn default() -> MutNullableDom<T> {
274 assert_in_script();
275 MutNullableDom {
276 ptr: UnsafeCell::new(None),
277 }
278 }
279}
280
281impl<T: DomObject> MallocSizeOf for MutNullableDom<T> {
282 fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
283 0
285 }
286}