Skip to content

Commit 2332c17

Browse files
committed
Add RawRc methods for slice values
1 parent c0329f1 commit 2332c17

File tree

1 file changed

+132
-1
lines changed

1 file changed

+132
-1
lines changed

library/alloc/src/raw_rc/raw_rc.rs

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use core::alloc::{AllocError, Allocator};
22
use core::cell::UnsafeCell;
33
use core::clone::CloneToUninit;
4+
#[cfg(not(no_global_oom_handling))]
5+
use core::iter::TrustedLen;
46
use core::marker::PhantomData;
57
#[cfg(not(no_global_oom_handling))]
68
use core::mem::{self, SizedTypeProperties};
@@ -15,7 +17,7 @@ use crate::raw_rc::MakeMutStrategy;
1517
use crate::raw_rc::raw_weak;
1618
use crate::raw_rc::raw_weak::RawWeak;
1719
#[cfg(not(no_global_oom_handling))]
18-
use crate::raw_rc::rc_layout::RcLayoutExt;
20+
use crate::raw_rc::rc_layout::{RcLayout, RcLayoutExt};
1921
use crate::raw_rc::rc_value_pointer::RcValuePointer;
2022
use crate::raw_rc::{RefCounter, rc_alloc};
2123

@@ -613,6 +615,135 @@ impl<T, A> RawRc<MaybeUninit<T>, A> {
613615
}
614616
}
615617

618+
impl<T, A> RawRc<[T], A> {
619+
#[cfg(not(no_global_oom_handling))]
620+
fn from_trusted_len_iter<I>(iter: I) -> Self
621+
where
622+
A: Allocator + Default,
623+
I: TrustedLen<Item = T>,
624+
{
625+
/// Returns a drop guard that calls the destructors of a slice of elements on drop.
626+
///
627+
/// # Safety
628+
///
629+
/// - `head..tail` must describe a valid consecutive slice of `T` values when the destructor
630+
/// of the returned guard is called.
631+
/// - After calling the returned function, the corresponding values should not be accessed
632+
/// anymore.
633+
unsafe fn drop_range_on_drop<T>(
634+
head: NonNull<T>,
635+
tail: NonNull<T>,
636+
) -> impl DerefMut<Target = (NonNull<T>, NonNull<T>)> {
637+
// SAFETY:
638+
DropGuard::new((head, tail), |(head, tail)| unsafe {
639+
let length = tail.offset_from_unsigned(head);
640+
641+
NonNull::<[T]>::slice_from_raw_parts(head, length).drop_in_place();
642+
})
643+
}
644+
645+
let (length, Some(high)) = iter.size_hint() else {
646+
// TrustedLen contract guarantees that `upper_bound == None` implies an iterator
647+
// length exceeding `usize::MAX`.
648+
// The default implementation would collect into a vec which would panic.
649+
// Thus we panic here immediately without invoking `Vec` code.
650+
panic!("capacity overflow");
651+
};
652+
653+
debug_assert_eq!(
654+
length,
655+
high,
656+
"TrustedLen iterator's size hint is not exact: {:?}",
657+
(length, high)
658+
);
659+
660+
let rc_layout = RcLayout::new_array::<T>(length);
661+
662+
let (ptr, alloc) = rc_alloc::allocate_with::<A, _, 1>(rc_layout, |ptr| {
663+
let ptr = ptr.as_ptr().cast::<T>();
664+
let mut guard = unsafe { drop_range_on_drop::<T>(ptr, ptr) };
665+
666+
// SAFETY: `iter` is `TrustedLen`, we can assume we will write correct number of
667+
// elements to the buffer.
668+
iter.for_each(|value| unsafe {
669+
guard.1.write(value);
670+
guard.1 = guard.1.add(1);
671+
});
672+
673+
mem::forget(guard);
674+
});
675+
676+
// SAFETY: We have written `length` of `T` values to the buffer, the buffer is now
677+
// initialized.
678+
unsafe {
679+
Self::from_raw_parts(
680+
NonNull::slice_from_raw_parts(ptr.as_ptr().cast::<T>(), length),
681+
alloc,
682+
)
683+
}
684+
}
685+
686+
fn try_into_array<const N: usize>(self) -> Result<RawRc<[T; N], A>, Self> {
687+
if self.as_ref().len() == N { Ok(unsafe { self.cast() }) } else { Err(self) }
688+
}
689+
690+
pub(crate) unsafe fn into_array<const N: usize, R>(self) -> Option<RawRc<[T; N], A>>
691+
where
692+
A: Allocator,
693+
R: RefCounter,
694+
{
695+
match self.try_into_array::<N>() {
696+
Ok(result) => Some(result),
697+
Err(mut raw_rc) => {
698+
unsafe { raw_rc.drop::<R>() };
699+
700+
None
701+
}
702+
}
703+
}
704+
}
705+
706+
impl<T, A> RawRc<[MaybeUninit<T>], A> {
707+
#[cfg(not(no_global_oom_handling))]
708+
pub(crate) fn new_uninit_slice_in(length: usize, alloc: A) -> Self
709+
where
710+
A: Allocator,
711+
{
712+
unsafe { Self::from_weak(RawWeak::new_uninit_slice_in::<1>(length, alloc)) }
713+
}
714+
715+
#[cfg(not(no_global_oom_handling))]
716+
pub(crate) fn new_uninit_slice(length: usize) -> Self
717+
where
718+
A: Allocator + Default,
719+
{
720+
unsafe { Self::from_weak(RawWeak::new_uninit_slice::<1>(length)) }
721+
}
722+
723+
#[cfg(not(no_global_oom_handling))]
724+
pub(crate) fn new_zeroed_slice_in(length: usize, alloc: A) -> Self
725+
where
726+
A: Allocator,
727+
{
728+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice_in::<1>(length, alloc)) }
729+
}
730+
731+
#[cfg(not(no_global_oom_handling))]
732+
pub(crate) fn new_zeroed_slice(length: usize) -> Self
733+
where
734+
A: Allocator + Default,
735+
{
736+
unsafe { Self::from_weak(RawWeak::new_zeroed_slice::<1>(length)) }
737+
}
738+
739+
/// # Safety
740+
///
741+
/// All `MaybeUninit<T>`s values contained by `self` must be initialized.
742+
pub(crate) unsafe fn assume_init(self) -> RawRc<[T], A> {
743+
unsafe { self.cast_with(|ptr| NonNull::new_unchecked(ptr.as_ptr() as _)) }
744+
}
745+
}
746+
616747
/// Decrements strong reference count in a reference-counted allocation with a value object that is
617748
/// pointed to by `value_ptr`.
618749
#[inline]

0 commit comments

Comments
 (0)