1use ::std::cell::{Cell, Ref, RefCell, RefMut};
2use ::std::ops::{Deref, DerefMut};
3use super::trace::Trace;
4
5#[derive(Debug)]
7pub struct GcRefCell<T: Trace> {
8 rooted: Cell<bool>,
9 ref_cell: RefCell<T>,
10}
11
12impl<T: Trace> GcRefCell<T> {
13 pub fn new(value: T) -> GcRefCell<T> {
14 GcRefCell {
15 rooted: Cell::new(true),
16 ref_cell: RefCell::new(value),
17 }
18 }
19
20 pub fn borrow(&self) -> GcRef<T> {
21 GcRef { _ref: self.ref_cell.borrow() }
22 }
23
24 pub fn borrow_mut(&self) -> GcRefMut<T> {
25 if !self.rooted.get() {
28 unsafe { self.ref_cell.borrow().root(); }
29 }
30 GcRefMut { rooted: &self.rooted, _ref: self.ref_cell.borrow_mut() }
31 }
32}
33
34unsafe impl<T: Trace> Trace for GcRefCell<T> {
35 unsafe fn mark(&self) {
36 match self.ref_cell.try_borrow() {
39 Ok(ref value) => value.mark(),
40 Err(_) => (),
41 }
42 }
43
44 unsafe fn root(&self) {
45 assert!(!self.rooted.get());
46 self.rooted.set(true);
47 match self.ref_cell.try_borrow() {
48 Ok(ref value) => value.root(),
49 Err(_) => (),
50 }
51 }
52
53 unsafe fn unroot(&self) {
54 assert!(self.rooted.get());
55 self.rooted.set(false);
56 match self.ref_cell.try_borrow() {
57 Ok(ref value) => value.unroot(),
58 Err(_) => (),
59 }
60 }
61}
62
63pub struct GcRef<'a, T: Trace + 'a> {
64 _ref: Ref<'a, T>,
65}
66
67impl<'a, T: Trace + 'a> Deref for GcRef<'a, T> {
68 type Target = T;
69
70 fn deref(&self) -> &T {
71 self._ref.deref()
72 }
73}
74
75pub struct GcRefMut<'a, T: Trace + 'a> {
76 rooted: &'a Cell<bool>,
77 _ref: RefMut<'a, T>,
78}
79
80impl<'a, T: Trace + 'a> Deref for GcRefMut<'a, T> {
81 type Target = T;
82
83 fn deref(&self) -> &T {
84 self._ref.deref()
85 }
86}
87
88impl<'a, T: Trace + 'a> DerefMut for GcRefMut<'a, T> {
89 fn deref_mut(&mut self) -> &mut T {
90 self._ref.deref_mut()
91 }
92}
93
94impl<'a, T: Trace + 'a> Drop for GcRefMut<'a, T> {
95 fn drop(&mut self) {
96 if !self.rooted.get() {
98 unsafe { self._ref.unroot(); }
99 }
100 }
101}