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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
/// ! Cycle collecting reference counted pointers for Rust with a safe api.
/// !
/// ! This crate is most useful when you have a data structure with inter-dependent nodes of
/// ! arbitrary lifetimes and no clear parent-children relationships.
/// !
/// ! If you can be certain that the layout of your data will be acyclic, or [`std::rc::Weak`]
/// ! would be sufficient to prevent leaks, this type is probably not a good fit. If you know all
/// ! of your data will be dropped after a certain phase of your program completes, you will
/// ! probably prefer arena allocation through a crate like `typed-arena`, `generational-arena`,
/// ! etc.
/// !
/// ! # Basic Example
/// ! ```
/// ! # use std::cell::RefCell;
/// ! # use tracing_rc::rc::{
/// ! # collect_full,
/// ! # Gc,
/// ! # GcVisitor,
/// ! # Traceable,
/// ! # };
/// !
/// ! struct GraphNode<T: 'static> {
/// ! data: T,
/// ! edge: Option<Gc<RefCell<GraphNode<T>>>>,
/// ! }
/// !
/// ! impl<T> Traceable for GraphNode<T> {
/// ! fn visit_children(&self, visitor: &mut GcVisitor) {
/// ! self.edge.visit_children(visitor);
/// ! }
/// ! }
/// !
/// ! # fn main() {
/// ! {
/// ! let node_a = Gc::new(RefCell::new(GraphNode {
/// ! data: 10,
/// ! edge: None,
/// ! }));
/// ! let node_b = Gc::new(RefCell::new(GraphNode {
/// ! data: 11,
/// ! edge: None,
/// ! }));
/// ! let node_c = Gc::new(RefCell::new(GraphNode {
/// ! data: 12,
/// ! edge: Some(node_a.clone()),
/// ! }));
/// !
/// ! node_a.borrow_mut().edge = Some(node_b.clone());
/// ! node_b.borrow_mut().edge = Some(node_c);
/// !
/// ! let a = node_a.borrow();
/// ! let b = a.edge.as_ref().unwrap().borrow();
/// ! let c = b.edge.as_ref().unwrap().borrow();
/// !
/// ! assert_eq!(a.data, c.edge.as_ref().unwrap().borrow().data);
/// ! // all of the nodes go out of scope at this point and would normally be leaked.
/// ! }
/// !
/// ! // In this simple example, we always have cycles and our program is complete after this,
/// ! // so we can't take advantage of the young generation picking up acyclic pointers without
/// ! // tracing.
/// ! collect_full();
/// !
/// ! // All leaked nodes have been cleaned up!
/// ! # }
/// ! ```
pub mod rc;
/// Controls the style of collection carried out.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CollectionType {
/// Do a simple pass over the young gen, collecting non-cyclical pointers
/// and moving old pointers to the old gen. Then perform a cycle-tracing
/// collection over the old gen.
Default,
/// Only run collection for the young gen. This may still move pointers to the old gen if they
/// qualify based on CollectOptions::old_gen_threshold
YoungOnly,
}
impl Default for CollectionType {
fn default() -> Self {
Self::Default
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CollectOptions {
/// The number of times a pointer may be seen in the young gen before moving it to the old
/// gen for a full tracing collection. Setting this to zero will cause all pointers to move to
/// the old gen if they cannot be immediately cleaned up.
pub old_gen_threshold: usize,
// The kind of collection to perform, e.g. just the young gen, or full tracing of both old &
// young gen.
pub kind: CollectionType,
}
impl CollectOptions {
pub const DEFAULT: CollectOptions = CollectOptions {
old_gen_threshold: 5,
kind: CollectionType::Default,
};
pub const TRACE_AND_COLLECT_ALL: CollectOptions = Self::DEFAULT.set_old_gen_threshold(0);
pub const YOUNG_ONLY: CollectOptions = Self::DEFAULT.set_kind(CollectionType::YoungOnly);
pub const fn set_kind(self, kind: CollectionType) -> Self {
let Self {
old_gen_threshold,
kind: _,
} = self;
Self {
old_gen_threshold,
kind,
}
}
pub const fn set_old_gen_threshold(self, threshold: usize) -> Self {
let Self {
old_gen_threshold: _,
kind,
} = self;
Self {
old_gen_threshold: threshold,
kind,
}
}
}
impl Default for CollectOptions {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Status {
Live,
RecentlyDecremented,
Dead,
}