Skip to main content

jrsonnet_gcmodule/
trace.rs

1/// Callback function that serves as the parameter of
2/// [`Trace::trace`](trait.Trace.html#method.trace).
3pub type Tracer<'a> = dyn FnMut(*const ()) + 'a;
4
5/// Defines how the cycle collector should collect a type.
6///
7/// ## Customized `Drop` implementation
8///
9/// The [`Drop`] implementation should avoid dereferencing other [`Cc<T>`]
10/// objects.  Failing to do so might cause panic or undefined behavior. For
11/// example, `T1` has a field `Cc<T2>`. The collector might have already
12/// dropped `T2` by the time `T1::drop` runs.
13///
14/// The [`Drop`] implementation should also be careful about cloning
15/// (resurrecting) [`Cc<T>`] objects. If it must do so, the `trace`
16/// implementation should match by avoiding visiting those cloned objects.
17///
18/// ## The `'static` bound
19///
20/// Types tracked by the collector can potentially be kept alive forever.
21/// Therefore types with non-static references are not allowed.
22pub trait Trace: 'static {
23    /// Define how to visit values referred by this value.
24    ///
25    /// For example, if `self.x` is a value referred by `self`,
26    /// call `self.x.trace(tracer)` to visit it.
27    ///
28    /// The values that are visited must match the `Drop::drop`
29    /// implementation. Otherwise memory leak or panic might
30    /// happen. After the panic, dereferencing already collected
31    /// `Cc<T>` can trigger:
32    /// - Undefined behavior on release build.
33    /// - Another panic on debug build.
34    ///
35    /// Ideally this can be generated by the compiler, since the
36    /// compiler already knows how to generate `Drop::drop`.
37    fn trace(&self, tracer: &mut Tracer) {
38        let _ = tracer;
39    }
40
41    /// Whether this type should be tracked by the collector.
42    ///
43    /// Types that might include `Cc<T>` where `T` can form a cycle should
44    /// be tracked. This allows the collector to visit the `Cc` values from
45    /// its parents and count references correctly.
46    ///
47    /// If a type `T` is tracked, `Cc<T>` will be 3 `usize` larger and the
48    /// collector will check them.
49    ///
50    /// For example,
51    ///
52    /// - `Vec<u8>` is not tracked. It does include any kind of `Cc<T>`.
53    /// - `Box<Cc<u8>>` is not tracked. It includes `Cc<u8>` but `u8` cannot
54    ///   create cycles.
55    /// - `Box<dyn Trace>` is tracked. The trait object can be anything,
56    ///   including any kinds of types that contains a `Cc<T>`.
57    ///
58    /// Usually, concrete Rust types can opt-out the cycle collector.
59    /// There are a few exceptions:
60    ///
61    /// - Trait objects, and types containing trait objects. Trait objects
62    ///   can be anything so they should be tracked.
63    /// - Recursive types. Such as, `struct S(RefCell<Option<Rc<Box<S>>>>)`.
64    ///   Those types need an explicit name like `S`, and a manual
65    ///   implementation of the [`Trace`](trait.Trace.html) trait.
66    ///   That implementation should make `is_type_tracked` return `true`
67    ///   directly.
68    ///
69    /// This is an optimization for performance. When in-doubt, return `true`
70    /// for correctness.
71    fn is_type_tracked() -> bool
72    where
73        Self: Sized,
74    {
75        // Fallback implementation: Opt-in the collector for correctness.
76        true
77    }
78}
79
80/// Type-level assertion for `Trace::is_type_tracked`
81///
82/// `is_type_tracked` is only allowed to return false for types which implement Acyclic trait.
83///
84/// # Safety
85///
86/// `Acyclic` struct might not contain cycles which should be collected
87pub unsafe trait Acyclic: Trace {
88    // This method is used by `derive(Acyclic)` macro to assert that every field
89    // of a type implements Acyclic itself.
90    #[doc(hidden)]
91    #[inline]
92    fn assert_fields_are_acyclic(&self) {}
93}