Skip to content

Commit 9184466

Browse files
committed
Add RawRc methods for slice values
1 parent 6b47771 commit 9184466

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

‎library/alloc/src/raw_rc/raw_rc.rs‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use core::cell::UnsafeCell;
33
#[cfg(not(no_global_oom_handling))]
44
use core::clone::CloneToUninit;
55
#[cfg(not(no_global_oom_handling))]
6+
use core::iter::TrustedLen;
7+
#[cfg(not(no_global_oom_handling))]
68
use core::marker::PhantomData;
79
#[cfg(not(no_global_oom_handling))]
810
use core::mem;
@@ -543,3 +545,106 @@ 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+
/// Used for dropping initialized elements in the slice if the iteration process panics.
557+
struct Guard<T> {
558+
head: NonNull<T>,
559+
tail: NonNull<T>,
560+
}
561+
562+
impl<T> Drop for Guard<T> {
563+
fn drop(&mut self) {
564+
unsafe {
565+
let length = self.tail.offset_from_unsigned(self.head);
566+
567+
NonNull::<[T]>::slice_from_raw_parts(self.head, length).drop_in_place();
568+
}
569+
}
570+
}
571+
572+
let (length, Some(high)) = iter.size_hint() else {
573+
// TrustedLen contract guarantees that `upper_bound == None` implies an iterator
574+
// length exceeding `usize::MAX`.
575+
// The default implementation would collect into a vec which would panic.
576+
// Thus we panic here immediately without invoking `Vec` code.
577+
panic!("capacity overflow");
578+
};
579+
580+
debug_assert_eq!(
581+
length,
582+
high,
583+
"TrustedLen iterator's size hint is not exact: {:?}",
584+
(length, high)
585+
);
586+
587+
let rc_layout = RcLayout::new_array::<T>(length);
588+
589+
let (ptr, alloc) = super::allocate_with::<A, _, 1>(rc_layout, |ptr| {
590+
let ptr = ptr.as_ptr().cast::<T>();
591+
let mut guard = Guard::<T> { head: ptr, tail: ptr };
592+
593+
// SAFETY: `iter` is `TrustedLen`, we can assume we will write correct number of
594+
// elements to the buffer.
595+
iter.for_each(|value| unsafe {
596+
guard.tail.write(value);
597+
guard.tail = guard.tail.add(1);
598+
});
599+
600+
mem::forget(guard);
601+
});
602+
603+
// SAFETY: We have written `length` of `T` values to the buffer, the buffer is now
604+
// initialized.
605+
unsafe {
606+
Self::from_raw_parts(
607+
NonNull::slice_from_raw_parts(ptr.as_ptr().cast::<T>(), length),
608+
alloc,
609+
)
610+
}
611+
}
612+
}
613+
614+
impl<T, A> RawRc<[MaybeUninit<T>], A> {
615+
#[cfg(not(no_global_oom_handling))]
616+
pub(crate) fn new_uninit_slice(length: usize) -> Self
617+
where
618+
A: Allocator + Default,
619+
{
620+
unsafe { Self::from_weak(RawWeak::new_uninit_slice::<1>(length)) }
621+
}
622+
623+
#[cfg(not(no_global_oom_handling))]
624+
pub(crate) fn new_uninit_slice_in(length: usize, alloc: A) -> Self
625+
where
626+
A: Allocator,
627+
{
628+
unsafe { Self::from_weak(RawWeak::new_uninit_slice_in::<1>(length, alloc)) }
629+
}
630+
631+
#[cfg(not(no_global_oom_handling))]
632+
pub(crate) fn new_zeroed_slice(length: usize) -> Self
633+
where
634+
A: Allocator + Default,
635+
{
636+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice::<1>(length)) }
637+
}
638+
639+
#[cfg(not(no_global_oom_handling))]
640+
pub(crate) fn new_zeroed_slice_in(length: usize, alloc: A) -> Self
641+
where
642+
A: Allocator,
643+
{
644+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice_in::<1>(length, alloc)) }
645+
}
646+
647+
pub(crate) unsafe fn assume_init(self) -> RawRc<[T], A> {
648+
unsafe { self.cast_with(|ptr| NonNull::new_unchecked(ptr.as_ptr() as _)) }
649+
}
650+
}

0 commit comments

Comments
 (0)