use core::mem;
use core::mem::MaybeUninit;
use core::ptr::drop_in_place;
macro_rules! assert_const {
($cond:expr, $($arg:tt)+) => {
if const { !$cond } {
assert!($cond, $($arg)+);
}
};
($cond:expr $(,)?) => {
if const { !$cond } {
assert!($cond);
}
};
}
pub(crate) use assert_const;
pub(crate) trait MaybeUninitExt<T> {
unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T]
where
Self: Sized;
fn clone_from_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
where
T: Clone;
}
impl<T> MaybeUninitExt<T> for MaybeUninit<T> {
#[inline(always)]
unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] {
unsafe { &mut *(slice as *mut [Self] as *mut [T]) }
}
fn clone_from_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
where
T: Clone,
{
struct Guard<'a, T> {
slice: &'a mut [MaybeUninit<T>],
initialized: usize,
}
impl<'a, T> Drop for Guard<'a, T> {
fn drop(&mut self) {
let initialized_part = &mut self.slice[..self.initialized];
unsafe {
drop_in_place(MaybeUninitExt::slice_assume_init_mut(initialized_part));
}
}
}
assert_eq!(
this.len(),
src.len(),
"destination and source slices have different lengths"
);
let len = this.len();
let src = &src[..len];
let mut guard = Guard {
slice: this,
initialized: 0,
};
#[allow(clippy::needless_range_loop)]
for i in 0..len {
guard.slice[i].write(src[i].clone());
guard.initialized += 1;
}
mem::forget(guard);
unsafe { MaybeUninitExt::slice_assume_init_mut(this) }
}
}
#[inline]
pub(crate) const unsafe fn pad_to_align(addr: usize, align: usize) -> usize {
let align_minus_one = unsafe { align.unchecked_sub(1) };
let aligned_addr = addr.wrapping_add(align_minus_one) & 0usize.wrapping_sub(align);
let byte_offset = aligned_addr.wrapping_sub(addr);
debug_assert!(byte_offset < align);
debug_assert!((addr + byte_offset) % align == 0);
byte_offset
}