summaryrefslogtreecommitdiffstats
path: root/src/lib.rs
blob: 3004718022a1fd15eb0320d16c23603f51bcf4d7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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;
}