// 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)
})
}
}