summary refs log tree commit diff stats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs128
1 files changed, 58 insertions, 70 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 17c4c10..bc06faf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,65 +8,53 @@
 #![no_std]
 #![cfg_attr(feature="nightly", feature(dropck_eyepatch))]
 
-//! Pain-free self-referential/recursively-referential pinned types.
+//! An experimental approach to self-referential structs in Rust.
 //!
-//! 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).
+//! This crate provides an alternative approach to self-referential structs,
+//! where instead of providing you with a macro or framework where you define
+//! a self-referential struct and it handles all of the details for you, we try
+//! to expose the abstractions and building blocks for making self-referential
+//! structs work well in safe Rust.
 //!
-//! 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:
+//! For example, a [`Holder`] is a safe wrapper around a self-referential
+//! struct, providing safe APIs for constructing and manipulating a
+//! self-referential struct. However, and unlike other self-referential crates,
+//! it does not dictate the backing storage of the struct. The [`Opaque`] trait
+//! is used to identify a self-referential struct for use with a [`Holder`] -
+//! since Rust does not support higher kinded types (HKTs), this crate uses
+//! generic associated types (GATs) as a workaround.
 //!
-//! ```rust
-//! 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>;
-//!     }
-//! }
-//! ```
+//! To use the crate, first define a self-referential struct in plain Rust:
 //!
-//! 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
+//! use std::cell::Cell;
 //!
-//! ```rust compile_fail
+//! // Your self-referential struct.
 //! struct MySelfRefStruct<'this> {
-//!     this: &'this MySelfRefStruct<'this>,
-//! }
-//!
-//! fn main() {
-//!     let x = MySelfRefStruct { this: &x };
+//!     // Rust uses RAII-like struct construction, as a result this must be
+//!     // somehow initialized after the struct. We can use an Option in a Cell
+//!     // for this.
+//!     this: Cell<Option<&'this MySelfRefStruct<'this>>>,
 //! }
 //! ```
 //!
-//! 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:
+//! Then, define a type to implement the `Opaque`. This can be done
+//! automatically with the `opaque` macro:
 //!
 //! ```rust
-//! use std::cell::Cell;
+//! # use std::cell::Cell;
+//! # // Your self-referential struct.
+//! # struct MySelfRefStruct<'this> {
+//! #     // Rust uses RAII-like struct construction, as a result this must be
+//! #     // somehow initialized after the struct. We can use an Option in a Cell
+//! #     // for this.
+//! #     this: Cell<Option<&'this MySelfRefStruct<'this>>>,
+//! # }
 //!
 //! use selfref::opaque;
 //!
-//! struct MySelfRefStruct<'this> {
-//!     this: Cell<Option<&'this MySelfRefStruct<'this>>>,
-//! }
-//!
+//! // A "marker type" that implements `Opaque`.
+//! // This follows the "type family" GAT pattern.
 //! struct MySelfRefStructKey;
 //!
 //! opaque! {
@@ -74,29 +62,38 @@
 //!         type Kind<'this> = MySelfRefStruct<'this>;
 //!     }
 //! }
+//!
+//! // Alternatively, it is possible to implement `Opaque` on, for example,
+//! // `MySelfRefStruct<'static>`, but the added lifetime adds verbosity which
+//! // may be considered unnecessary/undesired.
 //! ```
 //!
-//! and then we can use it:
+//! Now you can construct a `Holder` and pick a storage for it. For example,
+//! in a `Box`:
 //!
 //! ```rust
-//! // lines from the above example have been omitted
-//!
 //! # use std::cell::Cell;
-//! #
-//! use selfref::Holder;
-//! # use selfref::opaque;
-//! #
+//! # // Your self-referential struct.
 //! # struct MySelfRefStruct<'this> {
+//! #     // Rust uses RAII-like struct construction, as a result this must be
+//! #     // somehow initialized after the struct. We can use an Option in a Cell
+//! #     // for this.
 //! #     this: Cell<Option<&'this MySelfRefStruct<'this>>>,
 //! # }
-//! #
+//! # use selfref::opaque;
+//! # // A "marker type" that implements `Opaque`.
+//! # // This follows the "type family" GAT pattern.
 //! # struct MySelfRefStructKey;
-//! #
 //! # opaque! {
 //! #     impl Opaque for MySelfRefStructKey {
 //! #         type Kind<'this> = MySelfRefStruct<'this>;
 //! #     }
 //! # }
+//! # // Alternatively, it is possible to implement `Opaque` on, for example,
+//! # // `MySelfRefStruct<'static>`, but the added lifetime adds verbosity which
+//! # // may be considered unnecessary/undesired.
+//!
+//! use selfref::Holder;
 //!
 //! fn main() {
 //!     // first, construct the struct
@@ -122,12 +119,9 @@
 //! This is a more complex example borrowing from an external lifetime:
 //!
 //! ```rust
-//! #![feature(pin_macro)]
-//!
 //! use core::cell::Cell;
 //! use core::marker::PhantomData;
 //! use core::pin::Pin;
-//! use core::pin::pin;
 //! 
 //! use selfref::Holder;
 //! use selfref::opaque;
@@ -150,7 +144,7 @@
 //!     let stack_str = core::str::from_utf8(&stack_array).unwrap();
 //!
 //!     // construct the struct
-//!     let holder = pin!(Holder::<'_, FooKey<'_>>::new_with(|foo| {
+//!     let holder = Box::pin(Holder::<'_, FooKey<'_>>::new_with(|foo| {
 //!         foo.build(Foo {
 //!             foo: Default::default(),
 //!             t: stack_str,
@@ -175,9 +169,9 @@
 //!     "PhantomDrop".
 //!
 //! When enabling both features, `nightly` takes over and we use the wrapper
-//! always. This doesn't make a practical difference since the generated UB
-//! check is dead code anyway, but `PhantomDrop` should be lighter on compile
-//! times.
+//! always. This doesn't make a significant difference since the generated UB
+//! check is dead code anyway, but `PhantomDrop` doesn't depend on `alloc` and
+//! can be used in `no_std` environments.
 //!
 //! If not using either feature, `T: ?Sized` support requires `unsafe`ly
 //! implementing `Opaque`.
@@ -207,7 +201,7 @@ extern crate alloc;
 
 #[cfg(all(feature="alloc", not(feature="nightly")))]
 #[doc(hidden)]
-pub use alloc::boxed::Box as UBCheck;
+pub struct UBCheck<T: ?Sized>(alloc::boxed::Box<T>);
 
 #[cfg(feature="nightly")]
 #[doc(hidden)]
@@ -572,10 +566,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// Simple example:
     ///
     /// ```rust
-    /// #![feature(pin_macro)]
-    ///
     /// use core::cell::Cell;
-    /// use core::pin::pin;
     /// 
     /// use selfref::Holder;
     /// use selfref::opaque;
@@ -593,7 +584,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// }
     ///
     /// fn main() {
-    ///     let holder = pin!(Holder::<'_, FooKey>::new_with(
+    ///     let holder = Box::pin(Holder::<'_, FooKey>::new_with(
     ///         |foo| foo.build(Foo::default())
     ///     ));
     ///     // Actually making our Foo refer to itself.
@@ -608,12 +599,9 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// With lifetime parameters:
     ///
     /// ```rust
-    /// #![feature(pin_macro)]
-    ///
     /// use core::cell::Cell;
     /// use core::marker::PhantomData;
     /// use core::pin::Pin;
-    /// use core::pin::pin;
     /// 
     /// use selfref::Holder;
     /// use selfref::opaque;
@@ -634,7 +622,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     ///     let stack_array: [u8; 5] = *b"hello";
     ///     // a non-'static &str
     ///     let stack_str = core::str::from_utf8(&stack_array).unwrap();
-    ///     let holder = pin!(Holder::<'_, FooKey<'_>>::new_with(|foo| {
+    ///     let holder = Box::pin(Holder::<'_, FooKey<'_>>::new_with(|foo| {
     ///         foo.build(Foo {
     ///             foo: Default::default(),
     ///             t: stack_str,