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}