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
use crate::cc::GcHeader;
use std::any::Any;

/// Callback function that serves as the parameter of
/// [`Trace::trace`](trait.Trace.html#method.trace).
pub type Tracer<'a> = dyn FnMut(&GcHeader) + 'a;

/// Defines how the cycle collector should collect a type.
///
/// ## The `'static` bound
///
/// Types tracked by the collector can potentially be kept alive forever.
/// Therefore types with non-static references are not allowed.
pub trait Trace: 'static {
    /// Define how to visit values referred by this value.
    ///
    /// For example, if `self.x` is a value referred by `self`,
    /// call `self.x.trace(tracer)` to visit it.
    ///
    /// The values that are visited must match the `Drop::drop`
    /// implementation. Otherwise memory leak or panic might
    /// happen. After the panic, dereferencing already collected
    /// `Cc<T>` can trigger:
    /// - Undefined behavior on release build.
    /// - Another panic on debug build.
    ///
    /// Ideally this can be generated by the compiler, since the
    /// compiler already knows how to generate `Drop::drop`.
    fn trace(&self, tracer: &mut Tracer) {
        let _ = tracer;
    }

    /// Whether this type should be tracked by the collector.
    ///
    /// Types that might include `Cc<T>` where `T` can form a cycle should
    /// be tracked. This allows the collector to visit the `Cc` values from
    /// its parents and count references correctly.
    ///
    /// If a type `T` is tracked, `Cc<T>` will be 3 `usize` larger and the
    /// collector will check them.
    ///
    /// For example,
    ///
    /// - `Vec<u8>` is not tracked. It does include any kind of `Cc<T>`.
    /// - `Box<Cc<u8>>` is not tracked. It includes `Cc<u8>` but `u8` cannot
    ///   create cycles.
    /// - `Box<dyn Trace>` is tracked. The trait object can be anything,
    ///   including any kinds of types that contains a `Cc<T>`.
    ///
    /// Usually, concrete Rust types can opt-out the cycle collector.
    /// There are a few exceptions:
    ///
    /// - Trait objects, and types containing trait objects. Trait objects
    ///   can be anything so they should be tracked.
    /// - Recursive types. Such as, `struct S(RefCell<Option<Rc<Box<S>>>>)`.
    ///   Those types need an explicit name like `S`, and a manual
    ///   implementation of the [`Trace`](trait.Trace.html) trait.
    ///   That implementation should make `is_type_tracked` return `true`
    ///   directly.
    ///
    /// This is an optimization for performance. When in-doubt, return `true`
    /// for correctness.
    fn is_type_tracked() -> bool
    where
        Self: Sized,
    {
        // Fallback implementation: Opt-in the collector for correctness.
        return true;
    }

    /// Provide downcast support.
    ///
    /// Types that want downcast support should implement this method like:
    /// `fn as_any(&self) -> Option<&dyn std::any::Any> { Some(self) }`
    fn as_any(&self) -> Option<&dyn Any> {
        None
    }
}