Skip to content

Commit

Permalink
Replace gc_plugin with a macros 1.1-based gc_derive plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
mystor committed Oct 9, 2016
1 parent de2a076 commit aaca951
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 200 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ To include in your project, add the following to your Cargo.toml:
```
[dependencies]
gc = "*"
gc_plugin = "*"
gc_derive = "*"
```

This can be used pretty much like `Rc`, with the exception of interior mutability.

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.

Types placed inside a `Gc` must implement `Trace`. The easiest way to do this is to use the existing plugin:
Types placed inside a `Gc` must implement `Trace`. The easiest way to do this is to use the `gc_derive` crate:

```rust
#![feature(plugin, custom_derive)]
#![feature(proc_macro)]

#![plugin(gc_plugin)]
#[macro_use]
extern crate gc_derive;
extern crate gc;

use gc::Gc;
Expand All @@ -47,9 +48,10 @@ For types defined in the stdlib, please file an issue on this repository (use th
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.

```rust
#![feature(plugin, custom_derive, custom_attribute)]
#![feature(proc_macro)]

#![plugin(gc_plugin)]
#[macro_use]
extern crate gc_derive;
extern crate gc;

extern crate bar;
Expand Down
5 changes: 2 additions & 3 deletions gc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ readme = "../README.md"
license = "MPL-2.0"
keywords = ["garbage", "plugin", "memory"]

[dev-dependencies.gc_plugin]
path = "../gc_plugin"
version = "0.1.1"
[dev-dependencies]
gc_derive = { path = "../gc_derive" }
5 changes: 3 additions & 2 deletions gc/tests/finalize.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(plugin, custom_derive, specialization)]
#![feature(proc_macro, specialization)]

#![plugin(gc_plugin)]
#[macro_use]
extern crate gc_derive;
extern crate gc;

use std::cell::Cell;
Expand Down
5 changes: 3 additions & 2 deletions gc/tests/gc_semantics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(plugin, custom_derive, specialization)]
#![feature(proc_macro, specialization)]

#![plugin(gc_plugin)]
#[macro_use]
extern crate gc_derive;
extern crate gc;

use std::cell::Cell;
Expand Down
5 changes: 3 additions & 2 deletions gc/tests/gymnastics_cycle.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(plugin, custom_derive, specialization)]
#![feature(proc_macro, specialization)]

#![plugin(gc_plugin)]
#[macro_use]
extern crate gc_derive;
extern crate gc;

use std::cell::Cell;
Expand Down
5 changes: 3 additions & 2 deletions gc/tests/trace_impl.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(plugin, custom_derive)]
#![feature(proc_macro, specialization)]

#![plugin(gc_plugin)]
#[macro_use]
extern crate gc_derive;
extern crate gc;
use std::cell::RefCell;

Expand Down
16 changes: 10 additions & 6 deletions gc_plugin/Cargo.toml → gc_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
[package]
name = "gc_plugin"
name = "gc_derive"
version = "0.1.1"
authors = ["Manish Goregaokar <manishsmail@gmail.com>", "Michael Layzell <michael@thelayzells.com>"]

description = "Garbage collector plugin for rust-gc"
description = "Garbage collector derive plugin for rust-gc"
repository = "https://github.com/Manishearth/rust-gc"
readme = "../README.md"
license = "MPL-2.0"
keywords = ["garbage", "plugin", "memory"]

keywords = ["garbage", "macro", "memory"]

[lib]
name = "gc_plugin"
plugin = true
name = "gc_derive"
proc-macro = true

[dependencies]
syn = "0.9"
quote = "0.3"
synstructure = "0.1"
87 changes: 87 additions & 0 deletions gc_derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#![feature(proc_macro, proc_macro_lib)]

extern crate proc_macro;
extern crate syn;
extern crate synstructure;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use synstructure::BindStyle;

#[proc_macro_derive(Trace)]
pub fn derive_trace(input: TokenStream) -> TokenStream {
let source = input.to_string();
let mut ast = syn::parse_macro_input(&source).unwrap();

let trace = synstructure::each_field(&mut ast, BindStyle::Ref, |bi| {
// Check if this field is annotated with an #[unsafe_ignore_trace], and
// remove the attribute if it is present.
let attr_cnt = bi.field.attrs.len();
bi.field.attrs.retain(|attr| attr.name() != "unsafe_ignore_trace");

if bi.field.attrs.len() != attr_cnt {
quote::Tokens::new()
} else {
quote!(mark(#bi);)
}
});

// Build the output tokens
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let result = quote! {
// Original struct
#ast

unsafe impl #impl_generics ::gc::Trace for #name #ty_generics #where_clause {
#[inline] unsafe fn trace(&self) {
#[allow(dead_code)]
#[inline]
unsafe fn mark<T: ::gc::Trace>(it: &T) {
::gc::Trace::trace(it);
}
match *self { #trace }
}
#[inline] unsafe fn root(&self) {
#[allow(dead_code)]
#[inline]
unsafe fn mark<T: ::gc::Trace>(it: &T) {
::gc::Trace::root(it);
}
match *self { #trace }
}
#[inline] unsafe fn unroot(&self) {
#[allow(dead_code)]
#[inline]
unsafe fn mark<T: ::gc::Trace>(it: &T) {
::gc::Trace::unroot(it);
}
match *self { #trace }
}
#[inline] fn finalize_glue(&self) {
#[allow(dead_code)]
#[inline]
fn mark<T: ::gc::Trace>(it: &T) {
::gc::Trace::finalize_glue(it);
}
match *self { #trace }
::gc::Finalize::finalize(self);
}
}

// We also implement drop to prevent unsafe drop implementations on this
// type and encourage people to use Finalize. This implementation will
// call `Finalize::finalize` if it is safe to do so.
impl #impl_generics ::std::ops::Drop for #name #ty_generics #where_clause {
fn drop(&mut self) {
if ::gc::finalizer_safe() {
::gc::Finalize::finalize(self);
}
}
}
};

// Generate the final value as a TokenStream and return it
result.to_string().parse().unwrap()
}
177 changes: 0 additions & 177 deletions gc_plugin/src/lib.rs

This file was deleted.

0 comments on commit aaca951

Please sign in to comment.