Expand description

Pain-free self-referential/recursively-referential pinned types.

Because this crate optimizes for recursive references, it’s much nicer to use for porting/copying C code than alternatives. However, the cost is that it requires generic associated types (GATs). Further, this is the only crate for self-referential types which supports additional lifetimes than the self-referential one (with the small ergonomic caveat that closures don’t support where bounds for now, so a proper trait has to be used).

When using this crate, all you have to do is define your struct like you would in C, and then tell selfref about it. However, do watch out; the following will not be usable, despite compiling:

#![feature(generic_associated_types)]

use selfref::opaque;

// This is the actual self-referential struct.
struct MySelfRefStruct<'this> {
    this: &'this MySelfRefStruct<'this>,
}

// This is a "marker" type, used to tell `selfref` about the type.
// This is actually the "type family" GAT pattern.
struct MySelfRefStructKey;

// This tells `selfref` about our type.
opaque! {
    impl Opaque for MySelfRefStructKey {
        type Kind<'this> = MySelfRefStruct<'this>;
    }
}

That’s because there’s no way to create the reference &'this MySelfRefStruct<'this> before constructing the struct! That is, you cannot do this:

struct MySelfRefStruct<'this> {
    this: &'this MySelfRefStruct<'this>,
}

fn main() {
    let x = MySelfRefStruct { this: &x };
}

But then, you cannot do this in C either. Instead, to make it usable, we use an Option and, to be able to set it, a Cell, like so:

#![feature(generic_associated_types)]

use std::cell::Cell;

use selfref::opaque;

struct MySelfRefStruct<'this> {
    this: Cell<Option<&'this MySelfRefStruct<'this>>>,
}

struct MySelfRefStructKey;

opaque! {
    impl Opaque for MySelfRefStructKey {
        type Kind<'this> = MySelfRefStruct<'this>;
    }
}

and then we can use it:

// lines from the above example have been omitted

use selfref::Holder;
use selfref::new_with_closure;
use selfref::operate_in_closure;

fn main() {
    // first, construct the struct
    let holder = Box::pin(Holder::<'_, MySelfRefStructKey>::new_with(
        new_with_closure::<MySelfRefStructKey, _>(|_| {
            MySelfRefStruct {
                this: Cell::new(None)
            }
        })
    ));

    // then, build the self-reference
    holder.as_ref().operate_in(
        operate_in_closure::<MySelfRefStructKey, _, _>(|this| {
            this.this.set(Some(this.get_ref()));
        })
    );
}

Nightly

This crate (currently) requires nightly, as it relies on GATs.

Examples

This is a more complex example borrowing from an external lifetime:

#![feature(generic_associated_types)]
#![feature(pin_macro)]

use core::cell::Cell;
use core::marker::PhantomData;
use core::pin::Pin;
use core::pin::pin;
 
use selfref::Holder;
use selfref::NewWith;
use selfref::OperateIn;
use selfref::opaque;

struct Foo<'a, 'b: 'a> {
    foo: Cell<Option<&'a Foo<'a, 'b>>>,
    t: &'b str,
}

struct FooKey<'b>(PhantomData<&'b str>);
opaque! {
    impl['b] Opaque for FooKey<'b> {
        type Kind<'a> = Foo<'a, 'b>;
    }
}

fn main() {
    // can't use real closure, "hand-roll" a closure.
    struct FooBuilder<'b>(&'b str);
    impl<'k, 'b: 'k> NewWith<'k, FooKey<'b>> for FooBuilder<'b> {
        fn new_with<'a>(self) -> Foo<'a, 'b> where 'k: 'a {
            Foo {
                foo: Default::default(),
                t: self.0,
            }
        }
    }

    // a non-'static &str
    let stack_array: [u8; 5] = *b"hello";
    let stack_str = core::str::from_utf8(&stack_array).unwrap();

    // construct the struct
    let holder = pin!(Holder::new_with(FooBuilder(stack_str)));

    // setup the self-reference
    struct SetFooRef;
    impl<'k, 'b: 'k> OperateIn<'k, FooKey<'b>> for SetFooRef {
        type Out = ();
        fn operate_in<'a>(self, foo: Pin<&'a Foo<'a, 'b>>)
        where 'k: 'a {
            foo.foo.set(Some(foo.get_ref()));
        }
    }
    holder.as_ref().operate_in(SetFooRef);
}

Macros

Creates an opaqueified self-referential struct “key”.

Structs

Holds an “opaqueified” T::Kind.

Traits

Helper trait for creating a Holder.

An opaqueified self-referential struct “key”.

Helper trait for working with a Holder.

Functions

Helper for creating a Holder using a closure.

Helper for working with a Holder using a closure.