Skip to content

Commit 65fbaae

Browse files
committed
Add RawRc methods for slice values
1 parent 9f5f008 commit 65fbaae

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

0 commit comments

Comments
 (0)