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
pub(crate) mod collect;
mod ref_count;

#[cfg(test)]
mod tests;

use crate::cc::RawCc;
use crate::ref_count::RefCount;
use crate::Trace;
use crate::Tracer;
use collect::ThreadedObjectSpace;
use parking_lot::lock_api::RwLockReadGuard;
use parking_lot::RawRwLock;
use std::marker::PhantomData;
use std::ops::Deref;

/// A multi-thread reference-counting pointer that integrates with cyclic
/// garbage collection.
///
/// [`ThreadedCc`](type.ThreadedCc.html) is similar to [`Cc`](type.Cc.html).
/// It works with multi-thread but is significantly slower than
/// [`Cc`](type.Cc.html).
///
/// To construct a [`ThreadedCc`](type.ThreadedCc.html), use
/// [`ThreadedObjectSpace::create`](struct.ThreadedObjectSpace.html#method.create).
pub type ThreadedCc<T> = RawCc<T, ThreadedObjectSpace>;

/// Wraps a borrowed reference to [`ThreadedCc`](type.ThreadedCc.html).
///
/// The wrapper automatically takes a lock that prevents the collector from
/// running. This ensures that when the collector is running, there are no
/// borrowed references of [`ThreadedCc`](type.ThreadedCc.html). Therefore
/// [`ThreadedCc`](type.ThreadedCc.html)s can be seen as temporarily immutable,
/// even if they might have interior mutability. The collector relies on this
/// for correctness.
pub struct ThreadedCcRef<'a, T: ?Sized> {
    // Prevent the collector from running when a reference is present.
    locked: RwLockReadGuard<'a, RawRwLock, ()>,

    // Provide access to the parent `Acc`.
    parent: &'a ThreadedCc<T>,

    // !Send + !Sync.
    _phantom: PhantomData<*mut ()>,
}

// safety: similar to `std::sync::Arc`
unsafe impl<T: Send + Sync> Send for ThreadedCc<T> {}
unsafe impl<T: Send + Sync> Sync for ThreadedCc<T> {}

impl<T: ?Sized> ThreadedCc<T> {
    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned value exits scope.
    pub fn borrow(&self) -> ThreadedCcRef<'_, T> {
        ThreadedCcRef {
            locked: self.inner().ref_count.locked().unwrap(),
            parent: self,
            _phantom: PhantomData,
        }
    }
}

impl<'a, T: ?Sized> Deref for ThreadedCcRef<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        let _ = &self.locked;
        self.parent.inner().deref()
    }
}

impl<T: Trace> Trace for ThreadedCc<T> {
    fn trace(&self, tracer: &mut Tracer) {
        self.inner().trace_t(tracer)
    }

    #[inline]
    fn is_type_tracked() -> bool {
        T::is_type_tracked()
    }
}

impl Trace for ThreadedCc<dyn Trace> {
    fn trace(&self, tracer: &mut Tracer) {
        self.inner().trace_t(tracer)
    }

    #[inline]
    fn is_type_tracked() -> bool {
        // Trait objects can be anything.
        true
    }
}

impl Trace for ThreadedCc<dyn Trace + Send> {
    fn trace(&self, tracer: &mut Tracer) {
        self.inner().trace_t(tracer)
    }

    #[inline]
    fn is_type_tracked() -> bool {
        // Trait objects can be anything.
        true
    }
}

impl Trace for ThreadedCc<dyn Trace + Send + Sync> {
    fn trace(&self, tracer: &mut Tracer) {
        self.inner().trace_t(tracer)
    }

    #[inline]
    fn is_type_tracked() -> bool {
        // Trait objects can be anything.
        true
    }
}