impl<T> Clone for Cell<Rc<T>>


#21

Maybe the problem is that Rust isn’t pure (= doesn’t have type of pure functions)? If we could require F to be pure then I think that would close off all of these tricks for sneakily accessing things through side channels, and then our Sync bounds would actually be sufficient.


#22

As has been pointed out in past discussions, “pure” means different things to different people. I’m not sure what the right definition of “pure” for this problem would be. Any of the variants implying referential transparency are a bit too strong to bea satisfactory solution (e.g., they rule out almost all uses of mutable references). Approaching it from the other end, merely “doesn’t access globals” is too weak because of re-entrant locks and similar things.


#23

This makes “cell-freeness” generic in which cell it is talking about (as in, “this particular cell”). The way I think about it (based on how this works in some concurrency logics, which have a similar problem of avoiding reentrancy) is that each cell has some “color” or “class” or however you want to call it. There’s some default class that is used when safe code just instantiates a cell, but unsafe code like Rc can declare its cells to be in a different class. Cell-safety for a class then means that no cell of that class is accessed.

Essentially, this is a static approximation making sure there no reference cycles are followed.

However, .is_none() should be sound with an arbitrary Cell<Option<T>>.


#24

Agreed.


#26

To be honest it is not hard to do on a newtyped Cell<Rc<T>>:

use std::cell::Cell;
use std::rc::Rc;

struct CellRc<T>(Cell<Rc<T>>);

impl<T> Clone for CellRc<T> {
    fn clone(&self) -> Self {
        unsafe {
            CellRc(Cell::new((*self.0.as_ptr()).clone()))
        }
    }
}
impl CellRc {
    fn new(t: T) -> Self {
        Self(Cell::new(Rc::new(t)))
    }
}

fn main() {
    let c = CellRc::new(10);
    let g = c.clone();
}

or have a free function

pub fn clone_cell_rc<T>(t: &Cell<Rc<T>>) -> Cell<Rc<T>> {
    unsafe {
        Cell::new((*t.as_ptr()).clone())
    }
}

in general we can do

pub fn clone_cell<T: Clone>(t: &Cell<T>) -> Cell<T> {
    unsafe {
        Cell::new((*t.as_ptr()).clone())
    }
}

But we need to justify the unsafe block above.