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}