Skip to content

Commit d4f5683

Browse files
committed
Mention Finalize in the README
1 parent dd2eac9 commit d4f5683

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

README.md

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,54 @@ This can be used pretty much like `Rc`, with the exception of interior mutabilit
2222

2323
While this can be used pervasively, this is intended to be used only when needed, following Rust's "pay only for what you need" model. Avoid using `Gc` where `Rc` or `Box` would be equally usable.
2424

25-
Types placed inside a `Gc` must implement `Trace`. The easiest way to do this is to use the `gc_derive` crate:
25+
Types placed inside a `Gc` must implement `Trace` and `Finalize`. The easiest way to do this is to use the `gc_derive` crate:
2626

2727
```rust
28-
#![feature(proc_macro)]
29-
3028
#[macro_use]
3129
extern crate gc_derive;
3230
extern crate gc;
3331

3432
use gc::Gc;
3533

36-
#[derive(Trace)]
34+
#[derive(Trace, Finalize)]
3735
struct Foo {
38-
x: Gc<Foo>,
39-
y: u8,
40-
// ...
36+
x: Gc<Foo>,
37+
y: u8,
38+
// ...
4139
}
4240

4341
// now, `Gc<Foo>` may be used
4442
```
4543

44+
> NOTE: Finalize is automatically implemented on all types when the `nightly`
45+
> feature is enabled through specialization.
46+
47+
`Finalize` may also be implemented directly on the struct, in order to add custom finalizer behavior:
48+
49+
```rust
50+
#[macro_use]
51+
extern crate gc_derive;
52+
extern crate gc;
53+
54+
use gc::Finalize;
55+
56+
#[derive(Trace)]
57+
struct Foo {...}
58+
59+
impl Finalize for Foo {
60+
fn finalize(&self) {
61+
// Clean up resources for Foo, because we think it will be destroyed.
62+
// Foo may not be destroyed after a call to finalize, as another
63+
// finalizer may create a reference to it due to reference cycles.
64+
}
65+
}
66+
```
67+
4668
For types defined in the stdlib, please file an issue on this repository (use the `unsafe_ignore_trace` method shown below to make things work in the meantime).
4769

4870
Note that `Trace` is only needed for types which transitively contain a `Gc`, if you are sure that this isn't the case, you may use the `unsafe_empty_trace!` macro on your types. Alternatively, use the `#[unsafe_ignore_trace]` annotation on the struct field. Incorrect usage of `unsafe_empty_trace` and `unsafe_ignore_trace` may lead to unsafety.
4971

5072
```rust
51-
#![feature(proc_macro)]
52-
5373
#[macro_use]
5474
extern crate gc_derive;
5575
extern crate gc;
@@ -59,12 +79,12 @@ extern crate bar;
5979
use gc::Gc;
6080
use bar::Baz;
6181

62-
#[derive(Trace)]
82+
#[derive(Trace, Finalize)]
6383
struct Foo {
64-
x: Gc<Foo>,
65-
#[unsafe_ignore_trace]
66-
y: Baz, // we are assuming that `Baz` doesn't contain any `Gc` objects
67-
// ...
84+
x: Gc<Foo>,
85+
#[unsafe_ignore_trace]
86+
y: Baz, // we are assuming that `Baz` doesn't contain any `Gc` objects
87+
// ...
6888
}
6989
```
7090

@@ -74,10 +94,10 @@ To use `Gc`, simply call `Gc::new`:
7494
let x = Gc::new(1_u8);
7595
let y = Gc::new(Box::new(Gc::new(1_u8)));
7696

77-
#[derive(Trace)]
97+
#[derive(Trace, Finalize)]
7898
struct Foo {
79-
a: Gc<u8>,
80-
b: u8
99+
a: Gc<u8>,
100+
b: u8
81101
}
82102

83103
let z = Gc::new(Foo {a: x.clone(), b: 1})
@@ -88,10 +108,10 @@ Calling `clone()` on a `Gc` will create another garbage collected reference to t
88108
`Gc` is an immutable container. Much like with `Rc`, to get mutability, we must use a cell type. The regular `RefCell` from the stdlib will not work with `Gc` (as it does not implement `Trace`), instead, use `GcCell`. `GcCell` behaves very similar to `RefCell`, except that it internally helps keep track of GC roots.
89109

90110
```rust
91-
#[derive(Trace)]
111+
#[derive(Trace, Finalize)]
92112
struct Foo {
93-
cyclic: GcCell<Option<Gc<Foo>>>,
94-
data: u8,
113+
cyclic: GcCell<Option<Gc<Foo>>>,
114+
data: u8,
95115
}
96116

97117
let foo1 = Gc::new(Foo {cyclic: GcCell::new(None), data: 1});
@@ -103,8 +123,8 @@ let foo3 = Gc::new(Foo {cyclic: GcCell::new(Some(foo2.clone())), data: 3});
103123

104124
## Known issues
105125

106-
- Destructors should not access `Gc`/`GcCell` values. We may add finalizers in the future, but we'd need to figure out a way to prevent this.
107-
- There needs to be a better story for cross-crate deriving, but we may have to wait for the middle IR to land to work on this.
126+
- Destructors should not access `Gc`/`GcCell` values. This is enforced by the `Trace` custom derive automatically implementing `Drop` with a safe empty drop method. `Finalize` should be used for cleanup instead.
127+
- There needs to be a better story for cross-crate deriving.
108128
- The current GC is not concurrent and the GCed objects are confined to a thread. There is an experimental concurrent collector [in this pull request](https://github.com/Manishearth/rust-gc/pull/6).
109129

110130

0 commit comments

Comments
 (0)