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
use crate::context::CollectionContext;

/// A trait for garbage collected objects that can be placed into `Gc` pointers.  This trait is
/// unsafe, because `Gc` pointers inside an Arena are assumed never to be dangling, and in order to
/// ensure this certain rules must be followed:
///
///   1. `Collect::trace` *must* trace over *every* `Gc` pointer held inside this type, and cannot
///      fail.
///   2. Held `Gc` pointers must not be accessed inside `Drop::drop` since during drop any such
///      pointer may be dangling.
///   3. Internal mutability *must* not be used to adopt new `Gc` pointers without calling
///      `Gc::write_barrier` during the same arena mutation.
///
/// It is, however, possible to implement this trait safely by procedurally deriving it, which
/// requires that every field in the structure also implement `Collect`, and implements a safe,
/// empty version of `Drop`.  Internally mutable types like `Cell` and `RefCell` do not implement
/// `Collect` in such a way that it is possible to store `Gc` pointers inside them, so the write
/// barrier requirement cannot be broken when procedurally deriving `Collect`.  A safe way of
/// providing internal mutability in this case is to use `GcCell`, which provides internal
/// mutability while ensuring that the write barrier is always executed.
pub unsafe trait Collect {
    /// As an optimization, if this type can never hold a `Gc` pointer and `trace` is unnecessary to
    /// call, you may implement this method and return false.  The default implementation returns
    /// true, signaling that `Collect::trace` must be called.
    #[inline]
    fn needs_trace() -> bool
    where
        Self: Sized,
    {
        true
    }

    /// *Must* call `Collect::trace` on all held `Gc` pointers.  If this type holds inner types that
    /// implement `Collect`, a valid implementation would simply call `Collect::trace` on all the
    /// held values to ensure this.
    #[inline]
    fn trace(&self, _cc: CollectionContext) {}
}