ref_portals/
rc.rs

1//! Single-threaded anchors and portals.  
2//! These don't implement `Send` or `Sync`, but are more efficient for use cases where that's not needed.
3
4use {
5    crate::{ANCHOR_DROPPED, ANCHOR_POISONED, ANCHOR_STILL_IN_USE},
6    log::error,
7    std::{
8        borrow::Borrow,
9        cell::{Ref, RefCell, RefMut},
10        fmt::Debug,
11        marker::PhantomData,
12        mem::ManuallyDrop,
13        ops::{Deref, DerefMut},
14        panic::{RefUnwindSafe, UnwindSafe},
15        ptr::NonNull,
16        rc::{Rc, Weak},
17        sync::Mutex, // Only to deadlock.
18        thread,
19    },
20    wyz::pipe::*,
21};
22
23/// Poison helper for `!Send` mutable anchors.
24#[derive(Debug)]
25struct Poisonable<T> {
26    pointer: T,
27    poisoned: bool,
28}
29
30/// An `!Send` immutable anchor.  
31/// Use this to capture shared references in a single-threaded environment.
32///
33/// # Deadlocks
34///
35/// On drop, if any associated `Portal`s exist:
36///
37/// ```rust
38/// # use {assert_deadlock::assert_deadlock, std::time::Duration};
39/// use ref_portals::rc::Anchor;
40///
41/// let mut x = "Scoped".to_owned();
42/// let anchor = Anchor::new(&mut x);
43/// let portal = anchor.portal();
44///
45/// assert_deadlock!(drop(anchor), Duration::from_secs(1));
46/// ```
47#[derive(Debug)]
48#[repr(transparent)]
49pub struct Anchor<'a, T: ?Sized> {
50    /// Internal pointer to the target of the captured reference.
51    reference: ManuallyDrop<Rc<NonNull<T>>>,
52
53    /// Act as sharing borrower.
54    _phantom: PhantomData<&'a T>,
55}
56
57/// An `!Send` mutable anchor with overlapping immutable borrows.
58/// Use this to capture mutable references in a single-threaded environment.
59///
60/// # Deadlocks
61///
62/// Iff there is a currently active borrow, then dropping this anchor will cause a deadlock as last resort measure to prevent UB:
63///
64/// ```rust
65/// # use {assert_deadlock::assert_deadlock, std::time::Duration};
66/// use ref_portals::rc::RwAnchor;
67///
68/// let mut x = "Scoped".to_owned();
69/// let anchor = RwAnchor::new(&mut x);
70/// let portal = anchor.portal();
71/// let _guard = portal.borrow();
72///
73/// assert_deadlock!(drop(anchor), Duration::from_secs(1));
74/// ```
75///
76/// # Panics
77///
78/// On drop, if any associated `RwPortal`s exist:
79///
80/// ```rust
81/// # use assert_panic::assert_panic;
82/// use ref_portals::rc::RwAnchor;
83///
84/// let mut x = "Scoped".to_owned();
85/// let anchor = RwAnchor::new(&mut x);
86/// Box::leak(Box::new(anchor.portal()));
87///
88/// assert_panic!(
89///     drop(anchor),
90///     &str,
91///     "Anchor still in use (at least one portal exists)",
92/// );
93/// ```
94///
95/// Otherwise, on drop, iff the anchor has been poisoned:
96///
97/// ```rust
98/// # use assert_panic::assert_panic;
99/// use ref_portals::rc::RwAnchor;
100///
101/// let mut x = "Scoped".to_owned();
102/// let anchor = RwAnchor::new(&mut x);
103/// {
104///     let portal = anchor.portal();
105///     assert_panic!({
106///         let guard = portal.borrow_mut();
107///         panic!()
108///     });
109/// }
110///
111/// assert_panic!(
112///     drop(anchor),
113///     &str,
114///     "Anchor poisoned",
115/// );
116/// ```
117#[derive(Debug)]
118#[repr(transparent)]
119pub struct RwAnchor<'a, T: ?Sized> {
120    /// Internal pointer to the target of the captured reference.
121    reference: ManuallyDrop<Rc<RefCell<Poisonable<NonNull<T>>>>>,
122
123    /// Act as exclusive borrower.
124    _phantom: PhantomData<&'a mut T>,
125}
126
127impl<'a, T: ?Sized> Anchor<'a, T> {
128    /// Creates a new `Anchor` instance, capturing `reference`.
129    pub fn new(reference: &'a T) -> Anchor<'a, T> {
130        Self {
131            reference: ManuallyDrop::new(Rc::new(reference.into())),
132            _phantom: PhantomData,
133        }
134    }
135
136    /// Creates an infallible portal of indefinite lifetime associated with this anchor.
137    ///
138    /// # Example
139    ///
140    /// ```rust
141    /// # use ref_portals::rc::Anchor;
142    /// #
143    /// let x = "Scoped".to_owned();
144    /// let anchor = Anchor::new(&x);
145    /// let self_owned: Box<dyn Fn() + 'static> = Box::new({
146    ///     let portal = anchor.portal();
147    ///     move || println!("{}", *portal)
148    /// });
149    ///
150    /// self_owned(); // Scoped
151    /// ```
152    ///
153    #[inline]
154    pub fn portal(&self) -> Portal<T> {
155        self.reference.pipe_deref(Rc::clone).pipe(Portal)
156    }
157
158    /// Creates a weak portal of indefinite lifetime associated with this anchor.  
159    /// Dropping an anchor doesn't panic if only weak portals exist.
160    #[inline]
161    pub fn weak_portal(&self) -> WeakPortal<T> {
162        Portal::downgrade(&self.portal())
163    }
164}
165
166impl<'a, T: ?Sized> RwAnchor<'a, T> {
167    /// Creates a new `RwAnchor` instance, capturing `reference`.
168    pub fn new(reference: &'a mut T) -> Self {
169        Self {
170            reference: ManuallyDrop::new(Rc::new(RefCell::new(Poisonable {
171                pointer: reference.into(),
172                poisoned: false,
173            }))),
174            _phantom: PhantomData,
175        }
176    }
177
178    /// Creates a fallible portal with unbounded lifetime supporting overlapping reads.
179    ///
180    /// # Example
181    ///
182    /// ```rust
183    /// # use ref_portals::rc::RwAnchor;
184    /// #
185    /// let mut x = "Scoped".to_owned();
186    /// let anchor = RwAnchor::new(&mut x);
187    /// let self_owned: Box<dyn Fn() + 'static> = Box::new({
188    ///     let portal = anchor.portal();
189    ///     move || {
190    ///         println!("{}", *portal.borrow());
191    ///         *portal.borrow_mut() = "Replacement".to_owned();
192    ///     }
193    /// });
194    ///
195    /// self_owned(); // Scoped
196    /// drop(self_owned);
197    /// drop(anchor);
198    /// println!("{}", x); // Replacement
199    /// ```
200    ///
201    #[inline]
202    pub fn portal(&self) -> RwPortal<T> {
203        self.reference.pipe_deref(Rc::clone).pipe(RwPortal)
204    }
205
206    #[inline]
207    pub fn weak_portal(&self) -> WeakRwPortal<T> {
208        self.portal().downgrade()
209    }
210}
211
212impl<'a, T: ?Sized> Drop for Anchor<'a, T> {
213    //TODO: Deadlock if active borrows exist.
214    fn drop(&mut self) {
215        unsafe {
216            //SAFETY: Dropping.
217            ManuallyDrop::take(&mut self.reference)
218        }
219        .pipe(Rc::try_unwrap)
220        .unwrap_or_else(|_pointer| {
221            // Immutable portals are always active borrows, so we need to deadlock immediately here,
222            // since a reference could have been sent to another thread.
223            error!("!Send `Anchor` dropped while at least one Portal still exists. Deadlocking thread to prevent UB.");
224            let deadlock_mutex = Mutex::new(());
225            let _deadlock_guard = deadlock_mutex.lock().unwrap();
226            let _never = deadlock_mutex.lock();
227            // Congratulations.
228            unreachable!()
229        });
230    }
231}
232
233//TODO: Test deadlock.
234impl<'a, T: ?Sized> Drop for RwAnchor<'a, T> {
235    /// Executes the destructor for this type. [Read more](https://doc.rust-lang.org/nightly/core/ops/drop/trait.Drop.html#tymethod.drop)
236    ///
237    /// # Panics
238    ///
239    /// If any associated `RwPortal`s exist or, otherwise, iff the anchor has been poisoned:
240    ///
241    /// ```rust
242    /// # use assert_panic::assert_panic;
243    /// use ref_portals::rc::RwAnchor;
244    ///
245    /// let mut x = "Scoped".to_owned();
246    /// let anchor = RwAnchor::new(&mut x);
247    /// let portal = anchor.portal();
248    /// assert_panic!({
249    ///     // Poison anchor.
250    ///     let _guard = portal.borrow_mut();
251    ///     panic!()
252    /// });
253    ///
254    /// assert_panic!(
255    ///     drop(anchor),
256    ///     &str,
257    ///     "Anchor still in use (at least one portal exists)",
258    /// );
259    /// ```
260    fn drop(&mut self) {
261        unsafe {
262            //SAFETY: Dropping.
263            ManuallyDrop::take(&mut self.reference)
264        }
265        .pipe(Rc::try_unwrap)
266        .unwrap_or_else(|reference| {
267            reference
268                .try_borrow_mut()
269                .unwrap_or_else(|_| {
270                    // So at this point we know that something else has taken out a borrow of the poisonable value,
271                    // and we know that that borrow will never be released because all the types leading there are `!Send`,
272                    // and we also don't know whether that's only used on this one thread because a derived reference could have been sent elsewhere.
273                    // Meaning this is the only way to prevent UB here:
274                    error!("!Send `RwAnchor` dropped while borrowed from. Deadlocking thread to prevent UB.");
275                    let deadlock_mutex = Mutex::new(());
276                    let _deadlock_guard = deadlock_mutex.lock().unwrap();
277                    let _never = deadlock_mutex.lock();
278                    // Congratulations.
279                    unreachable!()
280                })
281                .poisoned = true;
282            panic!(ANCHOR_STILL_IN_USE)
283        })
284        .into_inner() // Not fallible.
285        .poisoned
286        .pipe(|poisoned| {
287            if poisoned {
288                panic!(ANCHOR_POISONED)
289            }
290        })
291    }
292}
293
294/// # Safety:
295///
296/// ```rust
297/// # use {assert_deadlock::assert_deadlock, std::time::Duration};
298/// use ref_portals::rc::Anchor;
299///
300/// let mut x = "Scoped".to_owned();
301/// let anchor = Anchor::new(&mut x);
302/// let portal = anchor.portal();
303///
304/// assert_deadlock!(
305///     drop(anchor),
306///     Duration::from_secs(1),
307/// );
308/// ```
309impl<'a, T: ?Sized> UnwindSafe for Anchor<'a, T> where T: RefUnwindSafe {}
310
311/// # Safety:
312///
313/// ```rust
314/// # use assert_panic::assert_panic;
315/// use ref_portals::rc::RwAnchor;
316///
317/// let mut x = "Scoped".to_owned();
318/// let anchor = RwAnchor::new(&mut x);
319/// let portal = anchor.portal();
320///
321/// assert_panic!(
322///     drop(anchor),
323///     &str,
324///     "Anchor still in use (at least one portal exists)",
325/// );
326/// assert_panic!(
327///     { portal.borrow_mut(); },
328///     &str,
329///     "Anchor poisoned",
330/// );
331/// ```
332impl<'a, T: ?Sized> UnwindSafe for RwAnchor<'a, T> where T: RefUnwindSafe {}
333
334/// An `!Send` immutable portal.  
335/// Dereference it directly with `*` or `.deref()`.
336#[derive(Debug)]
337#[must_use]
338#[repr(transparent)]
339pub struct Portal<T: ?Sized>(Rc<NonNull<T>>);
340
341/// An `!Send` mutable portal with overlapping immutable borrows.  
342/// Acquire a guard by calling `.borrow()` or `.borrow_mut()`.
343#[derive(Debug)]
344#[must_use]
345#[repr(transparent)]
346pub struct RwPortal<T: ?Sized>(Rc<RefCell<Poisonable<NonNull<T>>>>);
347
348impl<T: ?Sized> Portal<T> {
349    /// Creates a weak portal associated with the same anchor as `portal`.  
350    /// Dropping an anchor doesn't panic if only weak portals exist.
351    #[inline]
352    pub fn downgrade(portal: &Self) -> WeakPortal<T> {
353        Rc::downgrade(&portal.0).pipe(WeakPortal)
354    }
355}
356
357impl<T: ?Sized> Deref for Portal<T> {
358    type Target = T;
359    #[inline]
360    fn deref(&self) -> &Self::Target {
361        let pointer = self.0.deref();
362        unsafe {
363            //SAFETY: Valid as long as self.0 is.
364            pointer.as_ref()
365        }
366    }
367}
368
369impl<T: ?Sized> Borrow<T> for Portal<T> {
370    #[inline]
371    fn borrow(&self) -> &T {
372        &*self
373    }
374}
375
376impl<T: ?Sized> RwPortal<T> {
377    /// Creates a weak portal associated with the same anchor as this one.  
378    /// Dropping an anchor doesn't panic if only weak portals exist.
379    #[inline]
380    pub fn downgrade(&self) -> WeakRwPortal<T> {
381        Rc::downgrade(&self.0).pipe(WeakRwPortal)
382    }
383
384    #[inline]
385    pub fn borrow<'a>(&'a self) -> impl Deref<Target = T> + 'a {
386        let guard = self.0.as_ref().borrow();
387        if guard.poisoned {
388            panic!(ANCHOR_POISONED)
389        }
390        PortalRef(guard)
391    }
392
393    #[inline]
394    pub fn borrow_mut<'a>(&'a self) -> impl DerefMut<Target = T> + 'a {
395        let guard = self.0.as_ref().borrow_mut();
396        if guard.poisoned {
397            panic!(ANCHOR_POISONED)
398        }
399        PortalRefMut(guard)
400    }
401}
402
403impl<T: ?Sized> Clone for Portal<T> {
404    #[inline]
405    fn clone(&self) -> Self {
406        self.0.pipe_ref(Rc::clone).pipe(Self)
407    }
408}
409
410impl<T: ?Sized> Clone for RwPortal<T> {
411    #[inline]
412    fn clone(&self) -> Self {
413        self.0.pipe_ref(Rc::clone).pipe(Self)
414    }
415}
416
417//TODO: Docs, test.
418impl<T: ?Sized> RefUnwindSafe for RwPortal<T> where T: RefUnwindSafe {}
419
420//TODO: Docs, test.
421impl<T: ?Sized> UnwindSafe for RwPortal<T> where T: RefUnwindSafe {}
422
423#[derive(Debug)]
424#[must_use]
425#[repr(transparent)]
426pub struct WeakPortal<T: ?Sized>(Weak<NonNull<T>>);
427
428#[derive(Debug)]
429#[must_use]
430#[repr(transparent)]
431pub struct WeakRwPortal<T: ?Sized>(Weak<RefCell<Poisonable<NonNull<T>>>>);
432
433impl<T: ?Sized> WeakPortal<T> {
434    #[inline]
435    pub fn try_upgrade(&self) -> Option<Portal<T>> {
436        self.0.upgrade().map(Portal)
437    }
438
439    #[inline]
440    pub fn upgrade(&self) -> Portal<T> {
441        self.try_upgrade().expect(ANCHOR_DROPPED)
442    }
443}
444
445impl<T: ?Sized> WeakRwPortal<T> {
446    #[inline]
447    pub fn try_upgrade(&self) -> Option<RwPortal<T>> {
448        self.0.upgrade().map(RwPortal)
449    }
450
451    #[inline]
452    pub fn upgrade(&self) -> RwPortal<T> {
453        self.try_upgrade().expect(ANCHOR_DROPPED)
454    }
455}
456
457impl<T: ?Sized> Clone for WeakPortal<T> {
458    #[inline]
459    fn clone(&self) -> Self {
460        self.0.pipe_ref(Weak::clone).pipe(Self)
461    }
462}
463
464impl<T: ?Sized> Clone for WeakRwPortal<T> {
465    #[inline]
466    fn clone(&self) -> Self {
467        self.0.pipe_ref(Weak::clone).pipe(Self)
468    }
469}
470
471#[repr(transparent)]
472struct PortalRef<'a, T: 'a + ?Sized>(Ref<'a, Poisonable<NonNull<T>>>);
473
474#[repr(transparent)]
475struct PortalRefMut<'a, T: 'a + ?Sized>(RefMut<'a, Poisonable<NonNull<T>>>);
476
477impl<'a, T: ?Sized> Deref for PortalRef<'a, T> {
478    type Target = T;
479    #[inline]
480    fn deref(&self) -> &Self::Target {
481        let pointer = &self.0.deref().pointer;
482        unsafe {
483            //SAFETY: Valid as long as self.0 is. Can't be created from a read-only anchor.
484            pointer.as_ref()
485        }
486    }
487}
488
489impl<'a, T: ?Sized> Deref for PortalRefMut<'a, T> {
490    type Target = T;
491    #[inline]
492    fn deref(&self) -> &Self::Target {
493        let pointer = &self.0.deref().pointer;
494        unsafe {
495            //SAFETY: Valid as long as self.0 is. Can't be created from a read-only anchor.
496            pointer.as_ref()
497        }
498    }
499}
500
501impl<'a, T: ?Sized> DerefMut for PortalRefMut<'a, T> {
502    #[inline]
503    fn deref_mut(&mut self) -> &mut Self::Target {
504        let pointer = &mut self.0.deref_mut().pointer;
505        unsafe {
506            //SAFETY: Valid as long as self.0 is. Can't be created from a read-only anchor.
507            pointer.as_mut()
508        }
509    }
510}
511
512impl<'a, T: ?Sized> Drop for PortalRefMut<'a, T> {
513    #[inline]
514    fn drop(&mut self) {
515        if thread::panicking() {
516            self.0.poisoned = true;
517        }
518    }
519}
520
521#[cfg(test)]
522mod tests {
523    use super::*;
524
525    fn _auto_trait_assertions() {
526        // Anything that necessitates changes in this method is a breaking change.
527        use {assert_impl::assert_impl, core::any::Any};
528
529        assert_impl!(
530            !Send: Anchor<'_, ()>,
531            RwAnchor<'_, ()>,
532            Portal<()>,
533            RwPortal<()>,
534            PortalRef<'_, ()>,
535            PortalRefMut<'_, ()>,
536        );
537
538        assert_impl!(
539            !Sync: Anchor<'_, ()>,
540            RwAnchor<'_, ()>,
541            Portal<()>,
542            RwPortal<()>,
543            PortalRef<'_, ()>,
544            PortalRefMut<'_, ()>,
545        );
546
547        assert_impl!(
548            !UnwindSafe: Anchor<'_, dyn UnwindSafe>,
549            RwAnchor<'_, dyn UnwindSafe>,
550            Portal<dyn UnwindSafe>,
551            RwPortal<dyn UnwindSafe>,
552        );
553        assert_impl!(
554            UnwindSafe: Anchor<'_, dyn RefUnwindSafe>,
555            RwAnchor<'_, dyn RefUnwindSafe>,
556            Portal<dyn RefUnwindSafe>,
557            RwPortal<dyn RefUnwindSafe>,
558        );
559        assert_impl!(!UnwindSafe: PortalRef<'_, ()>, PortalRefMut<'_, ()>);
560
561        assert_impl!(!RefUnwindSafe: RwPortal<dyn UnwindSafe>);
562        assert_impl!(RefUnwindSafe: RwPortal<dyn RefUnwindSafe>);
563        assert_impl!(
564            //TODO: Should any of these by more RefUnwindSafe?
565            !RefUnwindSafe: Anchor<'_, ()>,
566            RwAnchor<'_, ()>,
567            Portal<()>,
568            PortalRef<'_, ()>,
569            PortalRefMut<'_, ()>,
570        );
571
572        assert_impl!(
573            Unpin: Anchor<'_, dyn Any>,
574            RwAnchor<'_, dyn Any>,
575            Portal<dyn Any>,
576            RwPortal<dyn Any>,
577            PortalRef<'_, dyn Any>,
578            PortalRefMut<'_, dyn Any>,
579        )
580    }
581
582    fn _impl_trait_assertions() {
583        use {assert_impl::assert_impl, core::any::Any};
584
585        assert_impl!(
586            Clone: Portal<dyn Any>,
587            RwPortal<dyn Any>,
588            WeakPortal<dyn Any>,
589            WeakRwPortal<dyn Any>,
590        );
591
592        assert_impl!(Deref<Target = dyn Any>: Portal<dyn Any>);
593        assert_impl!(Borrow<dyn Any>: Portal<dyn Any>);
594    }
595    //TODO
596}