Things to do:
- support multiple pages of objects (#4)
- fix nested heap structs (no tests, ergo it's broken)
- usability
- write a longer Tree example and see if the thing is the slightest bit usable
- having a struct as a field of a struct (like `children: Vec<ObjectRef>`)
is possible but not very useful without interior references. Given
struct Point / PointRef / PointInHeap {
x: u32,
y: u32
}
struct Rect / RectRef / RectInHeap {
top_left: Point,
bottom_right: Point
}
RectRef::top_left() should return a reference to that PointInHeap
embedded in the RectInHeap allocation.
- compatibility with the `custom_derive!` crate
- move toward a stable API
- remove the RefStorage type
- rename `Heap -> GCHeap`, `with_heap -> with_gc_heap`
or maybe just `GC` and `with_gc`
- decide which is better: `X / RefX / InHeapX/ InHeapRefX`
or `X / XRef / XStorage / XRefStorage`
and convert all the examples and tests :-P
- figure out if any of this stuff needs to be `!Send` or `!Sync`
- macros: allow (and probably require) explicitly providing the desired `#[derive]`
attributes for the "main" type, to avoid errors deriving Clone and Debug in tests
where they aren't even wanted
- documentation
- maybe use #[doc(hidden)] on the macro, document it in the README?
all that macro goop is not useful for people to read
- add a more detailed example to the readme
- add a *bunch* more examples to the doc comment on the macro
- (make sure macro documentation is actually attached in generated html)
- experimentally figure out common errors from macro gaffes and document them
(for example, leaving off the `/ set_foo` on a field causes
something bizarre about `@gc_heap_struct` not being expected,
sheer nonsense)
- performance
- add some bench tests
- profile
- if a lot of time is spent in into_heap/from_heap methods (particularly
from_heap), we can probably take advantage of the fact that IntoHeap
and in-heap values have the same bit-pattern.
- check in this todo list!
- upload to crates.io
- in debug builds, scribble on uninitialized memory
- review provided implementations of the traits:
- add comment: why Box is safe as written
- make sure there's a way to store a std::fs::File in the heap and borrow it for use
(today, could use an `Rc<RefCell<File>>`, I think?)
- consider Arc
- support HashMap
- consider PhantomData (oooooooooh)
- support small arrays
- consider non-'static refs that live at least as long as the Heap.
This is probably safe. (?!)
- figure out how to statically ensure Heap methods can't be reentered
from GC (e.g. via destructors or wayward mark methods);
or else add assertions against it: maybe `unsafe_deref(ptr, |r| { ... })`
- features
- IntoHeapAllocation::Ref should have get_all and set_all methods
- support typed allocators (to avoid the hash lookup per allocation)
- macros
- support immutable fields, with get and borrow accessors rather than get and set
- support more kinds of struct and enum syntax (particularly tuple structs and generics)
- support enum ref types and struct inline types
- consider toplevel type alias `type GCRef<'a, T: IntoHeapAllocation<'a>> = T::Ref;`
- support an "everything else" allocation-class with its own pages
- make tuples allocate-able, add `get_0` and `set_0` methods to the ref class
- review unsafe code and consider ways to isolate it
- test that when importing both GCRef and a macro-defined struct T from other modules,
the GCRef<'a, T> accessors are visible
- avoid stack overflow during marking
- get rid of BitVec and inline the "allocated" and "marked" bits into the page,
after the header (perf - but also eliminates a dependency)
- delete collections::VecStorage, just use Vec<T::In>
Things to test:
- boxed closures can live in the heap, as long as the lifetime is right
- destructor is also called when setting a field using the accessor
- a heap struct is destroyed: destructors for all fields are called too, transitively
- a ref can't be assigned to a variable of a different-lifetime ref type
- same goes for a struct even if it doesn't have any refs in it
- the next GC after unpinning a large amount of garbage collects it all
- multiple pages (type-classes) work
- it's safe to declare a destructor on a ref type, and even to chase the ref and use the heap
during destruction
- a heap struct can be nested inside a struct
- two types can refer to each other (byref)
- if two heap structs try to include each other inline, it won't compile
- types too big to fit in a page: won't compile?
- heap vectors are marked correctly
Done:
- test using it from another crate
- make Heap::id private again and retry all the "shouldn't compile" tests
- automate the "shouldn't compile" tests
- rename `$ref_type::address()` to `as_ptr()`
- consider not calling destructors but rather adding a `gc_drop()` method.
(it turns out `Drop` is safe!)
- test that destructors are called
- consider renaming the project to `tUnE_yArDs` (decided narrowly against it)
- make a `toy_gc::prelude` module (turns out most people are only going to need
`Heap` and `with_heap`, so this isn't worth it)
- don't expose the traits from the root - only from `traits`, so they don't
dominate the docs
- consider making `mark()` a plain old method, taking a non-`mut` self reference
(went ahead and did it)
- test gc is actually suitable for use in a toy vm (toy_vm.rs, a qualified success)
- worry about safety of user-defined Drop and statics with internal
mutability (it's ok)
- support heap structs of up to page size (issue #3)
- rename the project to something other than "toy_gc" (chose "cell_gc", catchy, i know)
- autogenerate README.md from crate doc-comments
- set up travis-ci
- check out meritbadge.herokuapp.com (yup, can haz badge)
- consider simplifying by unifying traits and loosening restrictions.
for example, maybe InHeap is not necessary; if not, it would eliminate the need
for the `$ref_storage_type` struct. (removed InHeap)
- review provided implementations of the traits:
- make sure the current bounds on the Box impls are the best ones (yep)
- make sure the current bounds on the Rc impls are the best ones (yep)
- consider non-'static refs that simply outlive the Heap (nope, can't write that bound)
- support tuples
- support 'static refs
- Vec<T: IntoHeap>
- consider Cell (seems redundant) and RefCell (could be useful - but I want
to be able to switch to a moving GC later without changing API; I think
borrowing will have to be much more restricted than that)
- macros
- unify the two macros
- allow declaring non-pub types,
to avoid `private type in public interface` errors in tests