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 SharedRwLock {
45 pub fn new() -> Self {
47 SharedRwLock {
48 cell: Some(Arc::new(AtomicRefCell::new(SomethingZeroSizedButTyped))),
49 }
50 }
51
52 pub fn new_leaked() -> Self {
54 SharedRwLock {
55 cell: Some(Arc::new_leaked(AtomicRefCell::new(
56 SomethingZeroSizedButTyped,
57 ))),
58 }
59 }
60
61 pub fn read_only() -> Self {
63 SharedRwLock { cell: None }
64 }
65
66 #[inline]
67 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
68 self.cell
69 .as_ref()
70 .map(|cell| cell.as_ptr() as *const _)
71 .unwrap_or(ptr::null())
72 }
73
74 pub fn wrap<T>(&self, data: T) -> Locked<T> {
76 Locked {
77 shared_lock: self.clone(),
78 data: UnsafeCell::new(data),
79 }
80 }
81
82 pub fn read(&self) -> SharedRwLockReadGuard<'_> {
84 SharedRwLockReadGuard(self.cell.as_ref().map(|cell| cell.borrow()))
85 }
86
87 pub fn write(&self) -> SharedRwLockWriteGuard<'_> {
89 SharedRwLockWriteGuard(self.cell.as_ref().unwrap().borrow_mut())
90 }
91}
92
93pub struct SharedRwLockReadGuard<'a>(Option<AtomicRef<'a, SomethingZeroSizedButTyped>>);
95
96impl<'a> SharedRwLockReadGuard<'a> {
97 #[inline]
98 fn ptr(&self) -> *const SomethingZeroSizedButTyped {
99 self.0
100 .as_ref()
101 .map(|r| &**r as *const _)
102 .unwrap_or(ptr::null())
103 }
104}
105
106pub struct SharedRwLockWriteGuard<'a>(AtomicRefMut<'a, SomethingZeroSizedButTyped>);
108
109pub struct Locked<T> {
111 shared_lock: SharedRwLock,
112 data: UnsafeCell<T>,
113}
114
115unsafe impl<T: Send> Send for Locked<T> {}
118unsafe impl<T: Send + Sync> Sync for Locked<T> {}
119
120impl<T: fmt::Debug> fmt::Debug for Locked<T> {
121 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122 let guard = self.shared_lock.read();
123 self.read_with(&guard).fmt(f)
124 }
125}
126
127impl<T> Locked<T> {
128 #[inline]
129 fn is_read_only_lock(&self) -> bool {
130 self.shared_lock.cell.is_none()
131 }
132
133 fn same_lock_as(&self, ptr: *const SomethingZeroSizedButTyped) -> bool {
134 ptr::eq(self.shared_lock.ptr(), ptr)
135 }
136
137 pub fn read_with<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> &'a T {
139 assert!(
140 self.is_read_only_lock() || self.same_lock_as(guard.ptr()),
141 "Locked::read_with called with a guard from an unrelated SharedRwLock: {:?} vs. {:?}",
142 self.shared_lock.ptr(),
143 guard.ptr(),
144 );
145
146 let ptr = self.data.get();
147
148 unsafe { &*ptr }
155 }
156
157 pub unsafe fn read_unchecked<'a>(&'a self) -> &'a T {
159 let ptr = self.data.get();
160 &*ptr
161 }
162
163 pub fn write_with<'a>(&'a self, guard: &'a mut SharedRwLockWriteGuard) -> &'a mut T {
165 assert!(
166 !self.is_read_only_lock() && self.same_lock_as(&*guard.0),
167 "Locked::write_with called with a guard from a read only or unrelated SharedRwLock"
168 );
169
170 let ptr = self.data.get();
171
172 unsafe { &mut *ptr }
181 }
182}
183
184impl<T: ToShmem> ToShmem for Locked<T> {
185 fn to_shmem(&self, builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
186 use std::mem::ManuallyDrop;
187
188 let guard = self.shared_lock.read();
189 Ok(ManuallyDrop::new(Locked {
190 shared_lock: SharedRwLock::read_only(),
191 data: UnsafeCell::new(ManuallyDrop::into_inner(
192 self.read_with(&guard).to_shmem(builder)?,
193 )),
194 }))
195 }
196}
197
198#[allow(dead_code)]
199mod compile_time_assert {
200 use super::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
201
202 trait Marker1 {}
203 impl<T: Clone> Marker1 for T {}
204 impl<'a> Marker1 for SharedRwLockReadGuard<'a> {} impl<'a> Marker1 for SharedRwLockWriteGuard<'a> {} trait Marker2 {}
208 impl<T: Copy> Marker2 for T {}
209 impl<'a> Marker2 for SharedRwLockReadGuard<'a> {} impl<'a> Marker2 for SharedRwLockWriteGuard<'a> {} }
212
213pub trait ToCssWithGuard {
216 fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result;
218
219 #[inline]
223 fn to_css_string(&self, guard: &SharedRwLockReadGuard) -> CssString {
224 let mut s = CssString::new();
225 self.to_css(guard, &mut s).unwrap();
226 s
227 }
228}
229
230pub trait DeepCloneWithLock: Sized {
233 fn deep_clone_with_lock(&self, lock: &SharedRwLock, guard: &SharedRwLockReadGuard) -> Self;
235}
236
237#[derive(Clone)]
239pub struct StylesheetGuards<'a> {
240 pub author: &'a SharedRwLockReadGuard<'a>,
242
243 pub ua_or_user: &'a SharedRwLockReadGuard<'a>,
245}
246
247impl<'a> StylesheetGuards<'a> {
248 pub fn for_origin(&self, origin: Origin) -> &SharedRwLockReadGuard<'a> {
250 match origin {
251 Origin::Author => &self.author,
252 _ => &self.ua_or_user,
253 }
254 }
255
256 pub fn same(guard: &'a SharedRwLockReadGuard<'a>) -> Self {
258 StylesheetGuards {
259 author: guard,
260 ua_or_user: guard,
261 }
262 }
263}