Skip to content

Commit 443e528

Browse files
committed
Add RawRc methods for slice values
1 parent 7dab519 commit 443e528

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};
@@ -596,6 +598,116 @@ impl<T, A> RawRc<MaybeUninit<T>, A> {
596598
}
597599
}
598600

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

0 commit comments

Comments
 (0)