summary refs log blame commit diff stats
path: root/src/srce.rs
blob: e263ddc2584925af04b7896bcfccc52a177998a4 (plain) (tree)




































































































































































































































































































                                                                                        
// SRCE - Self-referential cell environments
// Copyright (C) 2022-2023 Soni L.
// This software is made with love by a queer trans person.
//
// SPDX-License-Identifier: MIT OR Apache-2.0

//! SRCE is a way to open and close an `LCellOwner`. This provides the full
//! expressive power of `selfref`, with the ability to use zeroish-cost
//! `LCell`s in the struct.
//!
//! This module requires crate feature `qcell`.
//!
//! # Examples
//!
//! 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;
//!
//! use selfref::srce::LCellEnvironment;
//!
//! // Some traits we wanna have
//! trait Foo {
//!     fn update(&mut self);
//! }
//! trait Bar {
//!     fn get(&self) -> String;
//! }
//!
//! // Thing that impls multiple of them
//! struct MyThing;
//! impl Foo for MyThing {
//!     fn update(&mut self) {
//!         println!("hello world!");
//!     }
//! }
//! impl Bar for MyThing {
//!     fn get(&self) -> String {
//!         return String::from("hello");
//!     }
//! }
//!
//! // The container for the above.
//! // T is gonna become dyn Foo later
//! struct IntrusiveLCell<'a, T: ?Sized> {
//!     y: Cell<Option<&'a LCell<'a, dyn Bar>>>,
//!     x: LCell<'a, T>,
//! }
//! // The "key" or "kind" struct for `selfref` to do the magic.
//! struct IntrusiveLCellKey<T: ?Sized>(PhantomData<T>);
//! selfref::opaque! {
//!     impl[T: ?Sized] Opaque for IntrusiveLCellKey<T> {
//!         type Kind<'this> = IntrusiveLCell<'this, T>;
//!     }
//! }
//!
//! fn main() {
//!     // Create the holder
//!     let mut holder = pin!(
//!         LCellEnvironment::<IntrusiveLCellKey<MyThing>>::new_with(
//!             |thing| thing.build(IntrusiveLCell {
//!                 y: Cell::new(None),
//!                 x: LCell::new(MyThing),
//!             })
//!         )
//!     );
//!
//!     // Create the `&LCell<dyn Bar>`. doesn't actually require rw because of
//!     // the `Cell`!
//!     holder.as_ref().open_ro(|_, thing| {
//!         thing.y.set(Some(&thing.get_ref().x));
//!     });
//!
//!     // Coerce to dyn Foo.
//!     let mut holder: Pin<&mut LCellEnvironment<IntrusiveLCellKey<dyn Foo>>> = holder;
//!
//!     // Run some rw/mut operations on it.
//!     holder.as_mut().open_rw(|owner, thing| {
//!         owner.rw(&thing.x).update();
//!     });
//!
//!     // Run some ro/ref operations on it
//!     holder.as_ref().open_ro(|owner, thing| {
//!         if let Some(y) = thing.y.get() {
//!             owner.ro(y).get();
//!         }
//!     });
//! }
//! ```

use qcell::LCellOwner;
use crate::{Builder, Holder, Opaque, OperateIn};

use core::pin::Pin;

/// A self-referential environment of `LCell`s, with zero runtime cost.
///
/// Wrapper around [`Holder`]. Like `Holder`, the lifetime may be anything.
///
/// # Examples
///
/// ```rust
/// use qcell::LCell;
/// 
/// use selfref::srce::LCellEnvironment;
/// use selfref::opaque;
///
/// struct Foo<'a> {
///     foo: LCell<'a, Option<&'a Foo<'a>>>,
/// }
///
/// struct FooKey;
/// opaque! {
///     impl Opaque for FooKey {
///         type Kind<'a> = Foo<'a>;
///     }
/// }
///
/// fn main() {
///     // We can use a closure here, but we need to give the compiler a hint.
///     let holder = LCellEnvironment::<'_, FooKey>::new_with(
///         |foo| foo.build(Foo { foo: LCell::new(Default::default()) })
///     );
/// }
/// ```
pub struct LCellEnvironment<'k, T: Opaque + 'k> {
    inner: Holder<'k, T>,
}

impl<'k, T> LCellEnvironment<'k, T> where T: Opaque {
    /// Creates a new `LCellEnvironment`.
    ///
    /// Works exactly like [`Holder::new_with`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use qcell::LCell;
    /// 
    /// use selfref::srce::LCellEnvironment;
    /// use selfref::opaque;
    ///
    /// struct Foo<'a> {
    ///     foo: LCell<'a, Option<&'a Foo<'a>>>,
    /// }
    ///
    /// struct FooKey;
    /// opaque! {
    ///     impl Opaque for FooKey {
    ///         type Kind<'a> = Foo<'a>;
    ///     }
    /// }
    ///
    /// fn main() {
    ///     // We can use a closure here, but we need to help the compiler.
    ///     let holder = LCellEnvironment::<'_, FooKey>::new_with(
    ///         |foo| foo.build(Foo { foo: LCell::new(Default::default()) })
    ///     );
    /// }
    /// ```
    pub fn new_with<F>(f: F) -> Self
    where
        F: for<'a> FnOnce(&mut Builder<'a, T>),
        T::Kind<'k>: Sized,
    {
        Self {
            inner: Holder::new_with(f)
        }
    }
}

impl<'k, T> LCellEnvironment<'k, T> where T: Opaque {
    /// Opens this LCellEnvironment for reading and writing (mutable).
    ///
    /// # Examples
    ///
    /// ```rust
    /// #![feature(pin_macro)]
    ///
    /// use qcell::LCell;
    /// use core::pin::pin;
    /// 
    /// use selfref::srce::LCellEnvironment;
    /// use selfref::opaque;
    ///
    /// struct Foo<'a> {
    ///     foo: LCell<'a, Option<&'a Foo<'a>>>,
    /// }
    ///
    /// struct FooKey;
    /// opaque! {
    ///     impl Opaque for FooKey {
    ///         type Kind<'a> = Foo<'a>;
    ///     }
    /// }
    ///
    /// fn main() {
    ///     let mut holder = pin!(LCellEnvironment::<'_, FooKey>::new_with(
    ///         |foo| foo.build(Foo { foo: LCell::new(Default::default()) })
    ///     ));
    ///     // Actually making our Foo refer to itself.
    ///     holder.as_mut().open_rw(
    ///         |owner, foo| {
    ///             *owner.rw(&foo.foo) = Some(foo.get_ref());
    ///         }
    ///     );
    /// }
    /// ```
    pub fn open_rw<'i, F, R>(self: Pin<&'i mut Self>, f: F) -> R
    where
        F: for<'a, 'id> FnOnce(&'a mut LCellOwner<'id>, OperateIn<'id, T>) -> R,
    {
        unsafe {
            self.map_unchecked_mut(|this| &mut this.inner)
        }.into_ref().operate_in(|env| {
            // SAFETY? we're still unsure if this is entirely sound!
            // the LCellOwner is owned by us, and the borrow given to the
            // closure is mutable if we're mutable, and shared if we're shared.
            // while this is mixing concerns ('id is being used for 2 different
            // things), it is also invariant as far as the owner is concerned,
            // and (for rw access), it is also unique.
            // thus, we tentatively consider this sound.
            // see https://users.rust-lang.org/t/soundness-review-request-srce-0-1/87587
            let guard = unsafe {
                generativity::Guard::new(generativity::Id::new())
            };
            f(&mut LCellOwner::new(guard), env)
        })
    }

    /// Opens this LCellEnvironment for reading only (shared).
    ///
    /// # Examples
    ///
    /// ```rust
    /// #![feature(pin_macro)]
    ///
    /// use qcell::LCell;
    /// use core::pin::pin;
    /// 
    /// use selfref::srce::LCellEnvironment;
    /// use selfref::opaque;
    ///
    /// struct Foo<'a> {
    ///     foo: LCell<'a, Option<&'a Foo<'a>>>,
    /// }
    ///
    /// struct FooKey;
    /// opaque! {
    ///     impl Opaque for FooKey {
    ///         type Kind<'a> = Foo<'a>;
    ///     }
    /// }
    ///
    /// fn main() {
    ///     let holder = pin!(LCellEnvironment::<'_, FooKey>::new_with(
    ///         |foo| foo.build(Foo { foo: LCell::new(Default::default()) })
    ///     ));
    ///     holder.as_ref().open_ro(
    ///         |owner, foo| {
    ///             // can't write to it
    ///             assert!(owner.ro(&foo.foo).is_none());
    ///         }
    ///     );
    /// }
    /// ```
    pub fn open_ro<'i, F, R>(self: Pin<&'i Self>, f: F) -> R
    where
        F: for<'a, 'id> FnOnce(&'a LCellOwner<'id>, OperateIn<'id, T>) -> R,
    {
        unsafe {
            self.map_unchecked(|this| &this.inner)
        }.operate_in(|env| {
            // SAFETY? we're still unsure if this is entirely sound!
            // the LCellOwner is owned by us, and the borrow given to the
            // closure is mutable if we're mutable, and shared if we're shared.
            // while this is mixing concerns ('id is being used for 2 different
            // things), it is also invariant as far as the owner is concerned.
            // thus, we tentatively consider this sound.
            // see https://users.rust-lang.org/t/soundness-review-request-srce-0-1/87587
            let guard = unsafe {
                generativity::Guard::new(generativity::Id::new())
            };
            f(&LCellOwner::new(guard), env)
        })
    }
}