Skip to content

Commit 6cb537c

Browse files
committed
Add RawRc methods for sized values
1 parent 393e377 commit 6cb537c

File tree

1 file changed

+131
-2
lines changed

1 file changed

+131
-2
lines changed

library/alloc/src/raw_rc/raw_rc.rs

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::alloc::Allocator;
1+
use core::alloc::{AllocError, Allocator};
22
use core::cell::UnsafeCell;
33
#[cfg(not(no_global_oom_handling))]
44
use core::clone::CloneToUninit;
@@ -11,7 +11,7 @@ use core::ptr::NonNull;
1111
use crate::raw_rc::RefCounter;
1212
use crate::raw_rc::raw_weak::RawWeak;
1313
#[cfg(not(no_global_oom_handling))]
14-
use crate::raw_rc::rc_layout::RcLayout;
14+
use crate::raw_rc::rc_layout::{RcLayout, RcLayoutExt};
1515
use crate::raw_rc::rc_value_pointer::RcValuePointer;
1616

1717
/// Decrements strong reference count in a reference-counted allocation with a value object that is
@@ -347,3 +347,132 @@ where
347347
unsafe { self.weak.value_ptr_unchecked() }
348348
}
349349
}
350+
351+
impl<T, A> RawRc<T, A> {
352+
unsafe fn from_weak_with_value(weak: RawWeak<T, A>, value: T) -> Self {
353+
unsafe {
354+
weak.as_ptr().write(value);
355+
356+
Self::from_weak(weak)
357+
}
358+
}
359+
360+
#[inline]
361+
pub(crate) fn try_new(value: T) -> Result<Self, AllocError>
362+
where
363+
A: Allocator + Default,
364+
{
365+
RawWeak::try_new_uninit::<1>()
366+
.map(|weak| unsafe { Self::from_weak_with_value(weak, value) })
367+
}
368+
369+
#[inline]
370+
pub(crate) fn try_new_in(value: T, alloc: A) -> Result<Self, AllocError>
371+
where
372+
A: Allocator,
373+
{
374+
RawWeak::try_new_uninit_in::<1>(alloc)
375+
.map(|weak| unsafe { Self::from_weak_with_value(weak, value) })
376+
}
377+
378+
#[cfg(not(no_global_oom_handling))]
379+
#[inline]
380+
pub(crate) fn new(value: T) -> Self
381+
where
382+
A: Allocator + Default,
383+
{
384+
unsafe { Self::from_weak_with_value(RawWeak::new_uninit::<1>(), value) }
385+
}
386+
387+
#[cfg(not(no_global_oom_handling))]
388+
#[inline]
389+
pub(crate) fn new_in(value: T, alloc: A) -> Self
390+
where
391+
A: Allocator,
392+
{
393+
unsafe { Self::from_weak_with_value(RawWeak::new_uninit_in::<1>(alloc), value) }
394+
}
395+
396+
#[cfg(not(no_global_oom_handling))]
397+
fn new_with<F>(f: F) -> Self
398+
where
399+
A: Allocator + Default,
400+
F: FnOnce() -> T,
401+
{
402+
let (ptr, alloc) = super::allocate_with::<A, _, 1>(T::RC_LAYOUT, |ptr| unsafe {
403+
ptr.as_ptr().cast().write(f())
404+
});
405+
406+
unsafe { Self::from_raw_parts(ptr.as_ptr().cast(), alloc) }
407+
}
408+
409+
pub(crate) unsafe fn into_inner<R>(self) -> Option<T>
410+
where
411+
A: Allocator,
412+
R: RefCounter,
413+
{
414+
let is_last_strong_ref = unsafe { decrement_strong_ref_count::<R>(self.value_ptr()) };
415+
416+
is_last_strong_ref.then(|| unsafe { self.weak.assume_init_into_inner::<R>() })
417+
}
418+
419+
pub(crate) unsafe fn try_unwrap<R>(self) -> Result<T, RawRc<T, A>>
420+
where
421+
A: Allocator,
422+
R: RefCounter,
423+
{
424+
unsafe fn inner<R>(value_ptr: RcValuePointer) -> bool
425+
where
426+
R: RefCounter,
427+
{
428+
unsafe {
429+
R::from_raw_counter(value_ptr.strong_count_ptr().as_ref()).lock_strong_count()
430+
}
431+
}
432+
433+
let is_last_strong_ref = unsafe { inner::<R>(self.value_ptr()) };
434+
435+
if is_last_strong_ref {
436+
Ok(unsafe { self.weak.assume_init_into_inner::<R>() })
437+
} else {
438+
Err(self)
439+
}
440+
}
441+
442+
pub(crate) unsafe fn unwrap_or_clone<R>(self) -> T
443+
where
444+
T: Clone,
445+
A: Allocator,
446+
R: RefCounter,
447+
{
448+
/// Calls `RawRc::drop` on drop.
449+
struct Guard<'a, T, A, R>
450+
where
451+
T: ?Sized,
452+
A: Allocator,
453+
R: RefCounter,
454+
{
455+
rc: &'a mut RawRc<T, A>,
456+
_phantom_data: PhantomData<R>,
457+
}
458+
459+
impl<T, A, R> Drop for Guard<'_, T, A, R>
460+
where
461+
T: ?Sized,
462+
A: Allocator,
463+
R: RefCounter,
464+
{
465+
fn drop(&mut self) {
466+
unsafe { self.rc.drop::<R>() };
467+
}
468+
}
469+
470+
unsafe {
471+
self.try_unwrap::<R>().unwrap_or_else(|mut rc| {
472+
let guard = Guard::<T, A, R> { rc: &mut rc, _phantom_data: PhantomData };
473+
474+
T::clone(guard.rc.as_ptr().as_ref())
475+
})
476+
}
477+
}
478+
}

0 commit comments

Comments
 (0)