qcell/
tcell.rs

1#[cfg(any(feature = "std", feature = "exclusion-set"))]
2use core::any::TypeId;
3use core::cell::UnsafeCell;
4use core::marker::PhantomData;
5#[cfg(all(feature = "std", not(feature = "exclusion-set")))]
6use once_cell::sync::Lazy;
7#[cfg(all(feature = "std", not(feature = "exclusion-set")))]
8use std::{
9    collections::HashSet,
10    sync::{Condvar, Mutex},
11};
12
13use super::Invariant;
14
15#[cfg(all(feature = "std", not(feature = "exclusion-set")))]
16static SINGLETON_CHECK: Lazy<Mutex<HashSet<TypeId>>> = Lazy::new(|| Mutex::new(HashSet::new()));
17#[cfg(all(feature = "std", not(feature = "exclusion-set")))]
18static SINGLETON_CHECK_CONDVAR: Lazy<Condvar> = Lazy::new(Condvar::new);
19#[cfg(feature = "exclusion-set")]
20static SINGLETON_CHECK_SET: exclusion_set::Set<TypeId> = exclusion_set::Set::new();
21
22/// Borrowing-owner of zero or more [`TCell`](struct.TCell.html)
23/// instances.
24///
25/// See [crate documentation](index.html).
26pub struct TCellOwner<Q: 'static> {
27    // Allow Send and Sync, and Q is invariant
28    typ: PhantomData<Invariant<Q>>,
29}
30
31impl<Q: 'static> Drop for TCellOwner<Q> {
32    #[cfg(all(feature = "std", not(feature = "exclusion-set")))]
33    fn drop(&mut self) {
34        // Remove the TypeId of Q from the HashSet, indicating that
35        // no more instances of TCellOwner<Q> exist.
36        SINGLETON_CHECK.lock().unwrap().remove(&TypeId::of::<Q>());
37
38        // Wake up all threads waiting in TCellOwner::wait_for_new()
39        // to check if their Q was removed from the HashSet.
40        SINGLETON_CHECK_CONDVAR.notify_all();
41    }
42
43    #[cfg(feature = "exclusion-set")]
44    fn drop(&mut self) {
45        // Remove the TypeId of Q from the Set, indicating that
46        // no more instances of TCellOwner<Q> exist.
47        // SAFETY: the precondition of remove is satisfied since
48        // this can be the only TCellOwner for a given Q.
49        unsafe {
50            SINGLETON_CHECK_SET.remove(&TypeId::of::<Q>());
51        }
52    }
53
54    #[cfg(not(any(feature = "std", feature = "exclusion-set")))]
55    fn drop(&mut self) {
56        // constructors should be unavailable with this feature set, so the
57        // destructor should be unreachable
58        unreachable!()
59    }
60}
61
62#[cfg(any(feature = "std", feature = "exclusion-set"))]
63#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "exclusion-set"))))]
64impl<Q: 'static> Default for TCellOwner<Q> {
65    fn default() -> Self {
66        TCellOwner::new()
67    }
68}
69
70impl<Q: 'static> TCellOwner<Q> {
71    /// Create the singleton owner instance.  Each owner may be used
72    /// to create many `TCell` instances.  There may be only one
73    /// instance of this type per process at any given time for each
74    /// different marker type `Q`.  This call panics if a second
75    /// simultaneous instance is created.
76    ///
77    /// Keep in mind that in Rust, tests are run in parallel unless
78    /// specified otherwise (using e.g. `RUST_TEST_THREADS`), so
79    /// this panic may be more easy to trigger than you might think.
80    /// To avoid this panic, consider using the methods
81    #[cfg_attr(feature = "std", doc = "[`TCellOwner::wait_for_new`]")]
82    #[cfg_attr(not(feature = "std"), doc = "`TCellOwner::wait_for_new`")]
83    /// or [`TCellOwner::try_new`] instead.
84    #[cfg(any(feature = "std", feature = "exclusion-set"))]
85    #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "exclusion-set"))))]
86    pub fn new() -> Self {
87        if let Some(owner) = TCellOwner::try_new() {
88            owner
89        } else {
90            panic!("Illegal to create two TCellOwner instances with the same marker type parameter")
91        }
92    }
93
94    /// Same as [`TCellOwner::new`], except if another `TCellOwner`
95    /// of this type `Q` already exists, this returns `None` instead
96    /// of panicking.
97    #[cfg(all(feature = "std", not(feature = "exclusion-set")))]
98    pub fn try_new() -> Option<Self> {
99        if SINGLETON_CHECK.lock().unwrap().insert(TypeId::of::<Q>()) {
100            Some(Self { typ: PhantomData })
101        } else {
102            None
103        }
104    }
105
106    /// Same as [`TCellOwner::new`], except if another `TCellOwner`
107    /// of this type `Q` already exists, this returns `None` instead
108    /// of panicking.
109    #[cfg(feature = "exclusion-set")]
110    #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "exclusion-set"))))]
111    pub fn try_new() -> Option<Self> {
112        if SINGLETON_CHECK_SET.try_insert(TypeId::of::<Q>()) {
113            Some(Self { typ: PhantomData })
114        } else {
115            None
116        }
117    }
118
119    /// Same as [`TCellOwner::new`], except if another `TCellOwner`
120    /// of this type `Q` already exists, this function blocks the thread
121    /// until that other instance is dropped.  This will of course deadlock
122    /// if that other instance is owned by the same thread.
123    ///
124    /// Note that owners are expected to be relatively long-lived.  If
125    /// you need to access cells associated with a given marker type
126    /// from several different threads, the most efficient pattern is
127    /// to have a single long-lived owner shared between threads, with
128    /// a `Mutex` or `RwLock` to control access.  This call is
129    /// intended to help when several independent tests need to run
130    /// which use the same marker type internally.
131    #[cfg(all(feature = "std", not(feature = "exclusion-set")))]
132    pub fn wait_for_new() -> Self {
133        // Lock the HashSet mutex.
134        let hashset_guard = SINGLETON_CHECK.lock().unwrap();
135
136        // If the HashSet already contains the TypeId of Q, there is
137        // another TCellOwner. Block the thread until it gets dropped.
138        // (the HashSet mutex is unlocked while waiting)
139        let mut hashset_guard = SINGLETON_CHECK_CONDVAR
140            .wait_while(hashset_guard, |hashset| {
141                hashset.contains(&TypeId::of::<Q>())
142            })
143            .unwrap();
144
145        // If we get here, no other TCellOwner of this type exists.
146        // Return a new TCellOwner.  When dropped, it will remove the
147        // TypeId of Q from the HashSet, and notify all waiting threads.
148        let inserted = hashset_guard.insert(TypeId::of::<Q>());
149        assert!(inserted);
150        Self { typ: PhantomData }
151    }
152
153    /// Same as [`TCellOwner::new`], except if another `TCellOwner`
154    /// of this type `Q` already exists, this function blocks the thread
155    /// until that other instance is dropped.  This will of course deadlock
156    /// if that other instance is owned by the same thread.
157    ///
158    /// Note that owners are expected to be relatively long-lived.  If
159    /// you need to access cells associated with a given marker type
160    /// from several different threads, the most efficient pattern is
161    /// to have a single long-lived owner shared between threads, with
162    /// a `Mutex` or `RwLock` to control access.  This call is
163    /// intended to help when several independent tests need to run
164    /// which use the same marker type internally.
165    #[cfg(all(feature = "std", feature = "exclusion-set"))]
166    #[cfg_attr(
167        docsrs,
168        doc(cfg(any(feature = "std", all(feature = "exclusion-set", feature = "std"))))
169    )]
170    pub fn wait_for_new() -> Self {
171        SINGLETON_CHECK_SET.wait_to_insert(TypeId::of::<Q>());
172        Self { typ: PhantomData }
173    }
174
175    /// Create a new cell owned by this owner instance.  See also
176    /// [`TCell::new`].
177    ///
178    /// [`TCell::new`]: struct.TCell.html
179    pub fn cell<T>(&self, value: T) -> TCell<Q, T> {
180        TCell::<Q, T>::new(value)
181    }
182
183    /// Borrow contents of a `TCell` immutably (read-only).  Many
184    /// `TCell` instances can be borrowed immutably at the same time
185    /// from the same owner.
186    #[inline]
187    pub fn ro<'a, T: ?Sized>(&'a self, tc: &'a TCell<Q, T>) -> &'a T {
188        unsafe { &*tc.value.get() }
189    }
190
191    /// Borrow contents of a `TCell` mutably (read-write).  Only one
192    /// `TCell` at a time can be borrowed from the owner using this
193    /// call.  The returned reference must go out of scope before
194    /// another can be borrowed.
195    #[inline]
196    pub fn rw<'a, T: ?Sized>(&'a mut self, tc: &'a TCell<Q, T>) -> &'a mut T {
197        unsafe { &mut *tc.value.get() }
198    }
199
200    /// Borrow contents of two `TCell` instances mutably.  Panics if
201    /// the two `TCell` instances point to the same memory.
202    #[inline]
203    pub fn rw2<'a, T: ?Sized, U: ?Sized>(
204        &'a mut self,
205        tc1: &'a TCell<Q, T>,
206        tc2: &'a TCell<Q, U>,
207    ) -> (&'a mut T, &'a mut U) {
208        assert!(
209            tc1 as *const _ as *const () as usize != tc2 as *const _ as *const () as usize,
210            "Illegal to borrow same TCell twice with rw2()"
211        );
212        unsafe { (&mut *tc1.value.get(), &mut *tc2.value.get()) }
213    }
214
215    /// Borrow contents of three `TCell` instances mutably.  Panics if
216    /// any pair of `TCell` instances point to the same memory.
217    #[inline]
218    pub fn rw3<'a, T: ?Sized, U: ?Sized, V: ?Sized>(
219        &'a mut self,
220        tc1: &'a TCell<Q, T>,
221        tc2: &'a TCell<Q, U>,
222        tc3: &'a TCell<Q, V>,
223    ) -> (&'a mut T, &'a mut U, &'a mut V) {
224        assert!(
225            (tc1 as *const _ as *const () as usize != tc2 as *const _ as *const () as usize)
226                && (tc2 as *const _ as *const () as usize != tc3 as *const _ as *const () as usize)
227                && (tc3 as *const _ as *const () as usize != tc1 as *const _ as *const () as usize),
228            "Illegal to borrow same TCell twice with rw3()"
229        );
230        unsafe {
231            (
232                &mut *tc1.value.get(),
233                &mut *tc2.value.get(),
234                &mut *tc3.value.get(),
235            )
236        }
237    }
238}
239
240/// Cell whose contents is owned (for borrowing purposes) by a
241/// [`TCellOwner`].
242///
243/// To borrow from this cell, use the borrowing calls on the
244/// [`TCellOwner`] instance that shares the same marker type.
245///
246/// See also [crate documentation](index.html).
247///
248/// [`TCellOwner`]: struct.TCellOwner.html
249#[repr(transparent)]
250pub struct TCell<Q, T: ?Sized> {
251    // Use Invariant<Q> for invariant parameter
252    owner: PhantomData<Invariant<Q>>,
253
254    // It's fine to Send a TCell to a different thread if the contained
255    // type is Send, because you can only send something if nothing
256    // borrows it, so nothing can be accessing its contents.
257    //
258    // `UnsafeCell` disables `Sync` and already gives the right `Send` implementation.
259    // `Sync` is re-enabled below under certain conditions.
260    value: UnsafeCell<T>,
261}
262
263impl<Q, T> TCell<Q, T> {
264    /// Create a new `TCell` owned for borrowing purposes by the
265    /// `TCellOwner` derived from the same marker type `Q`.
266    #[inline]
267    pub const fn new(value: T) -> TCell<Q, T> {
268        TCell {
269            owner: PhantomData,
270            value: UnsafeCell::new(value),
271        }
272    }
273
274    /// Destroy the cell and return the contained value
275    ///
276    /// Safety: Since this consumes the cell, there can be no other
277    /// references to the cell or the data at this point.
278    #[inline]
279    pub fn into_inner(self) -> T {
280        self.value.into_inner()
281    }
282}
283
284impl<Q, T: ?Sized> TCell<Q, T> {
285    /// Borrow contents of this cell immutably (read-only).  Many
286    /// `TCell` instances can be borrowed immutably at the same time
287    /// from the same owner.
288    #[inline]
289    pub fn ro<'a>(&'a self, owner: &'a TCellOwner<Q>) -> &'a T {
290        owner.ro(self)
291    }
292
293    /// Borrow contents of this cell mutably (read-write).  Only one
294    /// `TCell` at a time can be borrowed from the owner using this
295    /// call.  The returned reference must go out of scope before
296    /// another can be borrowed.  To mutably borrow from two or three
297    /// cells at the same time, see [`TCellOwner::rw2`] or
298    /// [`TCellOwner::rw3`].
299    #[inline]
300    pub fn rw<'a>(&'a self, owner: &'a mut TCellOwner<Q>) -> &'a mut T {
301        owner.rw(self)
302    }
303
304    /// Returns a mutable reference to the underlying data
305    ///
306    /// Note that this is only useful at the beginning-of-life or
307    /// end-of-life of the cell when you have exclusive access to it.
308    /// Normally you'd use [`TCell::rw`] or [`TCellOwner::rw`] to get
309    /// a mutable reference to the contents of the cell.
310    ///
311    /// Safety: This call borrows `TCell` mutably which guarantees
312    /// that we possess the only reference.  This means that there can
313    /// be no active borrows of other forms, even ones obtained using
314    /// an immutable reference.
315    #[inline]
316    pub fn get_mut(&mut self) -> &mut T {
317        self.value.get_mut()
318    }
319}
320
321impl<Q: 'static, T: Default + ?Sized> Default for TCell<Q, T> {
322    fn default() -> Self {
323        TCell::new(T::default())
324    }
325}
326
327// We can add a Sync implementation, since it's fine to send a &TCell
328// to another thread, and even mutably borrow the value there, as long
329// as T is Send and Sync.
330//
331// The reason why TCell<T>'s impl of Sync requires T: Send + Sync
332// instead of just T: Sync is that TCell provides interior mutability.
333// If you send a &TCell<T> (and its owner) to a different thread, you
334// can call .rw() to get a &mut T, and use std::mem::swap() to move
335// the T, effectively sending the T to that other thread. That's not
336// allowed if T: !Send.
337//
338// Note that the bounds on T for TCell<T>'s impl of Sync are the same
339// as those of std::sync::RwLock<T>. That's not a coincidence.
340// The way these types let you access T concurrently is the same,
341// even though the locking mechanisms are different.
342unsafe impl<Q, T: Send + Sync + ?Sized> Sync for TCell<Q, T> {}
343
344#[cfg(all(test, any(feature = "std", feature = "exclusion-set")))]
345mod tests {
346    use super::{TCell, TCellOwner};
347    #[test]
348    #[should_panic]
349    fn tcell_singleton_1() {
350        struct Marker;
351        let _owner1 = TCellOwner::<Marker>::new();
352        let _owner2 = TCellOwner::<Marker>::new(); // Panic here
353    }
354
355    #[test]
356    fn tcell_singleton_2() {
357        struct Marker;
358        let owner1 = TCellOwner::<Marker>::new();
359        drop(owner1);
360        let _owner2 = TCellOwner::<Marker>::new();
361    }
362
363    #[test]
364    fn tcell_singleton_3() {
365        struct Marker1;
366        struct Marker2;
367        let _owner1 = TCellOwner::<Marker1>::new();
368        let _owner2 = TCellOwner::<Marker2>::new();
369    }
370
371    #[test]
372    fn tcell_singleton_try_new() {
373        struct Marker;
374        let owner1 = TCellOwner::<Marker>::try_new();
375        assert!(owner1.is_some());
376        let owner2 = TCellOwner::<Marker>::try_new();
377        assert!(owner2.is_none());
378    }
379
380    #[test]
381    fn tcell() {
382        struct Marker;
383        type ACellOwner = TCellOwner<Marker>;
384        type ACell<T> = TCell<Marker, T>;
385        let mut owner = ACellOwner::new();
386        let c1 = ACell::new(100u32);
387        let c2 = owner.cell(200u32);
388        (*owner.rw(&c1)) += 1;
389        (*owner.rw(&c2)) += 2;
390        let c1ref = owner.ro(&c1);
391        let c2ref = owner.ro(&c2);
392        let total = *c1ref + *c2ref;
393        assert_eq!(total, 303);
394    }
395
396    #[test]
397    #[should_panic]
398    fn tcell_threads() {
399        struct Marker;
400        type ACellOwner = TCellOwner<Marker>;
401        // Do it this way around to make the panic appear in the main
402        // thread, to avoid spurious messages in the test output.
403        let (tx, rx) = std::sync::mpsc::sync_channel(0);
404        std::thread::spawn(move || {
405            let mut _owner = ACellOwner::new();
406            tx.send(()).unwrap();
407            // Delay long enough for the panic to occur; this will
408            // fail if the main thread panics, so ignore that
409            let _ = tx.send(());
410        });
411        rx.recv().unwrap();
412        let mut _owner = ACellOwner::new(); // Panics here
413        let _ = rx.recv();
414    }
415
416    #[cfg(feature = "std")]
417    #[test]
418    fn tcell_wait_for_new_in_100_threads() {
419        use rand::Rng;
420        use std::sync::Arc;
421        struct Marker;
422        type ACellOwner = TCellOwner<Marker>;
423        type ACell = TCell<Marker, i32>;
424        let cell_arc = Arc::new(ACell::new(0));
425        let mut handles = vec![];
426        for _ in 0..100 {
427            let cell_arc_clone = cell_arc.clone();
428            let handle = std::thread::spawn(move || {
429                // wait a bit
430                let mut rng = rand::thread_rng();
431                std::thread::sleep(std::time::Duration::from_millis(rng.gen_range(0..10)));
432                // create a new owner
433                let mut owner = ACellOwner::wait_for_new();
434                // read the cell's current value
435                let current_cell_val = *owner.ro(&*cell_arc_clone);
436                // wait a bit more
437                std::thread::sleep(std::time::Duration::from_millis(rng.gen_range(0..10)));
438                // write the old cell value + 1 to the cell
439                // (no other thread should have been able to modify the cell in the
440                // meantime because we still hold on to the owner)
441                *owner.rw(&*cell_arc_clone) = current_cell_val + 1;
442            });
443            handles.push(handle);
444        }
445        for handle in handles {
446            assert!(handle.join().is_ok());
447        }
448        let owner = ACellOwner::wait_for_new();
449        assert_eq!(*owner.ro(&*cell_arc), 100);
450    }
451
452    #[cfg(feature = "std")]
453    #[test]
454    fn tcell_wait_for_new_timeout() {
455        fn assert_time_out<F>(d: std::time::Duration, f: F)
456        where
457            F: FnOnce(),
458            F: Send + 'static,
459        {
460            let (done_tx, done_rx) = std::sync::mpsc::channel();
461            let _handle = std::thread::spawn(move || {
462                let val = f();
463                done_tx.send(()).unwrap();
464                val
465            });
466
467            assert!(
468                done_rx.recv_timeout(d).is_err(),
469                "ACellOwner::wait_for_new completed (but it shouldn't have)"
470            );
471        }
472
473        assert_time_out(std::time::Duration::from_millis(1000), || {
474            struct Marker;
475            type ACellOwner = TCellOwner<Marker>;
476
477            let _owner1 = ACellOwner::new();
478            let _owner2 = ACellOwner::wait_for_new();
479        });
480    }
481
482    #[test]
483    fn tcell_get_mut() {
484        struct Marker;
485        type ACellOwner = TCellOwner<Marker>;
486        type ACell<T> = TCell<Marker, T>;
487        let owner = ACellOwner::new();
488        let mut cell = ACell::new(100u32);
489        let mut_ref = cell.get_mut();
490        *mut_ref = 50;
491        let cell_ref = owner.ro(&cell);
492        assert_eq!(*cell_ref, 50);
493    }
494
495    #[test]
496    fn tcell_into_inner() {
497        struct Marker;
498        type ACell<T> = TCell<Marker, T>;
499        let cell = ACell::new(100u32);
500        assert_eq!(cell.into_inner(), 100);
501    }
502
503    #[test]
504    fn tcell_unsized() {
505        struct Marker;
506        type ACellOwner = TCellOwner<Marker>;
507        type ACell<T> = TCell<Marker, T>;
508        let mut owner = ACellOwner::new();
509        struct Squares(u32);
510        struct Integers(u64);
511        trait Series {
512            fn step(&mut self);
513            fn value(&self) -> u64;
514        }
515        impl Series for Squares {
516            fn step(&mut self) {
517                self.0 += 1;
518            }
519            fn value(&self) -> u64 {
520                (self.0 as u64) * (self.0 as u64)
521            }
522        }
523        impl Series for Integers {
524            fn step(&mut self) {
525                self.0 += 1;
526            }
527            fn value(&self) -> u64 {
528                self.0
529            }
530        }
531        fn series(init: u32, is_squares: bool) -> Box<ACell<dyn Series>> {
532            if is_squares {
533                Box::new(ACell::new(Squares(init)))
534            } else {
535                Box::new(ACell::new(Integers(init as u64)))
536            }
537        }
538
539        let own = &mut owner;
540        let cell1 = series(4, false);
541        let cell2 = series(7, true);
542        let cell3 = series(3, true);
543        assert_eq!(cell1.ro(own).value(), 4);
544        cell1.rw(own).step();
545        assert_eq!(cell1.ro(own).value(), 5);
546        assert_eq!(own.ro(&cell2).value(), 49);
547        own.rw(&cell2).step();
548        assert_eq!(own.ro(&cell2).value(), 64);
549        let (r1, r2, r3) = own.rw3(&cell1, &cell2, &cell3);
550        r1.step();
551        r2.step();
552        r3.step();
553        assert_eq!(cell1.ro(own).value(), 6);
554        assert_eq!(cell2.ro(own).value(), 81);
555        assert_eq!(cell3.ro(own).value(), 16);
556        let (r1, r2) = own.rw2(&cell1, &cell2);
557        r1.step();
558        r2.step();
559        assert_eq!(cell1.ro(own).value(), 7);
560        assert_eq!(cell2.ro(own).value(), 100);
561    }
562}