1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A shareable mutable container for the DOM.
use dom::bindings::trace::JSTraceable;
use js::jsapi::{JSTracer};
use servo_util::task_state;
use servo_util::task_state::{SCRIPT, IN_GC};
use std::cell::{RefCell, Ref, RefMut};
/// A mutable field in the DOM.
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
pub struct DOMRefCell<T> {
value: RefCell<T>,
}
// Functionality specific to Servo's `DOMRefCell` type
// ===================================================
impl<T> DOMRefCell<T> {
/// Return a reference to the contents.
///
/// For use in the layout task only.
pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
debug_assert!(task_state::get().is_layout());
&*self.value.as_unsafe_cell().get()
}
/// Borrow the contents for the purpose of GC tracing.
///
/// This succeeds even if the object is mutably borrowed,
/// so you have to be careful in trace code!
pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T {
debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
&*self.value.as_unsafe_cell().get()
}
/// Is the cell mutably borrowed?
///
/// For safety checks in debug builds only.
pub fn is_mutably_borrowed(&self) -> bool {
self.value.try_borrow().is_some()
}
/// Attempts to immutably borrow the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
/// immutable borrows can be taken out at the same time.
///
/// Returns `None` if the value is currently mutably borrowed.
///
/// # Panics
///
/// Panics if this is called off the script thread.
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
debug_assert!(task_state::get().is_script());
self.value.try_borrow()
}
/// Mutably borrows the wrapped value.
///
/// The borrow lasts until the returned `RefMut` exits scope. The value
/// cannot be borrowed while this borrow is active.
///
/// Returns `None` if the value is currently borrowed.
///
/// # Panics
///
/// Panics if this is called off the script thread.
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
debug_assert!(task_state::get().is_script());
self.value.try_borrow_mut()
}
}
impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
fn trace(&self, trc: *mut JSTracer) {
(*self).borrow().trace(trc)
}
}
// Functionality duplicated with `core::cell::RefCell`
// ===================================================
impl<T> DOMRefCell<T> {
/// Create a new `DOMRefCell` containing `value`.
pub fn new(value: T) -> DOMRefCell<T> {
DOMRefCell {
value: RefCell::new(value),
}
}
/// Immutably borrows the wrapped value.
///
/// The borrow lasts until the returned `Ref` exits scope. Multiple
/// immutable borrows can be taken out at the same time.
///
/// # Panics
///
/// Panics if this is called off the script thread.
///
/// Panics if the value is currently mutably borrowed.
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
match self.try_borrow() {
Some(ptr) => ptr,
None => panic!("DOMRefCell<T> already mutably borrowed")
}
}
/// Mutably borrows the wrapped value.
///
/// The borrow lasts until the returned `RefMut` exits scope. The value
/// cannot be borrowed while this borrow is active.
///
/// # Panics
///
/// Panics if this is called off the script thread.
///
/// Panics if the value is currently borrowed.
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
match self.try_borrow_mut() {
Some(ptr) => ptr,
None => panic!("DOMRefCell<T> already borrowed")
}
}
}
|