alexcrichton · GitHub

@alexcrichton I meant this:

impl<T> MoveCell<Option<T>> {
    #[inline]
    pub fn is_none(&self) -> bool {
        unsafe {
            (*self.0.get()).is_none()
        }
    }
    #[inline]
    pub fn take(&self) -> Option<T> {
        unsafe {
            (*self.0.get()).take()
        }
    }
}
impl<T> MoveCell<Option<Weak<T>>> {
    #[inline]
    pub fn upgrade(&self) -> Option<Rc<T>> {
        unsafe {
            match *self.0.get() {
                Some(ref weak) => weak.upgrade(),
                None => None,
            }
        }
    }
}
impl<T> MoveCell<Option<Rc<T>>> {
    /// Return `Some` if this `Rc` is the only strong reference count,
    /// even if there are weak references.
    #[inline]
    pub fn take_if_unique_strong(&self) -> Option<Rc<T>> {
        unsafe {
            match *self.0.get() {
                None => None,
                Some(ref rc) if Rc::strong_count(rc) > 1 => None,
                // Not borrowing the `Rc<T>` here
                // as we would be invalidating that borrow while it is outstanding:
                Some(_) => self.take(),
            }
        }
    }
}

Coherence rules would not allow me to write these impls with a MoveCell defined in the standard library (and they’re specific-purpose enough that they don’t necessarily make sense to define in the standard library). But now that I think about it, I could define extension traits that use as_unsafe_cell.

By the way, the key to these method’s safety is that they’re known not to exercise the cell’s interior mutability (e.g. through reference cycles) while a &T reference to the inside of the cell exists. Another example is:

impl<T> MoveCell<T> where T: WellBehavedClone {
    #[inline]
    pub fn clone_inner(&self) -> T {
        unsafe {
            (*self.0.get()).clone()
        }
    }
}
/**
    A Clone impl that will not access the cell again through reference cycles,
    which would introduce mutable aliasing.
    Incorrect example:
    ```rust
    struct Evil(Box<u32>, Rc<MoveCell<Option<Evil>>>);
    impl Clone for Evil {
        fn clone(&self) -> Self {
            mem::drop(self.1.take());  // Mess with the "other" node, which might be `self`.
            Evil(
                self.0.clone(),  // use after free!
                Rc::new(MoveCell::new(None))
            )
        }
    }
    unsafe impl WellBehavedClone for Evil {}  // Wrong.
    let a = Rc::new(MoveCell::new(None));
    a.set(Some(Evil(Box::new(5), a.clone())));  // Make a reference cycle.
    a.clone_inner();
    ```
*/
pub unsafe trait WellBehavedClone: Clone {}
unsafe impl<T> WellBehavedClone for Rc<T> {}
unsafe impl<T> WellBehavedClone for Weak<T> {}
unsafe impl<T> WellBehavedClone for Option<T> where T: WellBehavedClone {}

In this case T::clone can have arbitrary behavior as far as this module is concern, so we add a bound on an unsafe trait.

Read the original on github.com ↗