From 55161ce3c7a5487b0ed8597e9daa50261b549489 Mon Sep 17 00:00:00 2001 From: SoniEx2 Date: Sat, 14 Jan 2023 01:08:09 -0300 Subject: [Project] Self-Ref Cell Environment Possibly-unsound extensions to `selfref` --- .gitignore | 2 + Cargo.toml | 20 ++++++++++ README.md | 8 ++++ src/lib.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9444bf9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "srce" +version = "0.1.0" +authors = ["SoniEx2 "] +edition = "2021" +description = "Self-Ref Cell Environments" +license = "MIT OR Apache-2.0" +repository = "https://soniex2.autistic.space/git-repos/srce.git" +categories = ["no-std", "rust-patterns"] +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +selfref = "0.4" +qcell = {version="0.5.2", default-features=false, features=["generativity"]} +generativity = "1.0.1" + +[dev-dependencies] +selfref = {features=["alloc"]} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5decae9 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Self-Ref Cell Environment (SRCE) + +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. 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) -> 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; +} -- cgit v1.2.3