Skip to content

Commit cef8367

Browse files
committed
Add RawRc methods for slice values
1 parent c7454d6 commit cef8367

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
@@ -2,6 +2,8 @@ use core::alloc::{AllocError, Allocator};
22
use core::cell::UnsafeCell;
33
#[cfg(not(no_global_oom_handling))]
44
use core::clone::CloneToUninit;
5+
#[cfg(not(no_global_oom_handling))]
6+
use core::iter::TrustedLen;
57
use core::marker::PhantomData;
68
#[cfg(not(no_global_oom_handling))]
79
use core::mem;
@@ -543,3 +545,113 @@ impl<T, A> RawRc<MaybeUninit<T>, A> {
543545
unsafe { self.cast() }
544546
}
545547
}
548+
549+
impl<T, A> RawRc<[T], A> {
550+
#[cfg(not(no_global_oom_handling))]
551+
fn from_trusted_len_iter<I>(iter: I) -> Self
552+
where
553+
A: Allocator + Default,
554+
I: TrustedLen<Item = T>,
555+
{
556+
/// Returns a drop guard that calls the destructors of a slice of elements on drop.
557+
///
558+
/// # Safety
559+
///
560+
/// - `head..tail` must describe a valid consecutive slice of `T` values when the destructor
561+
/// of the returned guard is called.
562+
/// - After calling the returned function, the corresponding values should not be accessed
563+
/// anymore.
564+
unsafe fn drop_range_on_drop<T>(
565+
head: NonNull<T>,
566+
tail: NonNull<T>,
567+
) -> impl DerefMut<Target = (NonNull<T>, NonNull<T>)> {
568+
// SAFETY:
569+
DropGuard::new((head, tail), |(head, tail)| unsafe {
570+
let length = tail.offset_from_unsigned(head);
571+
572+
NonNull::<[T]>::slice_from_raw_parts(head, length).drop_in_place();
573+
})
574+
}
575+
576+
let (length, Some(high)) = iter.size_hint() else {
577+
// TrustedLen contract guarantees that `upper_bound == None` implies an iterator
578+
// length exceeding `usize::MAX`.
579+
// The default implementation would collect into a vec which would panic.
580+
// Thus we panic here immediately without invoking `Vec` code.
581+
panic!("capacity overflow");
582+
};
583+
584+
debug_assert_eq!(
585+
length,
586+
high,
587+
"TrustedLen iterator's size hint is not exact: {:?}",
588+
(length, high)
589+
);
590+
591+
let rc_layout = RcLayout::new_array::<T>(length);
592+
593+
let (ptr, alloc) = rc_alloc::allocate_with::<A, _, 1>(rc_layout, |ptr| {
594+
let ptr = ptr.as_ptr().cast::<T>();
595+
let mut guard = unsafe { drop_range_on_drop::<T>(ptr, ptr) };
596+
597+
// SAFETY: `iter` is `TrustedLen`, we can assume we will write correct number of
598+
// elements to the buffer.
599+
iter.for_each(|value| unsafe {
600+
guard.1.write(value);
601+
guard.1 = guard.1.add(1);
602+
});
603+
604+
mem::forget(guard);
605+
});
606+
607+
// SAFETY: We have written `length` of `T` values to the buffer, the buffer is now
608+
// initialized.
609+
unsafe {
610+
Self::from_raw_parts(
611+
NonNull::slice_from_raw_parts(ptr.as_ptr().cast::<T>(), length),
612+
alloc,
613+
)
614+
}
615+
}
616+
}
617+
618+
impl<T, A> RawRc<[MaybeUninit<T>], A> {
619+
#[cfg(not(no_global_oom_handling))]
620+
pub(crate) fn new_uninit_slice(length: usize) -> Self
621+
where
622+
A: Allocator + Default,
623+
{
624+
unsafe { Self::from_weak(RawWeak::new_uninit_slice::<1>(length)) }
625+
}
626+
627+
#[cfg(not(no_global_oom_handling))]
628+
pub(crate) fn new_uninit_slice_in(length: usize, alloc: A) -> Self
629+
where
630+
A: Allocator,
631+
{
632+
unsafe { Self::from_weak(RawWeak::new_uninit_slice_in::<1>(length, alloc)) }
633+
}
634+
635+
#[cfg(not(no_global_oom_handling))]
636+
pub(crate) fn new_zeroed_slice(length: usize) -> Self
637+
where
638+
A: Allocator + Default,
639+
{
640+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice::<1>(length)) }
641+
}
642+
643+
#[cfg(not(no_global_oom_handling))]
644+
pub(crate) fn new_zeroed_slice_in(length: usize, alloc: A) -> Self
645+
where
646+
A: Allocator,
647+
{
648+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice_in::<1>(length, alloc)) }
649+
}
650+
651+
/// # Safety
652+
///
653+
/// All `MaybeUninit<T>`s values contained by `self` must be initialized.
654+
pub(crate) unsafe fn assume_init(self) -> RawRc<[T], A> {
655+
unsafe { self.cast_with(|ptr| NonNull::new_unchecked(ptr.as_ptr() as _)) }
656+
}
657+
}

0 commit comments

Comments
 (0)