Macro cell_gc::gc_heap_type [] [src]

macro_rules! gc_heap_type {
    { $(#[$attr:meta])* pub enum $($etc:tt)* } => { ... };
    { $(#[$attr:meta])* enum $($etc:tt)* } => { ... };
    { $(#[$attr:meta])* pub struct $($etc:tt)* } => { ... };
    { $(#[$attr:meta])* struct $($etc:tt)* } => { ... };
    { @as_item $x:item } => { ... };
    { @as_expr $x:expr } => { ... };
    {
        @gc_heap_struct ( $(#[$attr:meta])* ) ( $($maybe_pub:tt)* )
        struct $fields_type:ident / $ref_type:ident / $storage_type:ident <'h> {
            $($field_name:ident / $field_setter_name:ident : $field_type: ty),*
        }
    } => { ... };
    {
        @for_each_variant $_helper:tt {} $all_results:tt ($($ctn:tt)*)
    } => { ... };
    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident } $acc:tt $ctn:tt
    } => { ... };
    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident , $($more_variants:tt)* }
        $acc:tt $ctn:tt
    } => { ... };
    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ) }
        $acc:tt $ctn:tt
    } => { ... };
    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident ( $($field_types:tt)* ), $($more_variants:tt)*  }
        $acc:tt $ctn:tt
    } => { ... };
    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident { $($field_name:ident : $field_type:ty),* } }
        $acc:tt $ctn:tt
    } => { ... };
    {
        @for_each_variant ($($helper:tt)*)
        { $variant_name:ident { $($field_name:ident : $field_type:ty),* }, $($more_variants:tt)*  }
        $acc:tt $ctn:tt
    } => { ... };
    {
        @next_variant $helper:tt $more_variants:tt { $($acc:tt)* } $ctn:tt { $($rv:tt)* }
    } => { ... };
    {
        @zip_idents_with_types $_leftovers:tt () ($(($binding:ident : $btype:ty))*) ($($ctn:tt)*)
    } => { ... };
    {
        @zip_idents_with_types
        ($id:ident $($ids:tt)*)
        (($t:ty) $($ts:tt)*)
        ($($acc:tt)*)
        $ctn:tt
    } => { ... };
    {
        @enum_in_heap_variant $variant_name:ident NO_FIELDS ($($ctn:tt)*)
    } => { ... };
    {
        @enum_in_heap_variant $variant_name:ident ( $($field_type:ty),* ) ($($ctn:tt)*)
    } => { ... };
    {
        @enum_in_heap_variant $variant_name:ident { $($field_name:ident : $field_type:ty),* } ($($ctn:tt)*)
    } => { ... };
    {
        @enum_declare_in_heap_type ( $($maybe_pub:tt)* ) $storage_type:ident
            { $($variants:tt)* }
    } => { ... };
    {
        @enum_mark_variant $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => { ... };
    {
        @enum_mark_variant $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => { ... };
    {
        @enum_mark_variant_continued $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => { ... };
    {
        @enum_mark_variant $storage_type:ident
            $name:ident { $($field_name:ident : $field_type:ty),* } ($($ctn:tt)*)
    } => { ... };
    {
        @enum_mark_expr ($self_ref:expr) { $($arms:tt)* }
    } => { ... };
    {
        @enum_into_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS
            ($($ctn:tt)*)
    } => { ... };
    {
        @enum_into_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* )
            $ctn:tt
    } => { ... };
    {
        @enum_into_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => { ... };
    {
        @enum_into_heap_variant $stack_type:ident $storage_type:ident
            $name:ident { $($field_name:ident : $field_type:ty),* }
            ($($ctn:tt)*)
    } => { ... };
    {
        @enum_into_heap_expr ($self_:expr)
        { $($accumulated_output:tt)* }
    } => { ... };
    {
        @enum_from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident NO_FIELDS ($($ctn:tt)*)
    } => { ... };
    {
        @enum_from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident ( $($field_type:ty),* ) $ctn:tt
    } => { ... };
    {
        @enum_from_heap_variant_continued $stack_type:ident $storage_type:ident $name:ident ($($ctn:tt)*)
            ( $(($binding:ident : $field_type:ty))* )
    } => { ... };
    {
        @enum_from_heap_variant $stack_type:ident $storage_type:ident
            $name:ident { $($field_name:ident : $field_type:ty),* } ($($ctn:tt)*)
    } => { ... };
    {
        @enum_from_heap_expr ($self_ref:expr) { $($arms:tt)* }
    } => { ... };
    {
        @gc_heap_enum
        ($(#[$attr:meta])*)
        ($($maybe_pub:tt)*)
        enum $stack_type:ident / $storage_type:ident <'h>
        $variants:tt
    } => { ... };
}

The gc_heap_type! macro can declare structs and enums for use with Heap::alloc.

The argument to `gc_heap_type! is a struct or enum, with the following syntax:

heap-type:
    attr* heap-struct
    attr* heap-enum

attr:
    "#" "[" META "]"

heap-struct:
    "pub"? "struct" IDENT "/" IDENT "/" IDENT "<'h>" "{" heap-struct-field,* "}"

heap-struct-field:
    IDENT / IDENT ":" TYPE

heap-enum:
    "pub"? "enum" IDENT "/" IDENT "<'h>" "{" heap-enum-variant,* "}"

heap-enum-variant:
    IDENT
    IDENT "(" TYPE,* ")"

This syntax is almost a subset of real Rust struct and enum syntax. The only difference is that in some places we require two or three identifiers, instead of one:

  • The three names of a struct are: (1) the type you'll use to create instances and call heap.alloc with; (2) a Ref smart pointer type (what heap.alloc returns; and (3) the in-heap version of the struct, which you can just ignore. Attributes that appear in your code are applied only to the first of these three types.

  • The two names of a struct field are: (1) the field name, which doubles as the name of the getter on the Ref struct; (2) the setter name.

  • The two names of an enum are (1) the type you'll use; (2) the in-heap version of the enum, which you can just ignore. Threre's not a Ref type because at the moment, we don't support direct allocation of enums in the heap; they can only be fields of heap structs.

The exact lifetime name 'h is required. (A bizarre restriction - but I had little success getting the macro to accept an arbitrary lifetime passed in by the macro caller.)

Trailing commas are not supported everywhere they should be. (Sorry!)

Examples

A very simple "object" type for a text adventure game:

#[macro_use] extern crate cell_gc;
use cell_gc::collections::VecRef;

gc_heap_type! {
    struct Object / ObjectRef / ObjectInHeap <'h> {
        name / set_name : String,
        description / set_description: String,
        children / set_children: VecRef<'h, ObjectRef<'h>>
    }
}

Note that children is a VecRef<'h, ObjectRef<'h>>; that is, it is a reference to a separately GC-allocated Vec<ObjectRef<'h>>, which is a vector of references to other objects. In other words, this is exactly what you would have in Java for a field declared like this:

public ArrayList<Object> children;

The API generated by this macro looks like this:

struct Object<'h> {
    name: String,
    description: String,
    children: VecRef<'h, ObjectRef<'h>>
}

struct ObjectRef<'h> {
   /* all fields private */
}

impl<'h> ObjectRef<'h> {
    fn name(&self) -> String
    fn set_name(&self, name: String)
    fn description(&self) -> String
    fn set_description(&self, description: String)
    fn children(&self) -> VecRef<'h, ObjectRef<'h>>
    fn set_children(&self, children: VecRef<'h, ObjectRef<'h>>)
}

(You may never actually use that set_children() method. Instead, you'll initialize the children field with a vector when you create the object, and then you'll most likely mutate that existing vector rather than ever creating a new one.)

You can allocate Objects in the heap using heap.alloc(Object { ... }), and make one Object a child of another by using obj1.children().push(obj2).