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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! A concurrent, generational, trace and sweep garbage collected arena.
//!
//! ## Creating An Arena
//!
//! All garbage collection in Sandpit happens within an arena. Therefore, to
//! be begin we can start with creating a new arena.
//!
//! This can be done like so..
//! ```rust
//! use sandpit::{Arena, Root};
//! # use sandpit::{Trace, Mutator};
//! # #[derive(Trace)]
//! # struct MyRoot;
//! # impl MyRoot {
//! # fn new(mutator: &Mutator) -> Self { Self }
//! # }
//!
//! // This creates an arena with a `MyRoot` as the root.
//! let gc: Arena<Root![MyRoot]> = Arena::new(|mutator| {
//! MyRoot::new(mutator)
//! });
//! ```
//! There are two big things to unpack here:
//! * An `Arena` is generic on its single Root value which it holds.
//! * The Root of an `Arena` must be a Higher Kinded Type(HKT).
//!
//! This is explained in much further depth in [`sandpit::Arena`].
//!
//! ## Trace Trait
//! For a type to be GC'ed it is required to impl [`Trace`]
//! which can be safely derived as long as all inner types also impl [`Trace`].
//!
//! ```rust
//! use sandpit::{Trace, Gc, GcOpt};
//! # #[derive(Trace)]
//! # struct A;
//! # #[derive(Trace)]
//! # struct B;
//!
//! #[derive(Trace)]
//! enum Value<'gc> {
//! // GC values must be branded with a mutation lifetime
//! // to ensure freeing memory can happen safely.
//! A(Gc<'gc, A>), // Mutable pointer to a garbage collected value
//! B(GcOpt<'gc, B>), // Optionally null pointer that is also mutable. Can be unwrapped into a Gc.
//! }
//! // All inner values must be trace, therefore types A and B must impl Trace as well.
//! ```
//! Essentially when a value is traced the tracer will mark the value as live,
//! and call trace on all its inner pointers to GC values.
//!
//! There are 2 types of GC pointers:
//! * [`gc::Gc`]
//! * [`gc::GcOpt`]
//!
//! A type may also derive [`TraceLeaf`], if it contains no GC pointers.
//! [`TraceLeaf`] allows for easier interior mutability.
//!
//! ## Mutating the Arena
//! Once you have your arena and your traceable types, you can begin allocating
//! them in the arena by calling [`Arena::mutate`]. Within a mutation
//! we can essentially do 3 important things:
//! * Access all data reaachable from the root.
//! * Create new garbage collected values.
//! * Update Gc pointers to point to new values via a [`WriteBarrier`].
//! ```rust
//! use sandpit::{Trace, Gc};
//!
//! # use sandpit::{Arena, Root, Mutator, WriteBarrier};
//! # let arena: Arena<Root![Gc<'_, usize>]> = Arena::new(|mutator| {
//! # Gc::new(mutator, 0usize)
//! # });
//! # fn traverse(root: &usize) {}
//! arena.mutate(|mutator, root| {
//! // We can access everything reachable from the root.
//! traverse(root);
//!
//! // We can allocate new Gc values.
//! // Here is a pointer, to a pointer, to a bool!
//! let gc_mut = Gc::new(mutator,
//! Gc::new(mutator, true)
//! );
//!
//! // We can mutate existing inner Gc and GcOpt pointers.
//! gc_mut.write_barrier(mutator, |barrier| {
//! barrier.set(Gc::new(mutator, false));
//! })
//! });
//! ```
//!
//! ## Collection and Yielding
//!
//! In order for the Gc to free memory, and do so safely, all mutations must
//! exit. Therefore, if a mutation involves a continuous loop of instructions,
//! it must exit it's mutation every so often to allow the GC to free memory.
//!
//! The mutator exposes a signal([`Mutator::gc_yield`]) which indicates if it is ready to free memory,
//! and that the mutation should end.
//!
//! ```rust
//! # use sandpit::{Arena, Root, Mutator, WriteBarrier, Gc};
//! # let arena: Arena<Root![Gc<'_, usize>]> = Arena::new(|mutator| {
//! # Gc::new(mutator, 0usize)
//! # });
//! # fn allocate_stuff(mutator: &Mutator, root: &usize) {
//! # for i in 0..100 {
//! # Gc::new(mutator, 0);
//! # }
//! # }
//! arena.mutate(|mutator, root| loop {
//! // during this function it is likely the the GC will concurrently begin tracing!
//! allocate_stuff(mutator, root);
//!
//! if mutator.gc_yield() {
//! // the mutator is signaling to us that memory is ready to be freed so we should leave the mutation context
//! break;
//! } else {
//! // if the mutator isn't signaling for us to yield then we
//! // are fine to go on allocating more garbage
//! }
//! });
//! ```
//!
//! ***WARNING:*** If a mutation continously runs without occasionally checking
//! the yield signal, memory cannot be freed!
//!
extern crate alloc;
extern crate self as sandpit;
/// Re-exported from ForLt. Used in making the root of an arena.
pub use ForLt as Root;
pub use Arena;
pub use ;
pub use Config;
pub use ;
pub use GcSync;
pub use Metrics;
pub use Mutator;
pub use ;
pub use ;
pub use ;
pub use GcVec;
pub use ;