diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 133 |
1 files changed, 129 insertions, 4 deletions
diff --git a/src/lib.rs b/src/lib.rs index 8a4b81e..44a5a50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,131 @@ #![feature(generic_associated_types)] #![no_std] -//! Pain-free self-referential pinned types. + +//! 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: +//! +//! ```rust +//! #![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: +//! +//! ```rust compile_fail +//! 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: +//! +//! ```rust +//! #![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: +//! +//! ```rust +//! // lines from the above example have been omitted +//! +//! # #![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() { +//! // 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. //! -//! # Example +//! # Examples +//! +//! This is a more complex example borrowing from an external lifetime: //! //! ```rust //! #![feature(generic_associated_types)] @@ -40,6 +160,7 @@ //! } //! //! 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 { @@ -49,11 +170,15 @@ //! } //! } //! } -//! let stack_array: [u8; 5] = *b"hello"; +//! //! // 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))); -//! // Actually making our Foo refer to itself. +//! +//! // setup the self-reference //! struct SetFooRef; //! impl<'k, 'b: 'k> OperateIn<'k, FooKey<'b>> for SetFooRef { //! type Out = (); |