// 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>>, //! x: LCell<'a, T>, //! } //! // The "key" or "kind" struct for `selfref` to do the magic. //! struct IntrusiveLCellKey(PhantomData); //! selfref::opaque! { //! impl[T: ?Sized] Opaque for IntrusiveLCellKey { //! type Kind<'this> = IntrusiveLCell<'this, T>; //! } //! } //! //! fn main() { //! // Create the holder //! let mut holder = pin!( //! LCellEnvironment::>::new_with( //! |thing| thing.build(IntrusiveLCell { //! y: Cell::new(None), //! x: LCell::new(MyThing), //! }) //! ) //! ); //! //! // Create the `&LCell`. 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>> = 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) -> 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) }) } }