1use crate::derives::MallocSizeOf;
8use crate::stylesheets::Origin;
9use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
10use servo_arc::Arc;
11use std::cell::UnsafeCell;
12use std::fmt;
13use std::ptr;
14use style_traits::{CssString, CssStringWriter};
15use to_shmem::{SharedMemoryBuilder, ToShmem};
16
17#[derive(Clone)]
28pub struct SharedRwLock {
29 cell: Option<Arc<AtomicRefCell<SomethingZeroSizedButTyped>>>,
30}
31
32#[cfg(feature = "servo")]
33malloc_size_of::malloc_size_of_is_0!(SharedRwLock);
34
35#[derive(MallocSizeOf)]
36struct SomethingZeroSizedButTyped;
37
38impl fmt::Debug for SharedRwLock {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 f.write_str("SharedRwLock")
41 }
42}
43
44impl Default for SharedRwLock {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl SharedRwLock {
51 pub fn new() -> Self {
53 SharedRwLock {
54 cell: Some(Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))),
55 }
56 }
57
58 pub fn new_leaked() -> Self {
60 SharedRwLock {
61 cell: Some(Arc::new_leaked(AtomicRefCell::new(
62 SomethingZeroSizedButTyped,
63 ))),
64 }
65 }
66
67 pub fn read_only() -> Self {
69 SharedRwLock { cell: None }
70 }
71
72 #[inline]
73 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
74 self.cell
75 .as_ref()
76 .map(|cell| cell.as_ptr() as *const _)
77 .unwrap_or(ptr::null())
78 }
79
80 pub fn wrap<T>(&self, data: T) -> Locked<T> {
82 Locked {
83 shared_lock: self.clone(),
84 data: UnsafeCell::new(data),
85 }
86 }
87
88 pub fn read(&self) -> SharedRwLockReadGuard<'_> {
90 SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
91 }
92
93 pub fn write(&self) -> SharedRwLockWriteGuard<'_> {
95 SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut())
96 }
97}
98
99pub struct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>);
101
102impl<'a> SharedRwLockReadGuard<'a> {
103 #[inline]
104 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
105 self.0
106 .as_ref()
107 .map(|r| &**r as *const _)
108 .unwrap_or(ptr::null())
109 }
110}
111
112pub struct SharedRwLockWriteGuard<'a>(AtomicRefMut<'a, SomethingZeroSizedButTyped>);
114
115pub struct Locked<T> {
117 shared_lock: SharedRwLock,
118 data: UnsafeCell<T>,
119}
120
121unsafe impl<T: Send> Send for Locked<T> {}
124unsafe impl<T: Send + Sync> Sync for Locked<T> {}
125
126impl<T: fmt::Debug> fmt::Debug for Locked<T> {
127 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128 let guard = self.shared_lock.read();
129 self.read_with(&guard).fmt(f)
130 }
131}
132
133impl<T> Locked<T> {
134 #[inline]
135 fn is_read_only_lock(&self) -> bool {
136 self.shared_lock.cell.is_none()
137 }
138
139 fn same_lock_as(&self, ptr: *const SomethingZeroSizedButTyped) -> bool {
140 ptr::eq(self.shared_lock.ptr(), ptr)
141 }
142
143 pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
145 assert!(
146 self.is_read_only_lock() || self.same_lock_as(guard.ptr()),
147 "Locked::read_with called with a guard from an unrelated SharedRwLock: {:?} vs. {:?}",
148 self.shared_lock.ptr(),
149 guard.ptr(),
150 );
151
152 let ptr = self.data.get();
153
154 unsafe { &*ptr }
161 }
162
163 pub unsafe fn read_unchecked(&self) -> &T {
165 unsafe {
166 let ptr = self.data.get();
167 &*ptr
168 }
169 }
170
171 pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
173 assert!(
174 !self.is_read_only_lock() && self.same_lock_as(&*guard.0),
175 "Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
176 );
177
178 let ptr = self.data.get();
179
180 unsafe { &mut *ptr }
189 }
190}
191
192impl<T: ToShmem> ToShmem for Locked<T> {
193 fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
194 use std::mem::ManuallyDrop;
195
196 let guard = self.shared_lock.read();
197 Ok(ManuallyDrop::new(Locked {
198 shared_lock: SharedRwLock::read_only(),
199 data: UnsafeCell::new(ManuallyDrop::into_inner(
200 self.read_with(&guard).to_shmem(builder)?,
201 )),
202 }))
203 }
204}
205
206#[allow(dead_code)]
207mod compile_time_assert {
208 use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
209
210 trait Marker1 {}
211 impl<T: Clone> Marker1 for T {}
212 impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} trait Marker2 {}
216 impl<T: Copy> Marker2 for T {}
217 impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} }
220
221pub trait ToCssWithGuard {
224 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result;
226
227 #[inline]
231 fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> CssString {
232 let mut s = CssString::new();
233 self.to_css(guard, &mut s).unwrap();
234 s
235 }
236}
237
238pub trait DeepCloneWithLock: Sized {
241 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self;
243}
244
245#[derive(Clone)]
247pub struct StylesheetGuards<'a> {
248 pub author: &'a SharedRwLockReadGuard<'a>,
250
251 pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
253}
254
255impl<'a> StylesheetGuards<'a> {
256 pub fn for_origin(&self, origin: Origin) -> &SharedRwLockReadGuard<'a> {
258 match origin {
259 Origin::Author => self.author,
260 _ => self.ua_or_user,
261 }
262 }
263
264 pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
266 StylesheetGuards {
267 author: guard,
268 ua_or_user: guard,
269 }
270 }
271}