1use crate::stylesheets::Origin;
8use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
9use servo_arc::Arc;
10use std::cell::UnsafeCell;
11use std::fmt;
12use std::ptr;
13use style_traits::{CssString, CssStringWriter};
14use to_shmem::{SharedMemoryBuilder, ToShmem};
15
16#[derive(Clone)]
27pub struct SharedRwLock {
28 cell: Option<Arc<AtomicRefCell<SomethingZeroSizedButTyped>>>,
29}
30
31#[cfg(feature = "servo")]
32malloc_size_of::malloc_size_of_is_0!(SharedRwLock);
33
34#[cfg_attr(feature = "servo", derive(crate::derives::MallocSizeOf))]
35struct SomethingZeroSizedButTyped;
36
37impl fmt::Debug for SharedRwLock {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 f.write_str("SharedRwLock")
40 }
41}
42
43impl SharedRwLock {
44 pub fn new() -> Self {
46 SharedRwLock {
47 cell: Some(Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))),
48 }
49 }
50
51 pub fn new_leaked() -> Self {
53 SharedRwLock {
54 cell: Some(Arc::new_leaked(AtomicRefCell::new(
55 SomethingZeroSizedButTyped,
56 ))),
57 }
58 }
59
60 pub fn read_only() -> Self {
62 SharedRwLock { cell: None }
63 }
64
65 #[inline]
66 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
67 self.cell
68 .as_ref()
69 .map(|cell| cell.as_ptr() as *const _)
70 .unwrap_or(ptr::null())
71 }
72
73 pub fn wrap<T>(&self, data: T) -> Locked<T> {
75 Locked {
76 shared_lock: self.clone(),
77 data: UnsafeCell::new(data),
78 }
79 }
80
81 pub fn read(&self) -> SharedRwLockReadGuard<'_> {
83 SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
84 }
85
86 pub fn write(&self) -> SharedRwLockWriteGuard<'_> {
88 SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut())
89 }
90}
91
92pub struct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>);
94
95impl<'a> SharedRwLockReadGuard<'a> {
96 #[inline]
97 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
98 self.0
99 .as_ref()
100 .map(|r| &**r as *const _)
101 .unwrap_or(ptr::null())
102 }
103}
104
105pub struct SharedRwLockWriteGuard<'a>(AtomicRefMut<'a, SomethingZeroSizedButTyped>);
107
108pub struct Locked<T> {
110 shared_lock: SharedRwLock,
111 data: UnsafeCell<T>,
112}
113
114unsafe impl<T: Send> Send for Locked<T> {}
117unsafe impl<T: Send + Sync> Sync for Locked<T> {}
118
119impl<T: fmt::Debug> fmt::Debug for Locked<T> {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 let guard = self.shared_lock.read();
122 self.read_with(&guard).fmt(f)
123 }
124}
125
126impl<T> Locked<T> {
127 #[inline]
128 fn is_read_only_lock(&self) -> bool {
129 self.shared_lock.cell.is_none()
130 }
131
132 fn same_lock_as(&self, ptr: *const SomethingZeroSizedButTyped) -> bool {
133 ptr::eq(self.shared_lock.ptr(), ptr)
134 }
135
136 pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
138 assert!(
139 self.is_read_only_lock() || self.same_lock_as(guard.ptr()),
140 "Locked::read_with called with a guard from an unrelated SharedRwLock: {:?} vs. {:?}",
141 self.shared_lock.ptr(),
142 guard.ptr(),
143 );
144
145 let ptr = self.data.get();
146
147 unsafe { &*ptr }
154 }
155
156 pub unsafe fn read_unchecked<'a>(&'a self) -> &'a T {
158 let ptr = self.data.get();
159 &*ptr
160 }
161
162 pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
164 assert!(
165 !self.is_read_only_lock() && self.same_lock_as(&*guard.0),
166 "Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
167 );
168
169 let ptr = self.data.get();
170
171 unsafe { &mut *ptr }
180 }
181}
182
183impl<T: ToShmem> ToShmem for Locked<T> {
184 fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
185 use std::mem::ManuallyDrop;
186
187 let guard = self.shared_lock.read();
188 Ok(ManuallyDrop::new(Locked {
189 shared_lock: SharedRwLock::read_only(),
190 data: UnsafeCell::new(ManuallyDrop::into_inner(
191 self.read_with(&guard).to_shmem(builder)?,
192 )),
193 }))
194 }
195}
196
197#[allow(dead_code)]
198mod compile_time_assert {
199 use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
200
201 trait Marker1 {}
202 impl<T: Clone> Marker1 for T {}
203 impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} trait Marker2 {}
207 impl<T: Copy> Marker2 for T {}
208 impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} }
211
212pub trait ToCssWithGuard {
215 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result;
217
218 #[inline]
222 fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> CssString {
223 let mut s = CssString::new();
224 self.to_css(guard, &mut s).unwrap();
225 s
226 }
227}
228
229pub trait DeepCloneWithLock: Sized {
232 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self;
234}
235
236#[derive(Clone)]
238pub struct StylesheetGuards<'a> {
239 pub author: &'a SharedRwLockReadGuard<'a>,
241
242 pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
244}
245
246impl<'a> StylesheetGuards<'a> {
247 pub fn for_origin(&self, origin: Origin) -> &SharedRwLockReadGuard<'a> {
249 match origin {
250 Origin::Author => &self.author,
251 _ => &self.ua_or_user,
252 }
253 }
254
255 pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
257 StylesheetGuards {
258 author: guard,
259 ua_or_user: guard,
260 }
261 }
262}