Skip to content

Commit 223f103

Browse files
kmcallisterRonakNisher
authored andcommitted
Customize RefCell instead of wrapping it
This gets rid of a dubious transmute: let val = mem::transmute::<&RefCell<T>, &T>(&self.base); The code duplication will be reduced once rust-lang/rust#18131 is fixed.
1 parent 14798ad commit 223f103

File tree

1 file changed

+108
-30
lines changed
  • components/script/dom/bindings

1 file changed

+108
-30
lines changed

components/script/dom/bindings/cell.rs

+108-30
Original file line numberDiff line numberDiff line change
@@ -5,64 +5,142 @@
55
use dom::bindings::trace::JSTraceable;
66
use js::jsapi::{JSTracer};
77

8-
use std::cell;
9-
use std::cell::RefCell;
10-
use std::mem;
11-
12-
/// A mutable field in DOM for large sized value.
13-
/// This has a special method to return the pointer of itself
14-
/// for used in layout task.
15-
/// This simply wraps `RefCell<T>` to add the special method.
8+
use std::cell::{Cell, UnsafeCell};
9+
use std::kinds::marker;
10+
11+
/// A mutable field in the DOM.
12+
///
13+
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
14+
/// certain situations.
1615
pub struct DOMRefCell<T> {
17-
base: RefCell<T>,
16+
value: UnsafeCell<T>,
17+
borrow: Cell<BorrowFlag>,
18+
nocopy: marker::NoCopy,
19+
nosync: marker::NoSync,
1820
}
1921

20-
pub type Ref<'a, T> = cell::Ref<'a, T>;
21-
pub type RefMut<'a, T> = cell::RefMut<'a, T>;
22+
// Functionality specific to Servo's `DOMRefCell` type
23+
// ===================================================
2224

25+
impl<T> DOMRefCell<T> {
26+
/// Return a reference to the contents.
27+
///
28+
/// For use in the layout task only.
29+
pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
30+
&*self.value.get()
31+
}
32+
}
33+
34+
impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
35+
fn trace(&self, trc: *mut JSTracer) {
36+
(*self).borrow().trace(trc)
37+
}
38+
}
39+
40+
// Functionality duplicated with `core::cell::RefCell`
41+
// ===================================================
42+
//
43+
// This can shrink once rust-lang/rust#18131 is fixed.
44+
45+
// Values [1, MAX-1] represent the number of `Ref` active
46+
// (will not outgrow its range since `uint` is the size of the address space)
47+
type BorrowFlag = uint;
48+
static UNUSED: BorrowFlag = 0;
49+
static WRITING: BorrowFlag = -1;
2350

2451
impl<T> DOMRefCell<T> {
25-
#[inline(always)]
2652
pub fn new(value: T) -> DOMRefCell<T> {
2753
DOMRefCell {
28-
base: RefCell::new(value),
54+
value: UnsafeCell::new(value),
55+
borrow: Cell::new(UNUSED),
56+
nocopy: marker::NoCopy,
57+
nosync: marker::NoSync,
2958
}
3059
}
3160

32-
#[inline(always)]
3361
pub fn unwrap(self) -> T {
34-
self.base.unwrap()
62+
debug_assert!(self.borrow.get() == UNUSED);
63+
unsafe{self.value.unwrap()}
3564
}
3665

37-
#[inline(always)]
3866
pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
39-
self.base.try_borrow()
67+
match self.borrow.get() {
68+
WRITING => None,
69+
borrow => {
70+
self.borrow.set(borrow + 1);
71+
Some(Ref { _parent: self })
72+
}
73+
}
4074
}
4175

42-
#[inline(always)]
4376
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
44-
self.base.borrow()
77+
match self.try_borrow() {
78+
Some(ptr) => ptr,
79+
None => fail!("DOMRefCell<T> already mutably borrowed")
80+
}
4581
}
4682

47-
#[inline(always)]
4883
pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
49-
self.base.try_borrow_mut()
84+
match self.borrow.get() {
85+
UNUSED => {
86+
self.borrow.set(WRITING);
87+
Some(RefMut { _parent: self })
88+
},
89+
_ => None
90+
}
5091
}
5192

52-
#[inline(always)]
5393
pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
54-
self.base.borrow_mut()
94+
match self.try_borrow_mut() {
95+
Some(ptr) => ptr,
96+
None => fail!("DOMRefCell<T> already borrowed")
97+
}
5598
}
99+
}
56100

57-
/// This returns the pointer which refers T in `RefCell<T>` directly.
58-
pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
59-
let val = mem::transmute::<&RefCell<T>, &T>(&self.base);
60-
val
101+
pub struct Ref<'b, T:'b> {
102+
_parent: &'b DOMRefCell<T>
103+
}
104+
105+
#[unsafe_destructor]
106+
impl<'b, T> Drop for Ref<'b, T> {
107+
fn drop(&mut self) {
108+
let borrow = self._parent.borrow.get();
109+
debug_assert!(borrow != WRITING && borrow != UNUSED);
110+
self._parent.borrow.set(borrow - 1);
61111
}
62112
}
63113

64-
impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
65-
fn trace(&self, trc: *mut JSTracer) {
66-
(*self).base.borrow().trace(trc)
114+
impl<'b, T> Deref<T> for Ref<'b, T> {
115+
#[inline]
116+
fn deref<'a>(&'a self) -> &'a T {
117+
unsafe { &*self._parent.value.get() }
118+
}
119+
}
120+
121+
pub struct RefMut<'b, T:'b> {
122+
_parent: &'b DOMRefCell<T>
123+
}
124+
125+
#[unsafe_destructor]
126+
impl<'b, T> Drop for RefMut<'b, T> {
127+
fn drop(&mut self) {
128+
let borrow = self._parent.borrow.get();
129+
debug_assert!(borrow == WRITING);
130+
self._parent.borrow.set(UNUSED);
131+
}
132+
}
133+
134+
impl<'b, T> Deref<T> for RefMut<'b, T> {
135+
#[inline]
136+
fn deref<'a>(&'a self) -> &'a T {
137+
unsafe { &*self._parent.value.get() }
138+
}
139+
}
140+
141+
impl<'b, T> DerefMut<T> for RefMut<'b, T> {
142+
#[inline]
143+
fn deref_mut<'a>(&'a mut self) -> &'a mut T {
144+
unsafe { &mut *self._parent.value.get() }
67145
}
68146
}

0 commit comments

Comments
 (0)