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