summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2023-09-05 11:39:52 -0300
committerSoniEx2 <endermoneymod@gmail.com>2023-09-05 11:39:52 -0300
commitb49e8e6ca2185396b8cd05d0b4b83b3ae6b80dae (patch)
tree0d4a53f42c710668ec265be4967cfb20a5919caf
parentdbc79bbbc30308a86788b9b3d49b8f4c3b39b30a (diff)
Update crate documentation
Hopefully this clarifies things
-rw-r--r--Cargo.toml2
-rw-r--r--src/lib.rs128
-rw-r--r--src/srce.rs16
-rw-r--r--tests/ui/no_uaf_2.rs5
-rw-r--r--tests/ui/no_uaf_2.stderr8
5 files changed, 68 insertions, 91 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 75d049c..7eb9f7b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "selfref"
-version = "0.4.2"
+version = "0.4.3"
 authors = ["SoniEx2 <endermoneymod@gmail.com>"]
 edition = "2021"
 description = "Semi-pain-free self-referential pinned types"
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,
diff --git a/src/srce.rs b/src/srce.rs
index e263ddc..8015522 100644
--- a/src/srce.rs
+++ b/src/srce.rs
@@ -15,11 +15,9 @@
 //! Funny runtime specialization thing:
 //!
 //! ```rust
-//! #![feature(pin_macro)]
 //! use core::cell::Cell;
 //! use core::marker::PhantomData;
 //! use core::pin::Pin;
-//! use core::pin::pin;
 //!
 //! use qcell::LCell;
 //!
@@ -62,7 +60,7 @@
 //!
 //! fn main() {
 //!     // Create the holder
-//!     let mut holder = pin!(
+//!     let mut holder = Box::pin(
 //!         LCellEnvironment::<IntrusiveLCellKey<MyThing>>::new_with(
 //!             |thing| thing.build(IntrusiveLCell {
 //!                 y: Cell::new(None),
@@ -78,7 +76,7 @@
 //!     });
 //!
 //!     // Coerce to dyn Foo.
-//!     let mut holder: Pin<&mut LCellEnvironment<IntrusiveLCellKey<dyn Foo>>> = holder;
+//!     let mut holder: Pin<Box<LCellEnvironment<IntrusiveLCellKey<dyn Foo>>>> = holder;
 //!
 //!     // Run some rw/mut operations on it.
 //!     holder.as_mut().open_rw(|owner, thing| {
@@ -181,10 +179,7 @@ impl<'k, T> LCellEnvironment<'k, T> where T: Opaque {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(pin_macro)]
-    ///
     /// use qcell::LCell;
-    /// use core::pin::pin;
     /// 
     /// use selfref::srce::LCellEnvironment;
     /// use selfref::opaque;
@@ -201,7 +196,7 @@ impl<'k, T> LCellEnvironment<'k, T> where T: Opaque {
     /// }
     ///
     /// fn main() {
-    ///     let mut holder = pin!(LCellEnvironment::<'_, FooKey>::new_with(
+    ///     let mut holder = Box::pin(LCellEnvironment::<'_, FooKey>::new_with(
     ///         |foo| foo.build(Foo { foo: LCell::new(Default::default()) })
     ///     ));
     ///     // Actually making our Foo refer to itself.
@@ -239,10 +234,7 @@ impl<'k, T> LCellEnvironment<'k, T> where T: Opaque {
     /// # Examples
     ///
     /// ```rust
-    /// #![feature(pin_macro)]
-    ///
     /// use qcell::LCell;
-    /// use core::pin::pin;
     /// 
     /// use selfref::srce::LCellEnvironment;
     /// use selfref::opaque;
@@ -259,7 +251,7 @@ impl<'k, T> LCellEnvironment<'k, T> where T: Opaque {
     /// }
     ///
     /// fn main() {
-    ///     let holder = pin!(LCellEnvironment::<'_, FooKey>::new_with(
+    ///     let holder = Box::pin(LCellEnvironment::<'_, FooKey>::new_with(
     ///         |foo| foo.build(Foo { foo: LCell::new(Default::default()) })
     ///     ));
     ///     holder.as_ref().open_ro(
diff --git a/tests/ui/no_uaf_2.rs b/tests/ui/no_uaf_2.rs
index 49694b2..53e3ad8 100644
--- a/tests/ui/no_uaf_2.rs
+++ b/tests/ui/no_uaf_2.rs
@@ -1,9 +1,6 @@
 // by steffahn
 
-#![feature(pin_macro)]
-
 use std::cell::Cell;
-use std::pin::pin;
 
 use selfref::opaque;
 use selfref::Holder;
@@ -25,7 +22,7 @@ fn main() {
         Holder::<'_, MyStructKey>::new_with(|builder| builder.build(MyStruct {
             cell: Default::default(),
         }));
-    let s = pin!(s);
+    let s = Box::pin(s);
     s.as_ref().operate_in(|r| {
         r.cell.set(&String::from("hello world")); // temporary dropped at end of this statement
         println!("{}", r.cell.get()) // accesses dropped `String` data
diff --git a/tests/ui/no_uaf_2.stderr b/tests/ui/no_uaf_2.stderr
index 5737a38..5b9fa55 100644
--- a/tests/ui/no_uaf_2.stderr
+++ b/tests/ui/no_uaf_2.stderr
@@ -1,10 +1,10 @@
 error[E0716]: temporary value dropped while borrowed
-  --> tests/ui/no_uaf_2.rs:30:21
+  --> tests/ui/no_uaf_2.rs:27:21
    |
-29 |     s.as_ref().operate_in(|r| {
+26 |     s.as_ref().operate_in(|r| {
    |                            - has type `OperateIn<'1, MyStructKey>`
-30 |         r.cell.set(&String::from("hello world")); // temporary dropped at end of this statement
+27 |         r.cell.set(&String::from("hello world")); // temporary dropped at end of this statement
    |         ------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
    |         |           |
-   |         |           creates a temporary value which is freed while still in use
+   |         |           creates a temporary which is freed while still in use
    |         argument requires that borrow lasts for `'1`