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
//! Deferred self weak reference implementation
//!
//! Using `RtValue<T>` allows for injection of a `WeakRc` back to the contained `RtValue<T>`
//! value after it has been boxed and moved into the `StrongRc` struct.
//!
use std::cell::RefCell;
use std::fmt::{Debug, Formatter, Result};
use std::ops::Deref;

use num::Zero;

use ::api::result::Error;
use ::api::{RtObject, WeakRtObject};
use ::api::result::ObjectResult;
use ::system::primitives as rs;



/// A trait that must be implemented on a refcount wrapper type
/// in order to provide the necessary behavior for a value to
/// contain a reference to itself.
///
/// One of the admittedly weak areas of rust is cyclic data structures because of the strong
/// lifetime guarantees. In order to get a self reference to work in a way that will ensure
/// that the type attached to the selfref is properly deallocated the following must be true:
///
/// 1. The stored reference must be weak so the strong count can go to 0 (see std::rc::Rc)
/// 2. The selfref can only be set after the containing structure is created and therefore
///    must be set after the struct is moved into the appropriate `Box` and `Rc` containers.
///    So the field must be
pub trait SelfRef: Sized {
    fn strong_count(&self) -> rs::Integer;
    fn weak_count(&self) -> rs::Integer;
    fn set(&self, &RtObject);
    fn get(&self) -> WeakRtObject;
    fn upgrade(&self) -> ObjectResult;
}


/// A wrapper around a value with its own reference count
/// in the runtime.
#[derive(Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct RefCountedValue<T, V: SelfRef> {
    pub value: T,
    pub rc: V,
}

/// RefCount struct that holds a mutable and optional weakref
/// this is so instances can have a reference to their own RefCount
///
pub struct RefCount(pub RefCell<Option<WeakRtObject>>);

impl Clone for RefCount {
    fn clone(&self) -> Self {
        match *self.0.borrow().deref() {
            Some(ref weak) => RefCount(RefCell::new(Some(weak.clone()))),
            None => RefCount(RefCell::new(None)),
        }
    }
}

impl SelfRef for RefCount {
    /// Unwrap the optional type and proxy to the underlying WeakRtObject if present
    /// otherwise return 0.
    fn strong_count(&self) -> rs::Integer {
        match *self.0.borrow().deref() {
            Some(ref weak) => weak.strong_count(),
            None => rs::Integer::zero(),
        }
    }

    /// Unwrap the optional type and proxy to the underlying WeakRtObject if present
    /// otherwise return 0.
    fn weak_count(&self) -> rs::Integer {
        let count: rs::Integer;
        // use a scope to ensure that the borrow is dropped
        {
            count = match *self.0.borrow().deref() {
                Some(ref weak) => weak.weak_count(),
                None => rs::Integer::zero(),
            }
        }

        count
    }

    /// Set the `SelfRef` from strong `RtObject` by cloning and downgrading that
    /// reference.
    fn set(&self, selfref: &RtObject) {
        let mut rc = self.0.borrow_mut();
        match *rc {
            None => *rc = Some(selfref.downgrade()),
            // TODO: {T97} Make this an error and not a panic
            _ => panic!("Tried to overwrite self reference"),
        }
    }

    /// Return a clone of of the backing `WeakRtObject`
    fn get(&self) -> WeakRtObject {
        match *self.0.borrow().deref() {
            Some(ref weak) => weak.clone(),
            // TODO: {T97} Make this an error and not a runtime panic
            None => panic!("Unable to retrieve unset weak object reference"),
        }
    }

    /// Take the `WeakRtObject` backing the `SelfRef` and attempt to upgrade it
    /// to its strong version `RtObject`.
    fn upgrade(&self) -> ObjectResult {
        match *self.0.borrow().deref() {
            Some(ref weak) => weak.clone().upgrade(),
            None => Err(Error::runtime("Cannot upgrade a None weakref!")),
        }
    }
}


/// Display the strong and weak reference counts
impl Debug for RefCount {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "RefCount(strong: {}, weak: {})", self.strong_count(), self.weak_count())
    }
}


/// Default to an inner cell value of None meaning that the selfref has not been set
impl Default for RefCount {
    fn default() -> Self {
        RefCount(RefCell::new(None))
    }
}