[][src]Macro selfstack::selfstack

selfstack!() { /* proc-macro */ }

selfstack produces a stack-like self-referential data structure with a safe interface. This is safe because layers in the stack can only reference layers below them, and lower layers outlive higher layers. This restriction prevents cycles, dangling references, and other unsoundness that would generally be possible with self-reference.

You must declare a mod in this macro. This is so the macro can make unsafe operations private.

Any struct inside that mod defines the layers of a stack with its fields. This struct is the Store. It provides storage for all fields ahead of time, but at first is uninitialized. Lifetime names are ignored, but you may use them to document references.

selfstack::selfstack! {
    mod mystack {
        pub struct MyStore {
            layer1: u32,
            layer2: &'layer1 u32,
        }
    }
}

To initialize the first layer, call set_$field(T) on the Store with the value of the first field. This will return a SubStruct that will allow you to safely access the subset of initialized layers.

let mut store = mystack::MyStore::new();
let sub_struct = store.set_layer1(42);

You can initialize further layers with the build_$field() and try_build_$field() methods. These return SubStructs that will allow access to the next layer. For build(), you pass a closure that takes references to the previous fields and returns the value of the next field. try_build() is the same except the closure should return a Result and it will return a Result.

let sub_struct = sub_struct.build_layer2(|layer1: &u32|->&u32 {
    layer1
});

You can get a const reference to any layer or a mutable reference to the top-most layer using methods that match ref_$fieldname() or mut_$fieldname(). If you need references to multiple layers simultaneously, you can call the view() method which will return a ViewStruct that contains public fields referencing each layer 1.

assert_eq!(*sub_struct.ref_layer1(), 42);
let view = sub_struct.view();
assert_eq!(**view.layer2, 42);
assert_eq!(*view.layer2, view.layer1);
*view.layer2 = &0; // Top layer is mutable.
assert_eq!(**view.layer2, 0);

When the SubStruct is dropped, the initialized fields will be dropped in reverse order and the Store can be reused.


  1. This cludge is due to limitations in the borrow checker. Calling a method on the SubStruct borrows the entire SubStruct, and the borrow checker won't allow multiple borrows simultaneously if any are mutable. The borrow checker is able to allow simultaneous borrows to the individual fields of a struct however.