Skip to content

Commit effa938

Browse files
committed
Add RawUniqueRc methods for sized values
1 parent 308edb7 commit effa938

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-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
@@ -27,6 +27,8 @@ use crate::boxed::Box;
2727
#[cfg(not(no_global_oom_handling))]
2828
use crate::raw_rc::MakeMutStrategy;
2929
#[cfg(not(no_global_oom_handling))]
30+
use crate::raw_rc::raw_unique_rc::RawUniqueRc;
31+
#[cfg(not(no_global_oom_handling))]
3032
use crate::raw_rc::raw_weak;
3133
use crate::raw_rc::raw_weak::RawWeak;
3234
#[cfg(not(no_global_oom_handling))]
@@ -437,6 +439,45 @@ impl<T, A> RawRc<T, A> {
437439
unsafe { Self::from_raw_parts(ptr.as_ptr().cast(), alloc) }
438440
}
439441

442+
#[cfg(not(no_global_oom_handling))]
443+
unsafe fn new_cyclic_impl<F, R>(mut weak: RawWeak<T, A>, data_fn: F) -> Self
444+
where
445+
A: Allocator,
446+
F: FnOnce(&RawWeak<T, A>) -> T,
447+
R: RefCounter,
448+
{
449+
let guard = unsafe { raw_weak::new_weak_guard::<T, A, R>(&mut weak) };
450+
let data = data_fn(&guard);
451+
452+
mem::forget(guard);
453+
454+
unsafe { RawUniqueRc::from_weak_with_value(weak, data).into_rc::<R>() }
455+
}
456+
457+
#[cfg(not(no_global_oom_handling))]
458+
pub(crate) unsafe fn new_cyclic_in<F, R>(data_fn: F, alloc: A) -> Self
459+
where
460+
A: Allocator,
461+
F: FnOnce(&RawWeak<T, A>) -> T,
462+
R: RefCounter,
463+
{
464+
let weak = RawWeak::new_uninit_in::<0>(alloc);
465+
466+
unsafe { Self::new_cyclic_impl::<F, R>(weak, data_fn) }
467+
}
468+
469+
#[cfg(not(no_global_oom_handling))]
470+
pub(crate) unsafe fn new_cyclic<F, R>(data_fn: F) -> Self
471+
where
472+
A: Allocator + Default,
473+
F: FnOnce(&RawWeak<T, A>) -> T,
474+
R: RefCounter,
475+
{
476+
let weak = RawWeak::new_uninit::<0>();
477+
478+
unsafe { Self::new_cyclic_impl::<F, R>(weak, data_fn) }
479+
}
480+
440481
/// Attempts to map the value in an `Rc`, reusing the allocation if possible.
441482
///
442483
/// # Safety

library/alloc/src/raw_rc/raw_unique_rc.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
use core::alloc::Allocator;
22
use core::marker::PhantomData;
3+
#[cfg(not(no_global_oom_handling))]
4+
use core::mem::{self, SizedTypeProperties};
5+
#[cfg(not(no_global_oom_handling))]
6+
use core::ops::{ControlFlow, Try};
37

48
use crate::raw_rc::RefCounter;
59
use crate::raw_rc::raw_rc::RawRc;
10+
#[cfg(not(no_global_oom_handling))]
11+
use crate::raw_rc::raw_weak;
612
use crate::raw_rc::raw_weak::RawWeak;
713
use crate::raw_rc::rc_value_pointer::RcValuePointer;
814

@@ -73,3 +79,96 @@ where
7379
}
7480
}
7581
}
82+
83+
impl<T, A> RawUniqueRc<T, A> {
84+
#[cfg(not(no_global_oom_handling))]
85+
pub(super) unsafe fn from_weak_with_value(weak: RawWeak<T, A>, value: T) -> Self {
86+
unsafe { weak.as_ptr().write(value) };
87+
88+
Self { weak, _marker: PhantomData, _marker2: PhantomData }
89+
}
90+
91+
#[cfg(not(no_global_oom_handling))]
92+
pub(crate) fn new_in(value: T, alloc: A) -> Self
93+
where
94+
A: Allocator,
95+
{
96+
unsafe { Self::from_weak_with_value(RawWeak::new_uninit_in::<0>(alloc), value) }
97+
}
98+
99+
#[cfg(not(no_global_oom_handling))]
100+
pub(crate) fn new(value: T) -> Self
101+
where
102+
A: Allocator + Default,
103+
{
104+
unsafe { Self::from_weak_with_value(RawWeak::new_uninit::<0>(), value) }
105+
}
106+
107+
/// Attempts to map the value in a `RawUniqueRc`, reusing the allocation if possible.
108+
///
109+
/// # Safety
110+
///
111+
/// All accesses to `self` must use the same `RefCounter` implementation for `R`.
112+
#[cfg(not(no_global_oom_handling))]
113+
pub(crate) unsafe fn try_map<R, U>(
114+
mut self,
115+
f: impl FnOnce(T) -> U,
116+
) -> ControlFlow<U::Residual, RawUniqueRc<U::Output, A>>
117+
where
118+
A: Allocator,
119+
R: RefCounter,
120+
U: Try,
121+
{
122+
// Destruct `self` as a `RawWeak<T, A>` if `f` panics or returns a failure value.
123+
let guard = unsafe { raw_weak::new_weak_guard::<T, A, R>(&mut self.weak) };
124+
125+
let (allocation, mapped_value) = if T::LAYOUT == U::Output::LAYOUT
126+
&& R::unique_rc_weak_count(unsafe { R::from_raw_counter(guard.weak_count_unchecked()) })
127+
== 1
128+
{
129+
let mapped_value = f(unsafe { guard.as_ptr().read() }).branch()?;
130+
131+
// Avoid deallocation on success, reuse the allocation.
132+
mem::forget(guard);
133+
134+
let allocation = unsafe { self.weak.cast() };
135+
136+
(allocation, mapped_value)
137+
} else {
138+
let value = unsafe { guard.as_ptr().read() };
139+
140+
drop(guard);
141+
142+
let mapped_value = f(value).branch()?;
143+
let allocation = RawWeak::new_uninit_in::<0>(self.weak.into_raw_parts().1);
144+
145+
(allocation, mapped_value)
146+
};
147+
148+
ControlFlow::Continue(unsafe {
149+
RawUniqueRc::from_weak_with_value(allocation, mapped_value)
150+
})
151+
}
152+
153+
/// Maps the value in a `RawUniqueRc`, reusing the allocation if possible.
154+
///
155+
/// # Safety
156+
///
157+
/// All accesses to `self` must use the same `RefCounter` implementation for `R`.
158+
#[cfg(not(no_global_oom_handling))]
159+
pub(crate) unsafe fn map<R, U>(self, f: impl FnOnce(T) -> U) -> RawUniqueRc<U, A>
160+
where
161+
A: Allocator,
162+
R: RefCounter,
163+
{
164+
fn wrap_fn<T, U>(f: impl FnOnce(T) -> U) -> impl FnOnce(T) -> ControlFlow<!, U> {
165+
|x| ControlFlow::Continue(f(x))
166+
}
167+
168+
let f = wrap_fn(f);
169+
170+
match unsafe { self.try_map::<R, _>(f) } {
171+
ControlFlow::Continue(output) => output,
172+
}
173+
}
174+
}

0 commit comments

Comments
 (0)