Skip to content

Commit 9a29750

Browse files
committed
Add RawUniqueRc methods for sized values
1 parent efeba22 commit 9a29750

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

library/alloc/src/raw_rc/raw_rc.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use crate::boxed::Box;
3131
use crate::raw_rc::MakeMutStrategy;
3232
use crate::raw_rc::RefCounter;
3333
#[cfg(not(no_global_oom_handling))]
34+
use crate::raw_rc::raw_unique_rc::RawUniqueRc;
35+
#[cfg(not(no_global_oom_handling))]
3436
use crate::raw_rc::raw_weak;
3537
use crate::raw_rc::raw_weak::RawWeak;
3638
#[cfg(not(no_global_oom_handling))]
@@ -414,6 +416,45 @@ impl<T, A> RawRc<T, A> {
414416
unsafe { Self::from_raw_parts(ptr.as_ptr().cast(), alloc) }
415417
}
416418

419+
#[cfg(not(no_global_oom_handling))]
420+
unsafe fn new_cyclic_impl<F, R>(mut weak: RawWeak<T, A>, data_fn: F) -> Self
421+
where
422+
A: Allocator,
423+
F: FnOnce(&RawWeak<T, A>) -> T,
424+
R: RefCounter,
425+
{
426+
let guard = unsafe { raw_weak::new_weak_guard::<T, A, R>(&mut weak) };
427+
let data = data_fn(&guard);
428+
429+
mem::forget(guard);
430+
431+
unsafe { RawUniqueRc::from_weak_with_value(weak, data).into_rc::<R>() }
432+
}
433+
434+
#[cfg(not(no_global_oom_handling))]
435+
pub(crate) unsafe fn new_cyclic<F, R>(data_fn: F) -> Self
436+
where
437+
A: Allocator + Default,
438+
F: FnOnce(&RawWeak<T, A>) -> T,
439+
R: RefCounter,
440+
{
441+
let weak = RawWeak::new_uninit::<0>();
442+
443+
unsafe { Self::new_cyclic_impl::<F, R>(weak, data_fn) }
444+
}
445+
446+
#[cfg(not(no_global_oom_handling))]
447+
pub(crate) unsafe fn new_cyclic_in<F, R>(data_fn: F, alloc: A) -> Self
448+
where
449+
A: Allocator,
450+
F: FnOnce(&RawWeak<T, A>) -> T,
451+
R: RefCounter,
452+
{
453+
let weak = RawWeak::new_uninit_in::<0>(alloc);
454+
455+
unsafe { Self::new_cyclic_impl::<F, R>(weak, data_fn) }
456+
}
457+
417458
/// Maps the value in an `RawRc`, reusing the allocation if possible.
418459
///
419460
/// # Safety

library/alloc/src/raw_rc/raw_unique_rc.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
use core::alloc::Allocator;
2+
#[cfg(not(no_global_oom_handling))]
3+
use core::convert;
24
use core::marker::PhantomData;
5+
#[cfg(not(no_global_oom_handling))]
6+
use core::mem::{self, SizedTypeProperties};
7+
#[cfg(not(no_global_oom_handling))]
8+
use core::ops::{Residual, Try};
39

410
use crate::raw_rc::RefCounter;
511
use crate::raw_rc::raw_rc::RawRc;
12+
#[cfg(not(no_global_oom_handling))]
13+
use crate::raw_rc::raw_weak;
614
use crate::raw_rc::raw_weak::RawWeak;
715
use crate::raw_rc::rc_value_pointer::RcValuePointer;
816

@@ -73,3 +81,92 @@ where
7381
}
7482
}
7583
}
84+
85+
impl<T, A> RawUniqueRc<T, A> {
86+
#[cfg(not(no_global_oom_handling))]
87+
pub(super) unsafe fn from_weak_with_value(weak: RawWeak<T, A>, value: T) -> Self {
88+
unsafe { weak.as_ptr().write(value) };
89+
90+
Self { weak, _marker: PhantomData, _marker2: PhantomData }
91+
}
92+
93+
#[cfg(not(no_global_oom_handling))]
94+
pub(crate) fn new(value: T) -> Self
95+
where
96+
A: Allocator + Default,
97+
{
98+
unsafe { Self::from_weak_with_value(RawWeak::new_uninit::<0>(), value) }
99+
}
100+
101+
#[cfg(not(no_global_oom_handling))]
102+
pub(crate) fn new_in(value: T, alloc: A) -> Self
103+
where
104+
A: Allocator,
105+
{
106+
unsafe { Self::from_weak_with_value(RawWeak::new_uninit_in::<0>(alloc), value) }
107+
}
108+
109+
/// Maps the value in a `RawUniqueRc`, reusing the allocation if possible.
110+
///
111+
/// # Safety
112+
///
113+
/// All accesses to `self` must use the same `RefCounter` implementation for `R`.
114+
#[cfg(not(no_global_oom_handling))]
115+
pub(crate) unsafe 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+
unsafe { 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+
///
129+
/// # Safety
130+
///
131+
/// All accesses to `self` must use the same `RefCounter` implementation for `R`.
132+
#[cfg(not(no_global_oom_handling))]
133+
pub(crate) unsafe fn try_map<R, U, V>(
134+
mut self,
135+
f: impl FnOnce(T) -> U,
136+
map_result: impl FnOnce(RawUniqueRc<U::Output, A>) -> V, // How to remove this argument?
137+
) -> <U::Residual as Residual<V>>::TryType
138+
where
139+
A: Allocator,
140+
R: RefCounter,
141+
U: Try,
142+
U::Residual: Residual<V>,
143+
{
144+
// Destruct `self` as a `RawWeak<T, A>` if `f` panics or returns a failure value.
145+
let guard = unsafe { raw_weak::new_weak_guard::<T, A, R>(&mut self.weak) };
146+
147+
let (allocation, mapped_value) = if T::LAYOUT == U::Output::LAYOUT
148+
&& R::unique_rc_weak_count(unsafe { R::from_raw_counter(guard.weak_count_unchecked()) })
149+
== 1
150+
{
151+
let mapped_value = f(unsafe { guard.as_ptr().read() })?;
152+
153+
// Avoid deallocation on success, reuse the allocation.
154+
mem::forget(guard);
155+
156+
let allocation = unsafe { self.weak.cast() };
157+
158+
(allocation, mapped_value)
159+
} else {
160+
let value = unsafe { guard.as_ptr().read() };
161+
162+
drop(guard);
163+
164+
let mapped_value = f(value)?;
165+
let allocation = RawWeak::new_uninit_in::<0>(self.weak.into_raw_parts().1);
166+
167+
(allocation, mapped_value)
168+
};
169+
170+
try { map_result(unsafe { RawUniqueRc::from_weak_with_value(allocation, mapped_value) }) }
171+
}
172+
}

0 commit comments

Comments
 (0)