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
//! # safe\_cell
//!
//! This crate exports the `SafeCell` type, a wrapper type that enables safe
//! exterior mutability for arbitrary contents.
//!
//! The use case is similar to that of the standard library's
//! `UnsafeCell`[¹][unsafecell] type but, by virtue of being specialized for
//! situations where it can be statically proven that no unsound access
//! occurs, `SafeCell` is fully usable in safe code. In addition, the
//! implementation is easily proven to be fully sound, making `SafeCell` a
//! great alternative to `UnsafeCell` in safety-critical code.
//!
//! As the implementation is incredibly lightweight and does not make use of
//! any additional synchronization primitives or dynamic borrow tracking, it
//! has negligible overhead (and hence functions as a true "zero-cost
//! abstraction"[²][zerocost]).
//!
//! [unsafecell]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
//! [zerocost]: https://boats.gitlab.io/blog/post/zero-cost-abstractions/

/// The `SafeCell` type.
///
/// See the module-level documentation for more information.
#[derive(Debug, Clone, Default)]
pub struct SafeCell<T> {
    inner: T,
}

impl<T> SafeCell<T> {
    /// Returns a shared reference to the wrapped value.
    pub fn get(&self) -> &T {
        return &self.inner;
    }

    /// Returns a mutable reference to the wrapped value.
    ///
    /// Using this reference, the value can be safely mutated. Using the
    /// type-level mechanism provided by exterior mutability, `SafeCell`
    /// guarantees that no unsound concurrent access can occur.
    pub fn get_mut(&mut self) -> &mut T {
        // Safety: this is safe code.
        return &mut self.inner;
    }

    /// Extracts and returns the wrapped value.
    ///
    /// Note that this method must not be called concurrently, and once
    /// `into_inner` is called, references obtained by `get` and `get_mut`
    /// must no longer be used. This is statically ensured.
    pub fn into_inner(self) -> T {
        return self.inner;
    }

    /// Create a new `SafeCell`, enabling exterior mutability for the passed
    /// `value`.
    pub fn new(value: T) -> Self {
        return SafeCell {
            inner: value,
        };
    }
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::sync::{Arc, Mutex};
    use super::*;

    #[test]
    fn basic() {
        let mut cell = SafeCell::new(0);
        assert_eq!(cell.get(), &0);
        *cell.get_mut() += 1;
        assert_eq!(cell.get(), &1);

        let mut other_cell = cell.clone();
        *other_cell.get_mut() += 1;
        assert_eq!(other_cell.get(), &2);
        assert_eq!(cell.get(), &1);
        assert_eq!(cell.into_inner(), 1);
    }

    #[test]
    fn share() {
        let cell = Arc::new(Mutex::new(SafeCell::new(0)));
        let copy = cell.clone();

        let lock = cell.lock().unwrap();

        let a = {
            let cell = copy.clone();
            thread::spawn(move || {
                for _ in 0..10 {
                    *cell.lock().unwrap().get_mut() += 1;
                }
            })
        };

        let b = {
            let cell = copy.clone();
            thread::spawn(move || {
                for _ in 0..10 {
                    *cell.lock().unwrap().get_mut() += 2;
                }
            })
        };

        assert_eq!(lock.get(), &0);
        drop(lock);

        a.join().unwrap();
        b.join().unwrap();

        assert_eq!(cell.lock().unwrap().get(), &30);
    }
}