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
/// Callback function that serves as the parameter of
/// [`Trace::trace`](trait.Trace.html#method.trace).
pub type Tracer<'a> = dyn FnMut(*const ()) + 'a;
/// Defines how the cycle collector should collect a type.
///
/// ## Customized `Drop` implementation
///
/// The [`Drop`] implementation should avoid dereferencing other [`Cc<T>`]
/// objects. Failing to do so might cause panic or undefined behavior. For
/// example, `T1` has a field `Cc<T2>`. The collector might have already
/// dropped `T2` by the time `T1::drop` runs.
///
/// The [`Drop`] implementation should also be careful about cloning
/// (resurrecting) [`Cc<T>`] objects. If it must do so, the `trace`
/// implementation should match by avoiding visiting those cloned objects.
///
/// ## 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;
}
}