Skip to content

Commit 631e62e

Browse files
committed
Implement alloc::rc::{Rc,Weak,UniqueRc} with alloc::raw_rc types
1 parent 05ca297 commit 631e62e

File tree

11 files changed

+555
-1326
lines changed

11 files changed

+555
-1326
lines changed

library/alloc/src/raw_rc/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@
6060
//! - Converting `Option<Rc<T>>` to `Option<&T>` without checking for `None` values.
6161
//! - Converting `&[Rc<T>]` to `&[&T]` with zero cost.
6262
63-
#![allow(dead_code)]
64-
6563
use core::cell::UnsafeCell;
6664
use core::mem;
6765
use core::sync::atomic::Atomic;
6866

67+
pub(crate) use crate::raw_rc::raw_rc::RawRc;
68+
pub(crate) use crate::raw_rc::raw_unique_rc::RawUniqueRc;
69+
pub(crate) use crate::raw_rc::raw_weak::RawWeak;
70+
6971
mod raw_rc;
7072
mod raw_unique_rc;
7173
mod raw_weak;
@@ -169,4 +171,9 @@ pub(crate) unsafe trait RefCounter: Sized {
169171
/// - If strong count is greater than 1, returns `Some(MakeMutStrategy::Clone)`.
170172
#[cfg(not(no_global_oom_handling))]
171173
fn make_mut(strong_count: &Self, weak_count: &Self) -> Option<MakeMutStrategy>;
174+
175+
/// Returns the weak count of an `RawUniqueRc`, used to determine whether there are any weak
176+
/// pointers to the same allocation.
177+
#[cfg(not(no_global_oom_handling))]
178+
fn unique_rc_weak_count(weak_count: &Self) -> usize;
172179
}

library/alloc/src/raw_rc/raw_unique_rc.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
use core::alloc::Allocator;
2+
#[cfg(not(no_global_oom_handling))]
3+
use core::convert;
24
use core::fmt::{self, Debug, Display, Formatter, Pointer};
35
use core::hash::{Hash, Hasher};
46
use core::marker::{PhantomData, Unsize};
7+
#[cfg(not(no_global_oom_handling))]
8+
use core::mem::{self, SizedTypeProperties};
59
use core::ops::{CoerceUnsized, DispatchFromDyn};
10+
#[cfg(not(no_global_oom_handling))]
11+
use core::ops::{Residual, Try};
612

713
use crate::alloc::Global;
814
use crate::raw_rc::RefCounter;
915
use crate::raw_rc::raw_rc::RawRc;
16+
#[cfg(not(no_global_oom_handling))]
17+
use crate::raw_rc::raw_weak;
1018
use crate::raw_rc::raw_weak::RawWeak;
1119
use crate::raw_rc::rc_value_pointer::RcValuePointer;
1220

@@ -101,6 +109,62 @@ impl<T, A> RawUniqueRc<T, A> {
101109
{
102110
unsafe { Self::from_weak_with_value(RawWeak::new_uninit_in::<0>(alloc), value) }
103111
}
112+
113+
/// Maps the value in a `RawUniqueRc`, reusing the allocation if possible.
114+
#[cfg(not(no_global_oom_handling))]
115+
pub(crate) fn map<R, U>(self, f: impl FnOnce(T) -> U) -> RawUniqueRc<U, A>
116+
where
117+
A: Allocator,
118+
R: RefCounter,
119+
{
120+
fn wrap_fn<T, U>(f: impl FnOnce(T) -> U) -> impl FnOnce(T) -> Result<U, !> {
121+
|x| Ok(f(x))
122+
}
123+
124+
self.try_map::<R, _, _>(wrap_fn(f), convert::identity).into_ok()
125+
}
126+
127+
/// Attempts to map the value in a `RawUniqueRc`, reusing the allocation if possible.
128+
#[cfg(not(no_global_oom_handling))]
129+
pub(crate) fn try_map<R, U, V>(
130+
mut self,
131+
f: impl FnOnce(T) -> U,
132+
map_result: impl FnOnce(RawUniqueRc<U::Output, A>) -> V, // How to remove this argument?
133+
) -> <U::Residual as Residual<V>>::TryType
134+
where
135+
A: Allocator,
136+
R: RefCounter,
137+
U: Try,
138+
U::Residual: Residual<V>,
139+
{
140+
// Destruct `self` as a `RawWeak<T, A>` if `f` panics or returns `Err`.
141+
let guard = unsafe { raw_weak::new_weak_guard::<T, A, R>(&mut self.weak) };
142+
143+
let (allocation, mapped_value) = if T::LAYOUT == U::Output::LAYOUT
144+
&& R::unique_rc_weak_count(unsafe { R::from_raw_counter(guard.weak_count_unchecked()) })
145+
== 1
146+
{
147+
let mapped_value = f(unsafe { guard.as_ptr().read() })?;
148+
149+
// Avoid deallocation on success, reuse the allocation.
150+
mem::forget(guard);
151+
152+
let allocation = unsafe { self.weak.cast() };
153+
154+
(allocation, mapped_value)
155+
} else {
156+
let value = unsafe { guard.as_ptr().read() };
157+
158+
drop(guard);
159+
160+
let mapped_value = f(value)?;
161+
let allocation = RawWeak::new_uninit_in::<0>(self.weak.into_raw_parts().1);
162+
163+
(allocation, mapped_value)
164+
};
165+
166+
try { map_result(unsafe { RawUniqueRc::from_weak_with_value(allocation, mapped_value) }) }
167+
}
104168
}
105169

106170
impl<T, A> AsMut<T> for RawUniqueRc<T, A>

0 commit comments

Comments
 (0)