diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..3004718 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,129 @@ +// 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; +} |