summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2022-12-05 16:32:20 -0300
committerSoniEx2 <endermoneymod@gmail.com>2022-12-05 16:32:20 -0300
commit72841de072c4a904983e9eb631b690a61d3e06ff (patch)
tree18b5677a9bcc61e77a140b9012c1d82333e2f4f1
parent2b5d0cb87b13fd5354143bb0b802d06ca0715ca6 (diff)
Use closures for new_with
-rw-r--r--Cargo.toml2
-rw-r--r--src/lib.rs101
-rw-r--r--tests/ui/no_uaf_1.rs18
-rw-r--r--tests/ui/no_uaf_1.stderr47
-rw-r--r--tests/ui/no_uaf_2.rs4
5 files changed, 58 insertions, 114 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 672d5d7..6e8453c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "selfref"
-version = "0.3.0"
+version = "0.4.0"
 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 e87784d..fdefe7d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -84,7 +84,6 @@
 //! # use std::cell::Cell;
 //! #
 //! use selfref::Holder;
-//! use selfref::new_with_closure;
 //! # use selfref::opaque;
 //! #
 //! # struct MySelfRefStruct<'this> {
@@ -102,7 +101,7 @@
 //! fn main() {
 //!     // first, construct the struct
 //!     let holder = Box::pin(Holder::<'_, MySelfRefStructKey>::new_with(
-//!         new_with_closure::<MySelfRefStructKey, _>(|_| {
+//!         |foo| foo.build({
 //!             MySelfRefStruct {
 //!                 this: Cell::new(None)
 //!             }
@@ -131,7 +130,6 @@
 //! use core::pin::pin;
 //! 
 //! use selfref::Holder;
-//! use selfref::NewWith;
 //! use selfref::opaque;
 //!
 //! struct Foo<'a, 'b: 'a> {
@@ -147,23 +145,17 @@
 //! }
 //!
 //! 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)));
+//!     let holder = pin!(Holder::<'_, FooKey<'_>>::new_with(|foo| {
+//!         foo.build(Foo {
+//!             foo: Default::default(),
+//!             t: stack_str,
+//!         })
+//!     }));
 //!
 //!     holder.as_ref().operate_in(|foo| {
 //!         foo.foo.set(Some(foo.get_ref()));
@@ -427,7 +419,6 @@ macro_rules! opaque {
 /// use core::cell::Cell;
 /// 
 /// use selfref::Holder;
-/// use selfref::new_with_closure;
 /// use selfref::opaque;
 ///
 /// #[derive(Default)]
@@ -445,7 +436,7 @@ macro_rules! opaque {
 /// fn main() {
 ///     // We can use a closure here, but we need to give the compiler a hint.
 ///     let holder = Holder::<'_, FooKey>::new_with(
-///         new_with_closure::<FooKey, _>(|foo| Foo::default())
+///         |foo| foo.build(Foo::default())
 ///     );
 /// }
 /// ```
@@ -454,36 +445,23 @@ pub struct Holder<'k, T> where T: Opaque + 'k {
   inner: <T as Opaque>::Kind<'k>,
 }
 
-/// Helper trait for creating a [`Holder`].
+/// Helper for creating a [`Holder`].
 ///
 /// This is necessary because closures don't work properly here.
 ///
 /// See [`Holder::new_with`] for examples.
-pub trait NewWith<'k, T: Opaque + 'k> {
-    /// Creates a new `T::Kind` with an unbound lifetime.
-    fn new_with<'a>(self) -> T::Kind<'a> where 'k: 'a, T::Kind<'a>: Sized;
+pub struct Builder<'k, T: Opaque + 'k> where T::Kind<'k>: Sized {
+    inner: Option<T::Kind<'k>>,
 }
 
-impl<'k, T: Opaque + 'k, F> NewWith<'k, T> for F
-where
-    F: for<'a> FnOnce([&'a (); 0]) -> <T as Opaque>::Kind<'a>,
-{
-    fn new_with<'a>(self) -> T::Kind<'a> where 'k: 'a, T::Kind<'a>: Sized {
-        self([])
+impl<'k, T: Opaque + 'k> Builder<'k, T> where T::Kind<'k>: Sized {
+    /// Builds the [`Holder`].
+    #[inline]
+    pub fn build(&mut self, t: T::Kind<'k>) {
+        self.inner = Some(t);
     }
 }
 
-/// Helper for creating a [`Holder`] using a closure.
-///
-/// This only works if `K` is `'static`.
-pub fn new_with_closure<K: Opaque, F>(f: F) -> F
-where
-    F: for<'a> FnOnce([&'a (); 0]) -> <K as Opaque>::Kind<'a>,
-    for<'a> K::Kind<'a>: Sized,
-{
-    f
-}
-
 impl<'k, T> Holder<'k, T> where T: Opaque {
     /// Creates a new holder.
     ///
@@ -495,7 +473,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// use core::cell::Cell;
     /// 
     /// use selfref::Holder;
-    /// use selfref::new_with_closure;
     /// use selfref::opaque;
     ///
     /// #[derive(Default)]
@@ -513,7 +490,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// fn main() {
     ///     // We can use a closure here, but we need to help the compiler.
     ///     let holder = Holder::<'_, FooKey>::new_with(
-    ///         new_with_closure::<FooKey, _>(|foo| Foo::default())
+    ///         |foo| foo.build(Foo::default())
     ///     );
     /// }
     /// ```
@@ -525,7 +502,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// use core::marker::PhantomData;
     /// 
     /// use selfref::Holder;
-    /// use selfref::NewWith;
     /// use selfref::opaque;
     ///
     /// struct Foo<'a, 'b: 'a> {
@@ -541,28 +517,27 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// }
     ///
     /// 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";
     ///     // a non-'static &str
     ///     let stack_str = core::str::from_utf8(&stack_array).unwrap();
-    ///     let holder = Holder::new_with(FooBuilder(stack_str));
+    ///     let holder = Holder::<'_, FooKey<'_>>::new_with(|foo| {
+    ///         foo.build(Foo {
+    ///             foo: Default::default(),
+    ///             t: stack_str,
+    ///         });
+    ///     });
     /// }
     /// ```
     pub fn new_with<F>(f: F) -> Self
     where
-        F: NewWith<'k, T>,  T::Kind<'k>: Sized
+        F: for<'a> FnOnce(&mut Builder<'a, T>),
+        T::Kind<'k>: Sized,
     {
+        let mut builder = Builder { inner: None };
+        f(&mut builder);
         Self {
             // it is important that the constructor cannot observe 'k!
-            inner: f.new_with(),
+            inner: builder.inner.unwrap(),
             _pinned: PhantomPinned
         }
     }
@@ -600,7 +575,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// use core::pin::pin;
     /// 
     /// use selfref::Holder;
-    /// use selfref::new_with_closure;
     /// use selfref::opaque;
     ///
     /// #[derive(Default)]
@@ -617,7 +591,7 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     ///
     /// fn main() {
     ///     let holder = pin!(Holder::<'_, FooKey>::new_with(
-    ///         new_with_closure::<FooKey, _>(|foo| Foo::default())
+    ///         |foo| foo.build(Foo::default())
     ///     ));
     ///     // Actually making our Foo refer to itself.
     ///     holder.as_ref().operate_in(
@@ -639,7 +613,6 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// use core::pin::pin;
     /// 
     /// use selfref::Holder;
-    /// use selfref::NewWith;
     /// use selfref::opaque;
     ///
     /// struct Foo<'a, 'b: 'a> {
@@ -655,19 +628,15 @@ impl<'k, T> Holder<'k, T> where T: Opaque {
     /// }
     ///
     /// 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";
     ///     // a non-'static &str
     ///     let stack_str = core::str::from_utf8(&stack_array).unwrap();
-    ///     let holder = pin!(Holder::new_with(FooBuilder(stack_str)));
+    ///     let holder = pin!(Holder::<'_, FooKey<'_>>::new_with(|foo| {
+    ///         foo.build(Foo {
+    ///             foo: Default::default(),
+    ///             t: stack_str,
+    ///         });
+    ///     }));
     ///     // Actually making our Foo refer to itself.
     ///     holder.as_ref().operate_in(|foo| {
     ///         foo.foo.set(Some(foo.get_ref()));
diff --git a/tests/ui/no_uaf_1.rs b/tests/ui/no_uaf_1.rs
index e4d7ac4..1d9411e 100644
--- a/tests/ui/no_uaf_1.rs
+++ b/tests/ui/no_uaf_1.rs
@@ -1,7 +1,6 @@
 use core::cell::Cell;
 
 use selfref::Holder;
-use selfref::NewWith;
 use selfref::opaque;
 
 mod bad {
@@ -19,16 +18,13 @@ mod bad {
     }
     pub fn test() {
         let rc = Rc::new(Cell::new(""));
-        struct FooBuilder<'b>(Rc<Cell<&'b str>>);
-        impl<'k, 'b> NewWith<'k, FooOpaque> for FooBuilder<'b> {
-            fn new_with<'a>(self) -> Foo<'a> where 'k: 'a {
-                Foo {
-                    x: "Hello".to_owned(),
-                    y: self.0,
-                }
-            }
-        }
-        let x = Holder::new_with(FooBuilder(rc.clone()));
+        let rc_clone = rc.clone();
+        let x = Holder::<'_, FooOpaque>::new_with(move |builder| {
+            builder.build(Foo {
+                x: "Hello".to_owned(),
+                y: rc_clone,
+            });
+        });
         let x = Box::pin(x);
         x.as_ref().operate_in(|foo| {
             let foo = foo.get_ref();
diff --git a/tests/ui/no_uaf_1.stderr b/tests/ui/no_uaf_1.stderr
index 6db82ed..af0d3e6 100644
--- a/tests/ui/no_uaf_1.stderr
+++ b/tests/ui/no_uaf_1.stderr
@@ -1,37 +1,16 @@
-error: lifetime may not live long enough
-  --> tests/ui/no_uaf_1.rs:25:17
+error[E0521]: borrowed data escapes outside of closure
+  --> tests/ui/no_uaf_1.rs:23:13
    |
-23 |           impl<'k, 'b> NewWith<'k, FooOpaque> for FooBuilder<'b> {
-   |                    -- lifetime `'b` defined here
-24 |               fn new_with<'a>(self) -> Foo<'a> where 'k: 'a {
-   |                           -- lifetime `'a` defined here
-25 | /                 Foo {
-26 | |                     x: "Hello".to_owned(),
-27 | |                     y: self.0,
-28 | |                 }
-   | |_________________^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+21 |           let rc_clone = rc.clone();
+   |               -------- `rc_clone` declared here, outside of the closure body
+22 |           let x = Holder::<'_, FooOpaque>::new_with(move |builder| {
+   |                                                           ------- `builder` is a reference that is only valid in the closure body
+23 | /             builder.build(Foo {
+24 | |                 x: "Hello".to_owned(),
+25 | |                 y: rc_clone,
+26 | |             });
+   | |______________^ `builder` escapes the closure body here
    |
-   = help: consider adding the following bound: `'b: 'a`
-   = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
-   = note: the struct `Foo<'a>` is invariant over the parameter `'a`
+   = note: requirement occurs because of a mutable reference to `selfref::Builder<'_, FooOpaque>`
+   = note: mutable references are invariant over their type parameter
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-
-error: lifetime may not live long enough
-  --> tests/ui/no_uaf_1.rs:25:17
-   |
-23 |           impl<'k, 'b> NewWith<'k, FooOpaque> for FooBuilder<'b> {
-   |                    -- lifetime `'b` defined here
-24 |               fn new_with<'a>(self) -> Foo<'a> where 'k: 'a {
-   |                           -- lifetime `'a` defined here
-25 | /                 Foo {
-26 | |                     x: "Hello".to_owned(),
-27 | |                     y: self.0,
-28 | |                 }
-   | |_________________^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
-   |
-   = help: consider adding the following bound: `'a: 'b`
-   = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
-   = note: the struct `Foo<'a>` is invariant over the parameter `'a`
-   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
-
-help: `'b` and `'a` must be the same: replace one with the other
diff --git a/tests/ui/no_uaf_2.rs b/tests/ui/no_uaf_2.rs
index eb6b7d3..49694b2 100644
--- a/tests/ui/no_uaf_2.rs
+++ b/tests/ui/no_uaf_2.rs
@@ -6,7 +6,7 @@ use std::cell::Cell;
 use std::pin::pin;
 
 use selfref::opaque;
-use selfref::{new_with_closure, Holder};
+use selfref::Holder;
 
 struct MyStruct<'this> {
     cell: Cell<&'this str>,
@@ -22,7 +22,7 @@ opaque! {
 
 fn main() {
     let s =
-        Holder::<'_, MyStructKey>::new_with(new_with_closure::<MyStructKey, _>(|[]| MyStruct {
+        Holder::<'_, MyStructKey>::new_with(|builder| builder.build(MyStruct {
             cell: Default::default(),
         }));
     let s = pin!(s);