Skip to content

Commit 61ef0b2

Browse files
committed
Add RawRc methods for slice values
1 parent a5b9827 commit 61ef0b2

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

library/alloc/src/raw_rc/raw_rc.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use core::cell::UnsafeCell;
44
use core::clone::CloneToUninit;
55
#[cfg(not(no_global_oom_handling))]
66
use core::convert;
7+
#[cfg(not(no_global_oom_handling))]
8+
use core::iter::TrustedLen;
79
use core::marker::PhantomData;
810
#[cfg(not(no_global_oom_handling))]
911
use core::mem::{self, SizedTypeProperties};
@@ -595,6 +597,116 @@ impl<T, A> RawRc<MaybeUninit<T>, A> {
595597
}
596598
}
597599

600+
impl<T, A> RawRc<[T], A> {
601+
#[cfg(not(no_global_oom_handling))]
602+
fn from_trusted_len_iter<I>(iter: I) -> Self
603+
where
604+
A: Allocator + Default,
605+
I: TrustedLen<Item = T>,
606+
{
607+
/// Returns a drop guard that calls the destructors of a slice of elements on drop.
608+
///
609+
/// # Safety
610+
///
611+
/// - `head..tail` must describe a valid consecutive slice of `T` values when the destructor
612+
/// of the returned guard is called.
613+
/// - After calling the returned function, the corresponding values should not be accessed
614+
/// anymore.
615+
unsafe fn drop_range_on_drop<T>(
616+
head: NonNull<T>,
617+
tail: NonNull<T>,
618+
) -> impl DerefMut<Target = (NonNull<T>, NonNull<T>)> {
619+
// SAFETY:
620+
DropGuard::new((head, tail), |(head, tail)| unsafe {
621+
let length = tail.offset_from_unsigned(head);
622+
623+
NonNull::<[T]>::slice_from_raw_parts(head, length).drop_in_place();
624+
})
625+
}
626+
627+
let (length, Some(high)) = iter.size_hint() else {
628+
// TrustedLen contract guarantees that `upper_bound == None` implies an iterator
629+
// length exceeding `usize::MAX`.
630+
// The default implementation would collect into a vec which would panic.
631+
// Thus we panic here immediately without invoking `Vec` code.
632+
panic!("capacity overflow");
633+
};
634+
635+
debug_assert_eq!(
636+
length,
637+
high,
638+
"TrustedLen iterator's size hint is not exact: {:?}",
639+
(length, high)
640+
);
641+
642+
let rc_layout = RcLayout::new_array::<T>(length);
643+
644+
let (ptr, alloc) = rc_alloc::allocate_with::<A, _, 1>(rc_layout, |ptr| {
645+
let ptr = ptr.as_ptr().cast::<T>();
646+
let mut guard = unsafe { drop_range_on_drop::<T>(ptr, ptr) };
647+
648+
// SAFETY: `iter` is `TrustedLen`, we can assume we will write correct number of
649+
// elements to the buffer.
650+
iter.for_each(|value| unsafe {
651+
guard.1.write(value);
652+
guard.1 = guard.1.add(1);
653+
});
654+
655+
mem::forget(guard);
656+
});
657+
658+
// SAFETY: We have written `length` of `T` values to the buffer, the buffer is now
659+
// initialized.
660+
unsafe {
661+
Self::from_raw_parts(
662+
NonNull::slice_from_raw_parts(ptr.as_ptr().cast::<T>(), length),
663+
alloc,
664+
)
665+
}
666+
}
667+
}
668+
669+
impl<T, A> RawRc<[MaybeUninit<T>], A> {
670+
#[cfg(not(no_global_oom_handling))]
671+
pub(crate) fn new_uninit_slice(length: usize) -> Self
672+
where
673+
A: Allocator + Default,
674+
{
675+
unsafe { Self::from_weak(RawWeak::new_uninit_slice::<1>(length)) }
676+
}
677+
678+
#[cfg(not(no_global_oom_handling))]
679+
pub(crate) fn new_uninit_slice_in(length: usize, alloc: A) -> Self
680+
where
681+
A: Allocator,
682+
{
683+
unsafe { Self::from_weak(RawWeak::new_uninit_slice_in::<1>(length, alloc)) }
684+
}
685+
686+
#[cfg(not(no_global_oom_handling))]
687+
pub(crate) fn new_zeroed_slice(length: usize) -> Self
688+
where
689+
A: Allocator + Default,
690+
{
691+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice::<1>(length)) }
692+
}
693+
694+
#[cfg(not(no_global_oom_handling))]
695+
pub(crate) fn new_zeroed_slice_in(length: usize, alloc: A) -> Self
696+
where
697+
A: Allocator,
698+
{
699+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice_in::<1>(length, alloc)) }
700+
}
701+
702+
/// # Safety
703+
///
704+
/// All `MaybeUninit<T>`s values contained by `self` must be initialized.
705+
pub(crate) unsafe fn assume_init(self) -> RawRc<[T], A> {
706+
unsafe { self.cast_with(|ptr| NonNull::new_unchecked(ptr.as_ptr() as _)) }
707+
}
708+
}
709+
598710
/// Decrements strong reference count in a reference-counted allocation with a value object that is
599711
/// pointed to by `value_ptr`.
600712
#[inline]

0 commit comments

Comments
 (0)