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;
struct MySelfRefStruct<'this> {
this: &'this MySelfRefStruct<'this>,
}
struct MySelfRefStructKey;
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:
# #![feature(generic_associated_types)]
#
# use std::cell::Cell;
#
use selfref::Holder;
use selfref::new_with_closure;
# use selfref::opaque;
use selfref::operate_in_closure;
#
# struct MySelfRefStruct<'this> {
# this: Cell<Option<&'this MySelfRefStruct<'this>>>,
# }
#
# struct MySelfRefStructKey;
#
# opaque! {
# impl Opaque for MySelfRefStructKey {
# type Kind<'this> = MySelfRefStruct<'this>;
# }
# }
fn main() {
let holder = Box::pin(Holder::<'_, MySelfRefStructKey>::new_with(
new_with_closure::<MySelfRefStructKey, _>(|_| {
MySelfRefStruct {
this: Cell::new(None)
}
})
));
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() {
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,
}
}
}
let stack_array: [u8; 5] = *b"hello";
let stack_str = core::str::from_utf8(&stack_array).unwrap();
let holder = pin!(Holder::new_with(FooBuilder(stack_str)));
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);
}