1use crate::str::{CssString, CssStringWriter};
8use crate::stylesheets::Origin;
9#[cfg(feature = "gecko")]
10use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
11#[cfg(feature = "servo")]
12use parking_lot::RwLock;
13use servo_arc::Arc;
14use std::cell::UnsafeCell;
15use std::fmt;
16#[cfg(feature = "servo")]
17use std::mem;
18#[cfg(feature = "gecko")]
19use std::ptr;
20use to_shmem::{SharedMemoryBuilder, ToShmem};
21
22#[derive(Clone)]
37#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
38pub struct SharedRwLock {
39 #[cfg(feature = "servo")]
40 #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")]
41 arc: Arc<RwLock<()>>,
42
43 #[cfg(feature = "gecko")]
44 cell: Option<Arc<AtomicRefCell<SomethingZeroSizedButTyped>>>,
45}
46
47#[cfg(feature = "gecko")]
48struct SomethingZeroSizedButTyped;
49
50impl fmt::Debug for SharedRwLock {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 f.write_str("SharedRwLock")
53 }
54}
55
56impl SharedRwLock {
57 #[cfg(feature = "servo")]
59 pub fn new() -> Self {
60 SharedRwLock {
61 arc: Arc::new(RwLock::new(())),
62 }
63 }
64
65 #[cfg(feature = "gecko")]
67 pub fn new() -> Self {
68 SharedRwLock {
69 cell: Some(Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))),
70 }
71 }
72
73 #[cfg(feature = "servo")]
75 pub fn new_leaked() -> Self {
76 SharedRwLock {
77 arc: Arc::new_leaked(RwLock::new(())),
78 }
79 }
80
81 #[cfg(feature = "gecko")]
83 pub fn new_leaked() -> Self {
84 SharedRwLock {
85 cell: Some(Arc::new_leaked(AtomicRefCell::new(
86 SomethingZeroSizedButTyped,
87 ))),
88 }
89 }
90
91 #[cfg(feature = "gecko")]
93 pub fn read_only() -> Self {
94 SharedRwLock { cell: None }
95 }
96
97 #[cfg(feature = "gecko")]
98 #[inline]
99 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
100 self.cell
101 .as_ref()
102 .map(|cell| cell.as_ptr() as *const _)
103 .unwrap_or(ptr::null())
104 }
105
106 pub fn wrap<T>(&self, data: T) -> Locked<T> {
108 Locked {
109 shared_lock: self.clone(),
110 data: UnsafeCell::new(data),
111 }
112 }
113
114 #[cfg(feature = "servo")]
116 pub fn read(&self) -> SharedRwLockReadGuard {
117 mem::forget(self.arc.read());
118 SharedRwLockReadGuard(self)
119 }
120
121 #[cfg(feature = "gecko")]
123 pub fn read(&self) -> SharedRwLockReadGuard {
124 SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
125 }
126
127 #[cfg(feature = "servo")]
129 pub fn write(&self) -> SharedRwLockWriteGuard {
130 mem::forget(self.arc.write());
131 SharedRwLockWriteGuard(self)
132 }
133
134 #[cfg(feature = "gecko")]
136 pub fn write(&self) -> SharedRwLockWriteGuard {
137 SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut())
138 }
139}
140
141#[cfg(feature = "servo")]
143pub struct SharedRwLockReadGuard<'a>(&'a SharedRwLock);
144#[cfg(feature = "gecko")]
146pub struct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>);
147#[cfg(feature = "servo")]
148impl<'a> Drop for SharedRwLockReadGuard<'a> {
149 fn drop(&mut self) {
150 unsafe { self.0.arc.force_unlock_read() }
153 }
154}
155
156impl<'a> SharedRwLockReadGuard<'a> {
157 #[inline]
158 #[cfg(feature = "gecko")]
159 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
160 self.0
161 .as_ref()
162 .map(|r| &**r as *const _)
163 .unwrap_or(ptr::null())
164 }
165}
166
167#[cfg(feature = "servo")]
169pub struct SharedRwLockWriteGuard<'a>(&'a SharedRwLock);
170#[cfg(feature = "gecko")]
172pub struct SharedRwLockWriteGuard<'a>(AtomicRefMut<'a, SomethingZeroSizedButTyped>);
173#[cfg(feature = "servo")]
174impl<'a> Drop for SharedRwLockWriteGuard<'a> {
175 fn drop(&mut self) {
176 unsafe { self.0.arc.force_unlock_write() }
179 }
180}
181
182pub struct Locked<T> {
184 shared_lock: SharedRwLock,
185 data: UnsafeCell<T>,
186}
187
188unsafe impl<T: Send> Send for Locked<T> {}
191unsafe impl<T: Send + Sync> Sync for Locked<T> {}
192
193impl<T: fmt::Debug> fmt::Debug for Locked<T> {
194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195 let guard = self.shared_lock.read();
196 self.read_with(&guard).fmt(f)
197 }
198}
199
200impl<T> Locked<T> {
201 #[cfg(feature = "gecko")]
202 #[inline]
203 fn is_read_only_lock(&self) -> bool {
204 self.shared_lock.cell.is_none()
205 }
206
207 #[cfg(feature = "servo")]
208 fn same_lock_as(&self, lock: &SharedRwLock) -> bool {
209 Arc::ptr_eq(&self.shared_lock.arc, &lock.arc)
210 }
211
212 #[cfg(feature = "gecko")]
213 fn same_lock_as(&self, ptr: *const SomethingZeroSizedButTyped) -> bool {
214 ptr::eq(self.shared_lock.ptr(), ptr)
215 }
216
217 pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
219 #[cfg(feature = "gecko")]
220 assert!(
221 self.is_read_only_lock() || self.same_lock_as(guard.ptr()),
222 "Locked::read_with called with a guard from an unrelated SharedRwLock: {:?} vs. {:?}",
223 self.shared_lock.ptr(),
224 guard.ptr(),
225 );
226 #[cfg(not(feature = "gecko"))]
227 assert!(self.same_lock_as(&guard.0));
228
229 let ptr = self.data.get();
230
231 unsafe { &*ptr }
238 }
239
240 #[cfg(feature = "gecko")]
242 pub unsafe fn read_unchecked<'a>(&'a self) -> &'a T {
243 let ptr = self.data.get();
244 &*ptr
245 }
246
247 pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
249 #[cfg(feature = "gecko")]
250 assert!(
251 !self.is_read_only_lock() && self.same_lock_as(&*guard.0),
252 "Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
253 );
254 #[cfg(not(feature = "gecko"))]
255 assert!(self.same_lock_as(&guard.0));
256
257 let ptr = self.data.get();
258
259 unsafe { &mut *ptr }
268 }
269}
270
271#[cfg(feature = "gecko")]
272impl<T: ToShmem> ToShmem for Locked<T> {
273 fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
274 use std::mem::ManuallyDrop;
275
276 let guard = self.shared_lock.read();
277 Ok(ManuallyDrop::new(Locked {
278 shared_lock: SharedRwLock::read_only(),
279 data: UnsafeCell::new(ManuallyDrop::into_inner(
280 self.read_with(&guard).to_shmem(builder)?,
281 )),
282 }))
283 }
284}
285
286#[cfg(feature = "servo")]
287impl<T: ToShmem> ToShmem for Locked<T> {
288 fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
289 panic!("ToShmem not supported in Servo currently")
290 }
291}
292
293#[allow(dead_code)]
294mod compile_time_assert {
295 use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
296
297 trait Marker1 {}
298 impl<T: Clone> Marker1 for T {}
299 impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} trait Marker2 {}
303 impl<T: Copy> Marker2 for T {}
304 impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} }
307
308pub trait ToCssWithGuard {
311 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result;
313
314 #[inline]
318 fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> CssString {
319 let mut s = CssString::new();
320 self.to_css(guard, &mut s).unwrap();
321 s
322 }
323}
324
325pub trait DeepCloneWithLock: Sized {
328 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self;
330}
331
332#[derive(Clone)]
334pub struct StylesheetGuards<'a> {
335 pub author: &'a SharedRwLockReadGuard<'a>,
337
338 pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
340}
341
342impl<'a> StylesheetGuards<'a> {
343 pub fn for_origin(&self, origin: Origin) -> &SharedRwLockReadGuard<'a> {
345 match origin {
346 Origin::Author => &self.author,
347 _ => &self.ua_or_user,
348 }
349 }
350
351 pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
353 StylesheetGuards {
354 author: guard,
355 ua_or_user: guard,
356 }
357 }
358}