Skip to content

Commit db6cfb1

Browse files
committed
Add RawUniqueRc methods for sized values
1 parent c1e7118 commit db6cfb1

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))]
@@ -415,6 +417,45 @@ impl<T, A> RawRc<T, A> {
415417
unsafe { Self::from_raw_parts(ptr.as_ptr().cast(), alloc) }
416418
}
417419

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