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 } }