// 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) -> 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>>, x: LCell<'a, T>, } struct IntrusiveLCellKey(PhantomData); selfref::opaque! { impl[T: ?Sized] Opaque for IntrusiveLCellKey { type Kind<'this> = IntrusiveLCell<'this, T>; } } let mut holder = Box::pin( LCellEnvironment::>::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>>> = holder; }