Skip to content

Commit 82d9d99

Browse files
committed
1 parent 61f0cb6 commit 82d9d99

File tree

2 files changed

+121
-6
lines changed

2 files changed

+121
-6
lines changed

src/lib.rs

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use std::{
3535
os::fd::{AsFd, AsRawFd},
3636
panic::UnwindSafe,
3737
pin::Pin,
38-
ptr::{self, addr_of, addr_of_mut, slice_from_raw_parts_mut, write, NonNull}
38+
ptr::{self, addr_of, addr_of_mut, slice_from_raw_parts_mut, write, NonNull},
3939
};
4040

4141
use core::sync::atomic::AtomicUsize;
@@ -1189,7 +1189,7 @@ impl<T: ?Sized> Trc<T> {
11891189
this.shared.as_ptr() == other.shared.as_ptr()
11901190
}
11911191

1192-
/// Gets the raw pointer to the most inner layer of `Trc<T>`.
1192+
/// Gets the raw pointer to the most inner layer of `Trc<T>`. This is only valid if there is are at least some strong references.
11931193
///
11941194
/// # Examples
11951195
/// ```
@@ -1698,8 +1698,6 @@ impl<T: Clone + ?Sized> FromIterator<T> for Trc<[T]> {
16981698
//impl<T: ?Sized + std::marker::Unsize<U>, U: ?Sized> std::ops::CoerceUnsized<Trc<U>> for Trc<T> {}
16991699
//impl<T: ?Sized> std::ops::Receiver for Trc<T> {}
17001700

1701-
1702-
17031701
impl<T: ?Sized> Drop for Weak<T> {
17041702
#[inline]
17051703
fn drop(&mut self) {
@@ -1763,6 +1761,118 @@ impl<T: ?Sized> Weak<T> {
17631761
}
17641762
})
17651763
}
1764+
1765+
/// Gets the raw pointer to the most inner layer of `Weak<T>`. This is only valid if there is are at least some strong references.
1766+
///
1767+
/// # Examples
1768+
/// ```
1769+
/// use trc::Trc;
1770+
/// use trc::Weak;
1771+
///
1772+
/// let trc = Trc::new(100);
1773+
/// let weak = Trc::downgrade(&trc);
1774+
/// println!("{}", Trc::as_ptr(&trc) as usize)
1775+
/// ```
1776+
#[inline]
1777+
pub fn as_ptr(this: &Self) -> *const T {
1778+
let sharedptr = NonNull::as_ptr(this.data);
1779+
unsafe { addr_of_mut!((*sharedptr).data) }
1780+
}
1781+
1782+
/// Converts a `Weak<T>` into `*const T`, without freeing the allocation.
1783+
/// To avoid a memory leak, be sure to call `from_raw` to reclaim the allocation.
1784+
///
1785+
/// # Examples
1786+
/// ```
1787+
/// use trc::Trc;
1788+
/// use trc::Weak;
1789+
///
1790+
/// let trc = Trc::new(100);
1791+
/// let weak = Trc::downgrade(&trc);
1792+
/// let ptr = Trc::into_raw(trc);
1793+
///
1794+
/// assert_eq!(unsafe { *ptr }, 100);
1795+
///
1796+
/// unsafe { Weak::from_raw(ptr) };
1797+
/// ```
1798+
pub fn into_raw(this: Self) -> *const T {
1799+
let ptr = Self::as_ptr(&this);
1800+
1801+
forget(this);
1802+
ptr
1803+
}
1804+
}
1805+
1806+
impl<T> Weak<T> {
1807+
/// Converts a `*const T` into `Weak<T>`. The caller must uphold the below safety constraints.
1808+
/// To avoid a memory leak, be sure to call `from_raw` to reclaim the allocation.
1809+
///
1810+
/// # Safety
1811+
/// - The given pointer must be a valid pointer to `T` that came from `into_raw`.
1812+
/// - After `from_raw`, the pointer must not be accessed.
1813+
///
1814+
/// # Examples
1815+
/// ```
1816+
/// use trc::Trc;
1817+
/// use trc::Weak;
1818+
///
1819+
/// let weak = Trc::downgrade(&Trc::new(100));
1820+
/// let ptr = Weak::into_raw(weak);
1821+
///
1822+
/// assert_eq!(unsafe { *ptr }, 100);
1823+
///
1824+
/// unsafe { Weak::from_raw(ptr) };
1825+
///
1826+
/// let strong = Trc::new("hello".to_owned());
1827+
///
1828+
/// let raw_1 = Weak::into_raw(Trc::downgrade(&strong));
1829+
/// let raw_2 = Weak::into_raw(Trc::downgrade(&strong));
1830+
///
1831+
/// assert_eq!(3, Trc::weak_count(&strong));
1832+
///
1833+
/// assert_eq!("hello", &*Weak::upgrade(unsafe { &Weak::from_raw(raw_1) }).unwrap());
1834+
/// assert_eq!(2, Trc::weak_count(&strong));
1835+
///
1836+
/// drop(strong);
1837+
///
1838+
/// // Decrement the last weak count.
1839+
/// assert!( Weak::upgrade(unsafe {& Weak::from_raw(raw_2) }).is_none());
1840+
/// ```
1841+
pub unsafe fn from_raw(ptr: *const T) -> Self {
1842+
let layout = Layout::new::<SharedTrcInternal<()>>();
1843+
let n = layout.size();
1844+
1845+
let data_ptr = (ptr as *const u8).sub(n) as *mut SharedTrcInternal<T>;
1846+
1847+
Weak {
1848+
data: NonNull::new_unchecked(data_ptr),
1849+
}
1850+
}
1851+
1852+
/// Create a new, uninitialzed Weak<T>. Calling `Weak::upgrade` on this will always return `None.
1853+
///
1854+
/// # Examples
1855+
/// ```
1856+
/// use trc::Weak;
1857+
/// use core::mem::MaybeUninit;
1858+
///
1859+
/// let weak: Weak<MaybeUninit<i32>> = Weak::new();
1860+
///
1861+
/// assert!(Weak::upgrade(&weak).is_none());
1862+
/// ```
1863+
pub fn new() -> Weak<MaybeUninit<T>> {
1864+
let data = MaybeUninit::<T>::uninit();
1865+
1866+
let shareddata = SharedTrcInternal {
1867+
atomicref: AtomicUsize::new(0),
1868+
weakcount: AtomicUsize::new(0),
1869+
data,
1870+
};
1871+
1872+
let sbx = Box::new(shareddata);
1873+
1874+
Weak { data: NonNull::from(Box::leak(sbx)) }
1875+
}
17661876
}
17671877

17681878
impl<T: ?Sized> Clone for Weak<T> {

src/tests.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::thread;
1+
use std::{thread, mem::MaybeUninit};
22

33
use crate::{SharedTrc, Trc, Weak};
44

@@ -217,7 +217,12 @@ fn test_dyn2() {
217217
}
218218
}
219219

220-
221220
let vehicle = Trc::new(Truck);
222221
<Truck as Vehicle>::drive(&*vehicle);
222+
}
223+
224+
#[test]
225+
fn test_ub_weak_as_ptr() {
226+
//https://github.com/rust-lang/rust/issues/80365
227+
println!("{:?}", Weak::into_raw(Weak::<MaybeUninit<usize>>::new()));
223228
}

0 commit comments

Comments
 (0)