// 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
#![cfg_attr(not(test), no_std)]
//! SRCE is a way to open and close an `LCellOwner`, thus allowing the use of
//! `LCell` with tokio.
//!
//! It is based on `qcell` and `selfref`.
//!
//! This crate has not been audited for soundness at this time.
use qcell::LCellOwner;
use selfref::{Builder, Holder, Opaque, OperateIn};
use core::pin::Pin;
/// A self-referential environment of `LCell`s, with zero runtime cost.
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`].
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).
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 actually unsure if this is 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.
let guard = unsafe {
generativity::Guard::new(generativity::Id::new())
};
f(&mut LCellOwner::new(guard), env)
})
}
/// Opens this LCellEnvironment for reading only (shared).
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 actually unsure if this is 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.
let guard = unsafe {
generativity::Guard::new(generativity::Id::new())
};
f(&LCellOwner::new(guard), env)
})
}
}
#[test]
fn test() {
use core::cell::Cell;
use core::marker::PhantomData;
use qcell::LCell;
trait Foo {
fn update(&mut self);
}
trait Bar {
fn get(&self) -> String;
}
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");
}
}
struct IntrusiveLCell<'a, T: ?Sized> {
y: Cell<Option<&'a LCell<'a, dyn Bar>>>,
x: LCell<'a, T>,
}
struct IntrusiveLCellKey<T: ?Sized>(PhantomData<T>);
selfref::opaque! {
impl[T: ?Sized] Opaque for IntrusiveLCellKey<T> {
type Kind<'this> = IntrusiveLCell<'this, T>;
}
}
let mut holder = Box::pin(
LCellEnvironment::<IntrusiveLCellKey<MyThing>>::new_with(|b| b.build(
IntrusiveLCell {
x: LCell::new(MyThing),
y: Cell::new(None),
}
))
);
holder.as_mut().open_rw(|owner, x| {
x.y.set(Some(&x.get_ref().x));
owner.rw(&x.x).update();
println!("{}", owner.ro(x.y.get().unwrap()).get());
});
let mut holder_dyn: Pin<Box<LCellEnvironment<IntrusiveLCellKey<dyn Foo>>>> = holder;
}