| 1 | /*! |
| 2 | This create provides weak pointers for [`Pin`]`<`[`Rc<T>`]`>` and [`Pin`]`<`[`Arc<T>`]`>` |
| 3 | |
| 4 | ## Motivation |
| 5 | |
| 6 | [`Pin`]`<`[`Rc<T>`]`>` and [`Pin`]`<`[`Arc<T>`]`>` cannot be converted safely to |
| 7 | their `Weak<T>` equivalent if `T` does not implement [`Unpin`]. |
| 8 | That's because it would otherwise be possible to do something like this: |
| 9 | |
| 10 | ```no_run |
| 11 | # use std::{pin::Pin, marker::PhantomPinned, rc::{Rc, Weak}}; |
| 12 | struct SomeStruct(PhantomPinned); |
| 13 | let pinned = Rc::pin(SomeStruct(PhantomPinned)); |
| 14 | |
| 15 | // This is unsound !!! |
| 16 | let weak = unsafe { |
| 17 | Rc::downgrade(&Pin::into_inner_unchecked(pinned.clone())) |
| 18 | }; |
| 19 | |
| 20 | // ... because otherwise it would be possible to move the content of pinned: |
| 21 | let mut unpinned_rc = weak.upgrade().unwrap(); |
| 22 | std::mem::drop((pinned, weak)); |
| 23 | // unpinned_rc is now the only reference so this will work: |
| 24 | let x = std::mem::replace( |
| 25 | Rc::get_mut(&mut unpinned_rc).unwrap(), |
| 26 | SomeStruct(PhantomPinned), |
| 27 | ); |
| 28 | ``` |
| 29 | |
| 30 | In that example, `x` is the original `SomeStruct` which we moved in memory, |
| 31 | **that is undefined behavior**, do not do that at home. |
| 32 | |
| 33 | ## `PinWeak` |
| 34 | |
| 35 | This crate simply provide a [`rc::PinWeak`] and [`sync::PinWeak`] which allow to |
| 36 | get weak pointer from `Pin<std::rc::Rc>` and `Pin<std::sync::Arc>`. |
| 37 | |
| 38 | This is safe because you can one can only get back a `Pin` out of it when |
| 39 | trying to upgrade the weak pointer. |
| 40 | |
| 41 | `PinWeak` can be created using the `PinWeak` downgrade function. |
| 42 | |
| 43 | ## Example |
| 44 | |
| 45 | ``` |
| 46 | use pin_weak::rc::*; |
| 47 | # use std::marker::PhantomPinned; |
| 48 | struct SomeStruct(PhantomPinned, usize); |
| 49 | let pinned = Rc::pin(SomeStruct(PhantomPinned, 42)); |
| 50 | let weak = PinWeak::downgrade(pinned.clone()); |
| 51 | assert_eq!(weak.upgrade().unwrap().1, 42); |
| 52 | std::mem::drop(pinned); |
| 53 | assert!(weak.upgrade().is_none()); |
| 54 | ``` |
| 55 | |
| 56 | */ |
| 57 | |
| 58 | #![no_std ] |
| 59 | extern crate alloc; |
| 60 | |
| 61 | #[cfg (doc)] |
| 62 | use alloc::{rc::Rc, sync::Arc}; |
| 63 | #[cfg (doc)] |
| 64 | use core::pin::Pin; |
| 65 | |
| 66 | /// The implementation is in a macro because it is repeated for Arc and Rc |
| 67 | macro_rules! implementation { |
| 68 | ($Rc:ident, $Weak:ident, $rc_lit:literal) => { |
| 69 | #[doc(no_inline)] |
| 70 | /// re-exported for convenience |
| 71 | pub use core::pin::Pin; |
| 72 | /// This is a safe wrapper around something that could be compared to [`Pin`]`<`[`Weak<T>`]`>` |
| 73 | /// |
| 74 | /// The typical way to obtain a `PinWeak` is to call [`PinWeak::downgrade`] |
| 75 | #[derive(Debug)] |
| 76 | pub struct PinWeak<T: ?Sized>(Weak<T>); |
| 77 | impl<T> Default for PinWeak<T> { |
| 78 | fn default() -> Self { |
| 79 | Self(Weak::default()) |
| 80 | } |
| 81 | } |
| 82 | impl<T: ?Sized> Clone for PinWeak<T> { |
| 83 | fn clone(&self) -> Self { |
| 84 | Self(self.0.clone()) |
| 85 | } |
| 86 | } |
| 87 | impl<T: ?Sized> PinWeak<T> { |
| 88 | #[doc = concat!("Equivalent function to [`" , $rc_lit, "::downgrade`], but taking a `Pin<" , $rc_lit, "<T>>` instead." )] |
| 89 | pub fn downgrade(rc: Pin<$Rc<T>>) -> Self { |
| 90 | // Safety: we will never return anything else than a Pin<Rc> |
| 91 | unsafe { Self($Rc::downgrade(&Pin::into_inner_unchecked(rc))) } |
| 92 | } |
| 93 | #[doc = concat!("Equivalent function to [`Weak::upgrade`], but taking a `Pin<" , $rc_lit, "<T>>` instead." )] |
| 94 | pub fn upgrade(&self) -> Option<Pin<$Rc<T>>> { |
| 95 | // Safety: the weak was constructed from a Pin<Rc<T>> |
| 96 | self.0.upgrade().map(|rc| unsafe { Pin::new_unchecked(rc) }) |
| 97 | } |
| 98 | |
| 99 | /// Equivalent to [`Weak::strong_count`] |
| 100 | pub fn strong_count(&self) -> usize { |
| 101 | self.0.strong_count() |
| 102 | } |
| 103 | |
| 104 | /// Equivalent to [`Weak::weak_count`] |
| 105 | pub fn weak_count(&self) -> usize { |
| 106 | self.0.weak_count() |
| 107 | } |
| 108 | |
| 109 | /// Equivalent to [`Weak::ptr_eq`] |
| 110 | pub fn ptr_eq(&self, other: &Self) -> bool { |
| 111 | self.0.ptr_eq(&other.0) |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | #[test] |
| 116 | fn test() { |
| 117 | struct Foo { |
| 118 | _p: core::marker::PhantomPinned, |
| 119 | u: u32, |
| 120 | } |
| 121 | impl Foo { |
| 122 | fn new(u: u32) -> Self { |
| 123 | Self { _p: core::marker::PhantomPinned, u } |
| 124 | } |
| 125 | } |
| 126 | let c = $Rc::pin(Foo::new(44)); |
| 127 | let weak1 = PinWeak::downgrade(c.clone()); |
| 128 | assert_eq!(weak1.upgrade().unwrap().u, 44); |
| 129 | assert_eq!(weak1.clone().upgrade().unwrap().u, 44); |
| 130 | assert_eq!(weak1.strong_count(), 1); |
| 131 | assert_eq!(weak1.weak_count(), 1); |
| 132 | let weak2 = PinWeak::downgrade(c.clone()); |
| 133 | assert_eq!(weak2.upgrade().unwrap().u, 44); |
| 134 | assert_eq!(weak1.upgrade().unwrap().u, 44); |
| 135 | assert_eq!(weak2.strong_count(), 1); |
| 136 | assert_eq!(weak2.weak_count(), 2); |
| 137 | assert!(weak1.ptr_eq(&weak2)); |
| 138 | assert!(!weak1.ptr_eq(&Default::default())); |
| 139 | // note that this moves c and therefore it will be dropped |
| 140 | let weak3 = PinWeak::downgrade(c); |
| 141 | assert!(weak3.upgrade().is_none()); |
| 142 | assert!(weak2.upgrade().is_none()); |
| 143 | assert!(weak1.upgrade().is_none()); |
| 144 | assert!(weak1.clone().upgrade().is_none()); |
| 145 | assert_eq!(weak2.strong_count(), 0); |
| 146 | assert_eq!(weak2.weak_count(), 0); |
| 147 | |
| 148 | let def = PinWeak::<alloc::boxed::Box<&'static mut ()>>::default(); |
| 149 | assert!(def.upgrade().is_none()); |
| 150 | assert!(def.clone().upgrade().is_none()); |
| 151 | } |
| 152 | }; |
| 153 | } |
| 154 | |
| 155 | pub mod rc { |
| 156 | #[doc (no_inline)] |
| 157 | /// re-exported for convenience |
| 158 | pub use alloc::rc::{Rc, Weak}; |
| 159 | implementation! {Rc, Weak, "Rc" } |
| 160 | } |
| 161 | |
| 162 | #[cfg (feature = "sync" )] |
| 163 | pub mod sync { |
| 164 | #[doc (no_inline)] |
| 165 | /// re-exported for convenience |
| 166 | pub use alloc::sync::{Arc, Weak}; |
| 167 | implementation! {Arc, Weak, "Arc" } |
| 168 | } |
| 169 | |