shadow_shim_helper_rs/rootedcell/
cell.rs

1use std::cell::UnsafeCell;
2
3use vasi::VirtualAddressSpaceIndependent;
4
5use super::{Root, Tag};
6
7/// Analagous to [std::cell::Cell]. In particular like [std::cell::Cell], it
8/// doesn't perform any atomic operations internally, making it relatively
9/// inexpensive.
10///
11/// Unlike [std::cell::Cell], this type is [Send] and [Sync] if `T` is
12/// [Send]. This is safe because the owner is required to prove access to the
13/// associated [Root], which is `![Sync]`, to access.
14#[derive(Debug, VirtualAddressSpaceIndependent)]
15#[repr(C)]
16pub struct RootedCell<T> {
17    tag: Tag,
18    val: UnsafeCell<T>,
19}
20
21impl<T> RootedCell<T> {
22    /// Create a RootedCell associated with `root`.
23    #[inline]
24    pub fn new(root: &Root, val: T) -> Self {
25        Self {
26            tag: root.tag(),
27            val: UnsafeCell::new(val),
28        }
29    }
30
31    #[inline]
32    pub fn get_mut(&mut self) -> &mut T {
33        // Since we have the only reference to `self`, we don't need to check the root.
34        unsafe { &mut *self.val.get() }
35    }
36
37    #[inline]
38    pub fn set(&self, root: &Root, val: T) {
39        // Replace the current value, and just drop the old value.
40        drop(self.replace(root, val))
41    }
42
43    #[inline]
44    pub fn replace(&self, root: &Root, val: T) -> T {
45        // Prove that the root is held for this tag.
46        assert_eq!(
47            root.tag, self.tag,
48            "Expected {:?} Got {:?}",
49            self.tag, root.tag
50        );
51
52        unsafe { self.val.get().replace(val) }
53    }
54
55    #[inline]
56    pub fn into_inner(self) -> T {
57        self.val.into_inner()
58    }
59}
60
61impl<T: Copy> RootedCell<T> {
62    #[inline]
63    pub fn get(&self, root: &Root) -> T {
64        // Prove that the root is held for this tag.
65        assert_eq!(
66            root.tag, self.tag,
67            "Expected {:?} Got {:?}",
68            self.tag, root.tag
69        );
70
71        unsafe { *self.val.get() }
72    }
73}
74
75unsafe impl<T: Send> Send for RootedCell<T> where T: Copy {}
76unsafe impl<T: Send> Sync for RootedCell<T> where T: Copy {}
77
78#[cfg(test)]
79mod test_rooted_cell {
80    use std::thread;
81
82    use super::*;
83    use crate::explicit_drop::ExplicitDrop;
84    use crate::rootedcell::rc::RootedRc;
85
86    #[test]
87    fn get() {
88        let root = Root::new();
89        let c = RootedCell::new(&root, 1);
90        assert_eq!(c.get(&root), 1);
91    }
92
93    #[test]
94    fn get_mut() {
95        let root = Root::new();
96        let mut c = RootedCell::new(&root, 1);
97        assert_eq!(*c.get_mut(), 1);
98    }
99
100    #[test]
101    fn set() {
102        let root = Root::new();
103        let c = RootedCell::new(&root, 1);
104        c.set(&root, 2);
105        assert_eq!(c.get(&root), 2);
106    }
107
108    #[test]
109    fn replace() {
110        let root = Root::new();
111        let c = RootedCell::new(&root, 1);
112        let old = c.replace(&root, 2);
113        assert_eq!(old, 1);
114        assert_eq!(c.get(&root), 2);
115    }
116
117    #[test]
118    fn share_with_worker_thread() {
119        let root = Root::new();
120        let rc = RootedRc::new(&root, RootedCell::new(&root, 0));
121        let root = {
122            let rc = { rc.clone(&root) };
123            thread::spawn(move || {
124                rc.set(&root, 3);
125                rc.explicit_drop(&root);
126                root
127            })
128            .join()
129            .unwrap()
130        };
131        assert_eq!(rc.get(&root), 3);
132        rc.explicit_drop(&root);
133    }
134
135    #[test]
136    fn worker_thread_get_mut() {
137        let root = Root::new();
138        let cell = RootedCell::new(&root, 0);
139        let cell = {
140            thread::spawn(move || {
141                // Move into closure and make mutable.
142                let mut cell = cell;
143                // Since we have a mutable reference, we don't
144                // need the root to access.
145                *cell.get_mut() = 3;
146                // Return cell to parent thread.
147                cell
148            })
149            .join()
150            .unwrap()
151        };
152        assert_eq!(cell.get(&root), 3);
153    }
154}