use core::cell::UnsafeCell;
use core::marker::PhantomData;
use super::Invariant;
type Id<'id> = PhantomData<Invariant<&'id ()>>;
pub struct LCellOwner<'id> {
_id: Id<'id>,
}
impl<'id> LCellOwner<'id> {
pub fn scope<F>(f: F)
where
F: for<'scope_id> FnOnce(LCellOwner<'scope_id>),
{
f(Self { _id: PhantomData })
}
#[cfg(feature = "generativity")]
#[cfg_attr(docsrs, doc(cfg(feature = "generativity")))]
pub fn new(_guard: generativity::Guard<'id>) -> Self {
Self { _id: PhantomData }
}
pub fn cell<T>(&self, value: T) -> LCell<'id, T> {
LCell::<T>::new(value)
}
#[inline]
pub fn ro<'a, T: ?Sized>(&'a self, lc: &'a LCell<'id, T>) -> &'a T {
unsafe { &*lc.value.get() }
}
#[inline]
pub fn rw<'a, T: ?Sized>(&'a mut self, lc: &'a LCell<'id, T>) -> &'a mut T {
unsafe { &mut *lc.value.get() }
}
#[inline]
pub fn rw2<'a, T: ?Sized, U: ?Sized>(
&'a mut self,
lc1: &'a LCell<'id, T>,
lc2: &'a LCell<'id, U>,
) -> (&'a mut T, &'a mut U) {
assert!(
!core::ptr::eq(lc1 as *const _ as *const (), lc2 as *const _ as *const ()),
"Illegal to borrow same LCell twice with rw2()"
);
unsafe { (&mut *lc1.value.get(), &mut *lc2.value.get()) }
}
#[inline]
pub fn rw3<'a, T: ?Sized, U: ?Sized, V: ?Sized>(
&'a mut self,
lc1: &'a LCell<'id, T>,
lc2: &'a LCell<'id, U>,
lc3: &'a LCell<'id, V>,
) -> (&'a mut T, &'a mut U, &'a mut V) {
assert!(
!core::ptr::eq(lc1 as *const _ as *const (), lc2 as *const _ as *const ())
&& !core::ptr::eq(lc2 as *const _ as *const (), lc3 as *const _ as *const ())
&& !core::ptr::eq(lc3 as *const _ as *const (), lc1 as *const _ as *const ()),
"Illegal to borrow same LCell twice with rw3()"
);
unsafe {
(
&mut *lc1.value.get(),
&mut *lc2.value.get(),
&mut *lc3.value.get(),
)
}
}
}
#[repr(transparent)]
pub struct LCell<'id, T: ?Sized> {
_id: Id<'id>,
value: UnsafeCell<T>,
}
impl<'id, T> LCell<'id, T> {
#[inline]
pub fn new(value: T) -> LCell<'id, T> {
LCell {
_id: PhantomData,
value: UnsafeCell::new(value),
}
}
#[inline]
pub fn into_inner(self) -> T {
self.value.into_inner()
}
}
impl<'id, T: ?Sized> LCell<'id, T> {
#[inline]
pub fn ro<'a>(&'a self, owner: &'a LCellOwner<'id>) -> &'a T {
owner.ro(self)
}
#[inline]
pub fn rw<'a>(&'a self, owner: &'a mut LCellOwner<'id>) -> &'a mut T {
owner.rw(self)
}
#[inline]
pub fn get_mut(&mut self) -> &mut T {
self.value.get_mut()
}
}
impl<'id, T: Default> Default for LCell<'id, T> {
fn default() -> Self {
LCell::new(T::default())
}
}
unsafe impl<'id, T: Send + Sync + ?Sized> Sync for LCell<'id, T> {}
#[cfg(test)]
mod tests {
use super::{LCell, LCellOwner};
use std::rc::Rc;
#[test]
fn lcell() {
LCellOwner::scope(|mut owner| {
let c1 = LCell::new(100u32);
let c2 = owner.cell(200u32);
(*owner.rw(&c1)) += 1;
(*owner.rw(&c2)) += 2;
let c1ref = owner.ro(&c1);
let c2ref = owner.ro(&c2);
let total = *c1ref + *c2ref;
assert_eq!(total, 303);
});
}
#[test]
#[cfg(feature = "generativity")]
fn generativity() {
generativity::make_guard!(guard);
let mut owner = LCellOwner::new(guard);
let c1 = LCell::new(100_u32);
let c2 = LCell::new(200_u32);
(*owner.rw(&c1)) += 1;
(*owner.rw(&c2)) += 2;
let c1ref = owner.ro(&c1);
let c2ref = owner.ro(&c2);
let total = *c1ref + *c2ref;
assert_eq!(total, 303);
}
#[test]
#[should_panic]
fn lcell_rw2() {
LCellOwner::scope(|mut owner| {
let c1 = Rc::new(LCell::new(100u32));
let (mutref1, mutref2) = owner.rw2(&c1, &c1);
*mutref1 += 1;
*mutref2 += 1;
});
}
#[test]
#[should_panic]
fn lcell_rw3_1() {
LCellOwner::scope(|mut owner| {
let c1 = Rc::new(LCell::new(100u32));
let c2 = Rc::new(LCell::new(200u32));
let (mutref1, mutref2, mutref3) = owner.rw3(&c1, &c1, &c2);
*mutref1 += 1;
*mutref2 += 1;
*mutref3 += 1;
});
}
#[test]
#[should_panic]
fn lcell_rw3_2() {
LCellOwner::scope(|mut owner| {
let c1 = Rc::new(LCell::new(100u32));
let c2 = Rc::new(LCell::new(200u32));
let (mutref1, mutref2, mutref3) = owner.rw3(&c1, &c2, &c1);
*mutref1 += 1;
*mutref2 += 1;
*mutref3 += 1;
});
}
#[test]
#[should_panic]
fn lcell_rw3_3() {
LCellOwner::scope(|mut owner| {
let c1 = Rc::new(LCell::new(100u32));
let c2 = Rc::new(LCell::new(200u32));
let (mutref1, mutref2, mutref3) = owner.rw3(&c2, &c1, &c1);
*mutref1 += 1;
*mutref2 += 1;
*mutref3 += 1;
});
}
#[test]
fn lcell_get_mut() {
LCellOwner::scope(|owner| {
let mut cell = LCell::new(100u32);
let mut_ref = cell.get_mut();
*mut_ref = 50;
let cell_ref = owner.ro(&cell);
assert_eq!(*cell_ref, 50);
});
}
#[test]
fn lcell_into_inner() {
let cell = LCell::new(100u32);
assert_eq!(cell.into_inner(), 100);
}
#[test]
fn lcell_unsized() {
LCellOwner::scope(|mut owner| {
struct Squares(u32);
struct Integers(u64);
trait Series {
fn step(&mut self);
fn value(&self) -> u64;
}
impl Series for Squares {
fn step(&mut self) {
self.0 += 1;
}
fn value(&self) -> u64 {
(self.0 as u64) * (self.0 as u64)
}
}
impl Series for Integers {
fn step(&mut self) {
self.0 += 1;
}
fn value(&self) -> u64 {
self.0
}
}
fn series<'id>(init: u32, is_squares: bool) -> Box<LCell<'id, dyn Series>> {
if is_squares {
Box::new(LCell::new(Squares(init)))
} else {
Box::new(LCell::new(Integers(init as u64)))
}
}
let own = &mut owner;
let cell1 = series(4, false);
let cell2 = series(7, true);
let cell3 = series(3, true);
assert_eq!(cell1.ro(own).value(), 4);
cell1.rw(own).step();
assert_eq!(cell1.ro(own).value(), 5);
assert_eq!(own.ro(&cell2).value(), 49);
own.rw(&cell2).step();
assert_eq!(own.ro(&cell2).value(), 64);
let (r1, r2, r3) = own.rw3(&cell1, &cell2, &cell3);
r1.step();
r2.step();
r3.step();
assert_eq!(cell1.ro(own).value(), 6);
assert_eq!(cell2.ro(own).value(), 81);
assert_eq!(cell3.ro(own).value(), 16);
let (r1, r2) = own.rw2(&cell1, &cell2);
r1.step();
r2.step();
assert_eq!(cell1.ro(own).value(), 7);
assert_eq!(cell2.ro(own).value(), 100);
});
}
}