qcell/
tlcell.rs

1use std::any::TypeId;
2use std::cell::UnsafeCell;
3use std::collections::HashSet;
4use std::marker::PhantomData;
5
6use super::Invariant;
7
8std::thread_local! {
9    static SINGLETON_CHECK: std::cell::RefCell<HashSet<TypeId>> = std::cell::RefCell::new(HashSet::new());
10}
11
12struct NotSendOrSync(*const ());
13
14/// Borrowing-owner of zero or more [`TLCell`](struct.TLCell.html)
15/// instances.
16///
17/// See [crate documentation](index.html).
18#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
19pub struct TLCellOwner<Q: 'static> {
20    // Use NotSendOrSync to disable Send and Sync,
21    not_send_or_sync: PhantomData<NotSendOrSync>,
22    // Use Invariant<Q> for invariant parameter
23    typ: PhantomData<Invariant<Q>>,
24}
25
26impl<Q: 'static> Drop for TLCellOwner<Q> {
27    fn drop(&mut self) {
28        SINGLETON_CHECK.with(|set| set.borrow_mut().remove(&TypeId::of::<Q>()));
29    }
30}
31
32impl<Q: 'static> Default for TLCellOwner<Q> {
33    fn default() -> Self {
34        TLCellOwner::new()
35    }
36}
37
38impl<Q: 'static> TLCellOwner<Q> {
39    /// Create the singleton owner instance.  Each owner may be used
40    /// to create many `TLCell` instances.  There may be only one
41    /// instance of this type per thread at any given time for each
42    /// different marker type `Q`.  This call panics if a second
43    /// simultaneous instance is created.  Since the owner is only
44    /// valid to use in the thread it is created in, it does not
45    /// support `Send` or `Sync`.
46    pub fn new() -> Self {
47        SINGLETON_CHECK.with(|set| {
48            assert!(set.borrow_mut().insert(TypeId::of::<Q>()),
49                    "Illegal to create two TLCellOwner instances within the same thread with the same marker type parameter");
50        });
51        Self {
52            not_send_or_sync: PhantomData,
53            typ: PhantomData,
54        }
55    }
56
57    /// Create a new cell owned by this owner instance.  See also
58    /// [`TLCell::new`].
59    ///
60    /// [`TLCell::new`]: struct.TLCell.html
61    pub fn cell<T>(&self, value: T) -> TLCell<Q, T> {
62        TLCell::<Q, T>::new(value)
63    }
64
65    /// Borrow contents of a `TLCell` immutably (read-only).  Many
66    /// `TLCell` instances can be borrowed immutably at the same time
67    /// from the same owner.
68    #[inline]
69    pub fn ro<'a, T: ?Sized>(&'a self, tc: &'a TLCell<Q, T>) -> &'a T {
70        unsafe { &*tc.value.get() }
71    }
72
73    /// Borrow contents of a `TLCell` mutably (read-write).  Only one
74    /// `TLCell` at a time can be borrowed from the owner using this
75    /// call.  The returned reference must go out of scope before
76    /// another can be borrowed.
77    #[inline]
78    pub fn rw<'a, T: ?Sized>(&'a mut self, tc: &'a TLCell<Q, T>) -> &'a mut T {
79        unsafe { &mut *tc.value.get() }
80    }
81
82    /// Borrow contents of two `TLCell` instances mutably.  Panics if
83    /// the two `TLCell` instances point to the same memory.
84    #[inline]
85    pub fn rw2<'a, T: ?Sized, U: ?Sized>(
86        &'a mut self,
87        tc1: &'a TLCell<Q, T>,
88        tc2: &'a TLCell<Q, U>,
89    ) -> (&'a mut T, &'a mut U) {
90        assert!(
91            tc1 as *const _ as *const () as usize != tc2 as *const _ as *const () as usize,
92            "Illegal to borrow same TLCell twice with rw2()"
93        );
94        unsafe { (&mut *tc1.value.get(), &mut *tc2.value.get()) }
95    }
96
97    /// Borrow contents of three `TLCell` instances mutably.  Panics if
98    /// any pair of `TLCell` instances point to the same memory.
99    #[inline]
100    pub fn rw3<'a, T: ?Sized, U: ?Sized, V: ?Sized>(
101        &'a mut self,
102        tc1: &'a TLCell<Q, T>,
103        tc2: &'a TLCell<Q, U>,
104        tc3: &'a TLCell<Q, V>,
105    ) -> (&'a mut T, &'a mut U, &'a mut V) {
106        assert!(
107            (tc1 as *const _ as *const () as usize != tc2 as *const _ as *const () as usize)
108                && (tc2 as *const _ as *const () as usize != tc3 as *const _ as *const () as usize)
109                && (tc3 as *const _ as *const () as usize != tc1 as *const _ as *const () as usize),
110            "Illegal to borrow same TLCell twice with rw3()"
111        );
112        unsafe {
113            (
114                &mut *tc1.value.get(),
115                &mut *tc2.value.get(),
116                &mut *tc3.value.get(),
117            )
118        }
119    }
120}
121
122/// Cell whose contents is owned (for borrowing purposes) by a
123/// [`TLCellOwner`].
124///
125/// To borrow from this cell, use the borrowing calls on the
126/// [`TLCellOwner`] instance that shares the same marker type.  Since
127/// there may be another indistinguishable [`TLCellOwner`] in another
128/// thread, `Sync` is not supported for this type.  However it *is*
129/// possible to send the cell to another thread, which then allows its
130/// contents to be borrowed using the owner in that thread.
131///
132/// See also [crate documentation](index.html).
133///
134/// [`TLCellOwner`]: struct.TLCellOwner.html
135#[repr(transparent)]
136#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
137pub struct TLCell<Q, T: ?Sized> {
138    // Use Invariant<Q> for invariant parameter
139    owner: PhantomData<Invariant<Q>>,
140
141    // TLCell absolutely cannot be Sync, since otherwise you could send
142    // two &TLCell's to two different threads, that each have their own
143    // TLCellOwner<Q> instance and that could therefore both give out
144    // a &mut T to the same T.
145    //
146    // However, it's fine to Send a TLCell to a different thread, because
147    // you can only send something if nothing borrows it, so nothing can
148    // be accessing its contents. After sending the TLCell, the original
149    // TLCellOwner can no longer give access to the TLCell's contents since
150    // TLCellOwner is !Send + !Sync. Only the TLCellOwner of the new thread
151    // can give access to this TLCell's contents now.
152    //
153    // `UnsafeCell` already disables `Sync` and gives the right `Send` implementation.
154    value: UnsafeCell<T>,
155}
156
157impl<Q, T> TLCell<Q, T> {
158    /// Create a new `TLCell` owned for borrowing purposes by the
159    /// `TLCellOwner` derived from the same marker type `Q`.
160    #[inline]
161    pub const fn new(value: T) -> TLCell<Q, T> {
162        TLCell {
163            owner: PhantomData,
164            value: UnsafeCell::new(value),
165        }
166    }
167
168    /// Destroy the cell and return the contained value
169    ///
170    /// Safety: Since this consumes the cell, there can be no other
171    /// references to the cell or the data at this point.
172    #[inline]
173    pub fn into_inner(self) -> T {
174        self.value.into_inner()
175    }
176}
177
178impl<Q, T: ?Sized> TLCell<Q, T> {
179    /// Borrow contents of this cell immutably (read-only).  Many
180    /// `TLCell` instances can be borrowed immutably at the same time
181    /// from the same owner.
182    #[inline]
183    pub fn ro<'a>(&'a self, owner: &'a TLCellOwner<Q>) -> &'a T {
184        owner.ro(self)
185    }
186
187    /// Borrow contents of this cell mutably (read-write).  Only one
188    /// `TLCell` at a time can be borrowed from the owner using this
189    /// call.  The returned reference must go out of scope before
190    /// another can be borrowed.  To mutably borrow from two or three
191    /// cells at the same time, see [`TLCellOwner::rw2`] or
192    /// [`TLCellOwner::rw3`].
193    #[inline]
194    pub fn rw<'a>(&'a self, owner: &'a mut TLCellOwner<Q>) -> &'a mut T {
195        owner.rw(self)
196    }
197
198    /// Returns a mutable reference to the underlying data
199    ///
200    /// Note that this is only useful at the beginning-of-life or
201    /// end-of-life of the cell when you have exclusive access to it.
202    /// Normally you'd use [`TLCell::rw`] or [`TLCellOwner::rw`] to
203    /// get a mutable reference to the contents of the cell.
204    ///
205    /// Safety: This call borrows `TLCell` mutably which guarantees
206    /// that we possess the only reference.  This means that there can
207    /// be no active borrows of other forms, even ones obtained using
208    /// an immutable reference.
209    #[inline]
210    pub fn get_mut(&mut self) -> &mut T {
211        self.value.get_mut()
212    }
213}
214
215impl<Q: 'static, T: Default + ?Sized> Default for TLCell<Q, T> {
216    fn default() -> Self {
217        TLCell::new(T::default())
218    }
219}
220
221#[cfg(test)]
222mod tests {
223    use super::{TLCell, TLCellOwner};
224
225    #[test]
226    #[should_panic]
227    fn tlcell_singleton_1() {
228        struct Marker;
229        let _owner1 = TLCellOwner::<Marker>::new();
230        let _owner2 = TLCellOwner::<Marker>::new(); // Panic here
231    }
232
233    #[test]
234    fn tlcell_singleton_2() {
235        struct Marker;
236        let owner1 = TLCellOwner::<Marker>::new();
237        drop(owner1);
238        let _owner2 = TLCellOwner::<Marker>::new();
239    }
240
241    #[test]
242    fn tlcell_singleton_3() {
243        struct Marker1;
244        struct Marker2;
245        let _owner1 = TLCellOwner::<Marker1>::new();
246        let _owner2 = TLCellOwner::<Marker2>::new();
247    }
248
249    #[test]
250    fn tlcell() {
251        struct Marker;
252        type ACellOwner = TLCellOwner<Marker>;
253        type ACell<T> = TLCell<Marker, T>;
254        let mut owner = ACellOwner::new();
255        let c1 = ACell::new(100u32);
256        let c2 = owner.cell(200u32);
257        (*owner.rw(&c1)) += 1;
258        (*owner.rw(&c2)) += 2;
259        let c1ref = owner.ro(&c1);
260        let c2ref = owner.ro(&c2);
261        let total = *c1ref + *c2ref;
262        assert_eq!(total, 303);
263    }
264
265    #[test]
266    fn tlcell_threads() {
267        struct Marker;
268        type ACellOwner = TLCellOwner<Marker>;
269        let mut _owner1 = ACellOwner::new();
270        std::thread::spawn(|| {
271            let mut _owner2 = ACellOwner::new();
272        })
273        .join()
274        .unwrap();
275    }
276
277    #[test]
278    fn tlcell_get_mut() {
279        struct Marker;
280        type ACellOwner = TLCellOwner<Marker>;
281        type ACell<T> = TLCell<Marker, T>;
282        let owner = ACellOwner::new();
283        let mut cell = ACell::new(100u32);
284        let mut_ref = cell.get_mut();
285        *mut_ref = 50;
286        let cell_ref = owner.ro(&cell);
287        assert_eq!(*cell_ref, 50);
288    }
289
290    #[test]
291    fn tlcell_into_inner() {
292        struct Marker;
293        type ACell<T> = TLCell<Marker, T>;
294        let cell = ACell::new(100u32);
295        assert_eq!(cell.into_inner(), 100);
296    }
297
298    #[test]
299    fn tlcell_unsized() {
300        struct Marker;
301        type ACellOwner = TLCellOwner<Marker>;
302        type ACell<T> = TLCell<Marker, T>;
303        let mut owner = ACellOwner::new();
304        struct Squares(u32);
305        struct Integers(u64);
306        trait Series {
307            fn step(&mut self);
308            fn value(&self) -> u64;
309        }
310        impl Series for Squares {
311            fn step(&mut self) {
312                self.0 += 1;
313            }
314            fn value(&self) -> u64 {
315                (self.0 as u64) * (self.0 as u64)
316            }
317        }
318        impl Series for Integers {
319            fn step(&mut self) {
320                self.0 += 1;
321            }
322            fn value(&self) -> u64 {
323                self.0
324            }
325        }
326        fn series(init: u32, is_squares: bool) -> Box<ACell<dyn Series>> {
327            if is_squares {
328                Box::new(ACell::new(Squares(init)))
329            } else {
330                Box::new(ACell::new(Integers(init as u64)))
331            }
332        }
333
334        let own = &mut owner;
335        let cell1 = series(4, false);
336        let cell2 = series(7, true);
337        let cell3 = series(3, true);
338        assert_eq!(cell1.ro(own).value(), 4);
339        cell1.rw(own).step();
340        assert_eq!(cell1.ro(own).value(), 5);
341        assert_eq!(own.ro(&cell2).value(), 49);
342        own.rw(&cell2).step();
343        assert_eq!(own.ro(&cell2).value(), 64);
344        let (r1, r2, r3) = own.rw3(&cell1, &cell2, &cell3);
345        r1.step();
346        r2.step();
347        r3.step();
348        assert_eq!(cell1.ro(own).value(), 6);
349        assert_eq!(cell2.ro(own).value(), 81);
350        assert_eq!(cell3.ro(own).value(), 16);
351        let (r1, r2) = own.rw2(&cell1, &cell2);
352        r1.step();
353        r2.step();
354        assert_eq!(cell1.ro(own).value(), 7);
355        assert_eq!(cell2.ro(own).value(), 100);
356    }
357}