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