cell_gc/lib.rs
1//! A simple garbage collector for use in Rust.
2//!
3//! The goal is to help you quickly build a VM in Rust.
4//! So this GC is designed for:
5//!
6//! * Safety
7//!
8//! * No dependency on linters or compiler plugins
9//!
10//! * An API that's consistent with a high-performance implementation
11//! (though right now cell-gc is not speedy)
12//!
13//! * Fun
14//!
15//!
16//! # Caveats
17//!
18//! **cell-gc is for use in VMs.** So the assumption is that the data the GC is
19//! managing is not really *your* data; it's your end user's data. If you don't
20//! want every field of every GC-managed object to be public and mutable, cell-gc
21//! is not the GC for your project!
22//!
23//! **The API is completely unstable.** I promise I will change it in ways
24//! that will break code; you'll just have to keep up until things stabilize.
25//!
26//! cell-gc is not designed to support multithread access to a single heap (like Java).
27//! Instead, you can create one heap per thread (like JavaScript).
28//!
29//! Currently it does not support lots of small heaps with random lifetimes (like Erlang),
30//! but I have some ideas on how to get there.
31//! [See issue #7.](https://github.com/jorendorff/rust-toy-gc/issues/7)
32//!
33//!
34//! # How to use it
35//!
36//! There are two parts to using `cell_gc`: GC types and GC heaps.
37//!
38//! ## Declaring GC types
39//!
40//! Declaring GC types is actually super easy. Just add `#[derive(IntoHeap)]`
41//! to any struct:
42//!
43//! ```rust
44//! extern crate cell_gc;
45//! #[macro_use] extern crate cell_gc_derive;
46//!
47//! /// A linked list of numbers that lives in the GC heap.
48//! /// The `#[derive(IntoHeap)]` here causes Rust to define an additional
49//! /// type, `IntListRef`.
50//! #[derive(IntoHeap)]
51//! struct IntList<'h> {
52//! head: i64,
53//! tail: Option<IntListRef<'h>>
54//! }
55//! # fn main(){}
56//! ```
57//!
58//! `cell_gc` does several things:
59//!
60//! * Behind the scenes, it generates some code used for garbage collection,
61//! such as marking code. You never need to worry about that stuff.
62//!
63//! * It checks that `IntList`'s fields are all GC-safe.
64//!
65//! Not every type is safe to use as a field of a heap struct or enum.
66//! Here are the allowed field types:
67//!
68//! * primitive types, like `i32`
69//! * types declared with `#[derive(IntoHeap)]`, like `IntList<'h>` and `IntListRef<'h>`
70//! * `Box<T>` where `T` has `'static` lifetime
71//! * `Rc<T>` where `T` has `'static` lifetime
72//! * `Option<T>` where `T` is any of these types
73//!
74//! If you try to use anything else, you'll get bizarre error messages
75//! from `rustc`.
76//!
77//! * It declare a `Ref` type for you, in this case `IntListRef`.
78//! `cell_gc` names this type by gluing `Ref` to the end of the struct
79//! name. `IntListRef` is a smart pointer to a GC-managed `IntList`. You
80//! need this because `cell_gc` doesn't let you have normal Rust references
81//! to stuff in the GC heap.
82//!
83//! `IntListRef` values keep in-heap `IntList` values alive; once the last
84//! `IntListRef` pointing at an object is gone, it becomes available for
85//! garbage collection, and eventually it'll be recycled.
86//!
87//! `IntListRef` is like `std::rc::Rc`: it's `Clone` but not `Copy`, and
88//! calling `.clone()` copies the Ref, not the object it points to.
89//!
90//! `Ref` types have accessor methods for getting and setting each
91//! field of the struct. For example, `IntList` has methods `.head()`, `.tail()`,
92//! `.set_head(i64)`, and `.set_tail(Option<IntListRef>)`.
93//!
94//! You can also derive `IntoHeap` for an enum, but support is incomplete: no
95//! `Ref` type is generated for enums. Tuple structs are not supported.
96//!
97//! ## Understanding heaps
98//!
99//! This part isn't documented well yet. But here's an example,
100//! using the `IntList` from above:
101//!
102//! ```rust
103//! # #[macro_use] extern crate cell_gc;
104//! # #[macro_use] extern crate cell_gc_derive;
105//! # #[derive(IntoHeap)]
106//! # struct IntList<'h> {
107//! # head: i64,
108//! # tail: Option<IntListRef<'h>>
109//! # }
110//! use cell_gc::Heap;
111//!
112//! fn main() {
113//! // Create a heap (you'll only do this once in your whole program)
114//! let mut heap = Heap::new();
115//!
116//! heap.enter(|hs| {
117//! // Allocate an object (returns an IntListRef)
118//! let obj1 = hs.alloc(IntList { head: 17, tail: None });
119//! assert_eq!(obj1.head(), 17);
120//! assert_eq!(obj1.tail(), None);
121//!
122//! // Allocate another object
123//! let obj2 = hs.alloc(IntList { head: 33, tail: Some(obj1) });
124//! assert_eq!(obj2.head(), 33);
125//! assert_eq!(obj2.tail().unwrap().head(), 17);
126//! });
127//! }
128//! ```
129//!
130//! Use `Heap::new()` in your `main()` function to create a heap.
131//! Use `heap.enter()` to gain access to the heap (opening a "heap session", `hs`).
132//! Use `hs.alloc(v)` to allocate values in the heap.
133//!
134//! # Vectors in the GC heap
135//!
136//! A very simple "object" type for a text adventure game:
137//!
138//! ```rust
139//! #[macro_use] extern crate cell_gc;
140//! #[macro_use] extern crate cell_gc_derive;
141//!
142//! use cell_gc::collections::VecRef;
143//!
144//! #[derive(IntoHeap)]
145//! struct Object<'h> {
146//! name: String,
147//! description: String,
148//! children: VecRef<'h, ObjectRef<'h>>
149//! }
150//! # fn main() {}
151//! ```
152//!
153//! Note that `children` is a `VecRef<'h, ObjectRef<'h>>`; that is, it is
154//! a reference to a separately GC-allocated `Vec<ObjectRef<'h>>`, which is
155//! a vector of references to other objects. In other words, this is exactly
156//! what you would have in Java for a field declared like this:
157//!
158//! ```java
159//! public ArrayList<Object> children;
160//! ```
161//!
162//! The API generated by this macro looks like this:
163//!
164//! ```rust
165//! # struct VecRef<'h, T: 'h>(&'h T); // hack to make this compile
166//! struct Object<'h> {
167//! name: String,
168//! description: String,
169//! children: VecRef<'h, ObjectRef<'h>>
170//! }
171//!
172//! struct ObjectRef<'h> {
173//! /* all fields private */
174//! # target: &'h Object<'h> // hack to make this compile
175//! }
176//!
177//! impl<'h> ObjectRef<'h> {
178//! fn name(&self) -> String
179//! # { unimplemented!(); }
180//! fn set_name(&self, name: String)
181//! # { unimplemented!(); }
182//! fn description(&self) -> String
183//! # { unimplemented!(); }
184//! fn set_description(&self, description: String)
185//! # { unimplemented!(); }
186//! fn children(&self) -> VecRef<'h, ObjectRef<'h>>
187//! # { unimplemented!(); }
188//! fn set_children(&self, children: VecRef<'h, ObjectRef<'h>>)
189//! # { unimplemented!(); }
190//! }
191//! ```
192//!
193//! (You might never actually use that `set_children()` method.
194//! Instead, you'll initialize the `children` field with a vector when you
195//! create the object, and then you'll most likely mutate that existing vector
196//! rather than ever creating a new one.)
197//!
198//! You can allocate `Object`s in the heap using `hs.alloc(Object { ... })`,
199//! and make one `Object` a child of another by using `obj1.children().push(obj2)`.
200//!
201//! # Safety
202//!
203//! As long as you don't type the keyword `unsafe` in your code,
204//! this GC is safe.<sup>[citation needed]</sup>
205//!
206//! Still, there's one weird rule to be aware of:
207//! **Don't implement `Drop` or `Clone`
208//! for any type declared using `derive(IntoHeap)`.**
209//! It's safe in the full Rust sense of that word
210//! (it won't cause crashes or undefined behavior,
211//! as long as your `.drop()` or `.clone()` method does nothing `unsafe`),
212//! but it won't do what you want.
213//! Your `.drop()` and `.clone()` methods simply will not be called when you expect;
214//! and they'll be called at other times that make no sense.
215//!
216//! So don't do that!
217//! The safe alternative is to put a `Box` or `Rc` around your value
218//! (the one that implements `Drop` or `Clone`)
219//! and use that as a field of a GC heap struct.
220//!
221//!
222//! # Why is it called "cell-gc"?
223//!
224//! In cell-gc, every field of every GC-managed object is mutable.
225//! You can't get *direct* references to the data;
226//! instead you use methods to get and set values.
227//!
228//! It's as though every field were a [Cell](http://doc.rust-lang.org/std/cell/struct.Cell.html).
229
230extern crate bit_vec;
231
232pub mod traits;
233mod pages;
234mod heap;
235mod gcref;
236mod gcleaf;
237pub mod collections;
238pub mod ptr;
239mod marking;
240
241pub use heap::{Heap, HeapSession, with_heap};
242pub use gcref::GcRef;
243pub use gcleaf::GCLeaf;
244
245/// Return the number of allocations of a given type that fit in a "page".
246/// (Unstable. This is a temporary hack for testing.)
247pub fn page_capacity<'h, T: traits::IntoHeapAllocation<'h>>() -> usize {
248 pages::TypedPage::<T::In>::capacity()
249}