use core::{
cell::Ref,
mem::{self, ManuallyDrop, MaybeUninit},
slice,
};
use generic_array::{ArrayLength, GenericArray};
#[must_use]
#[inline]
pub fn clone_arr<'a, T, N>(orig: &GenericArray<Ref<'a, T>, N>) -> GenericArray<Ref<'a, T>, N>
where
T: ?Sized,
N: ArrayLength<Ref<'a, T>>,
{
let mut arr = MaybeUninit::<GenericArray<Ref<'a, T>, N>>::uninit();
let data = arr.as_mut_ptr().cast::<MaybeUninit<Ref<'a, T>>>();
let len = N::to_usize();
let slice = unsafe { slice::from_raw_parts_mut(data, len) };
let mut dropper = PartialArrayDropper::new(data.cast::<Ref<'a, T>>());
for (old, new) in orig.iter().zip(slice) {
new.write(Ref::clone(old));
unsafe { dropper.prime_next() };
}
dropper.defuse();
unsafe { arr.assume_init() }
}
struct PartialArrayDropper<T> {
data: *mut T,
len: usize,
}
impl<T> PartialArrayDropper<T> {
#[must_use]
#[inline]
pub const fn new(data: *mut T) -> Self {
let len = 0;
Self { data, len }
}
#[inline]
pub unsafe fn prime_next(&mut self) {
self.len += 1;
}
#[inline]
pub const fn defuse(self) {
mem::forget(self);
}
}
impl<T> Drop for PartialArrayDropper<T> {
#[inline]
fn drop(&mut self) {
let data = self.data.cast::<ManuallyDrop<T>>();
let slice = unsafe { slice::from_raw_parts_mut(data, self.len) };
for elem in slice {
unsafe { ManuallyDrop::drop(elem) };
}
}
}