use core::{mem, ptr::NonNull};
use crate::pin::POwn;
impl<'a, T, const N: usize> POwn<'a, [T; N]> {
#[inline]
#[must_use]
pub const fn to_slice(self) -> POwn<'a, [T]> {
let drop_flag = self.drop_flag;
let inner = self.inner;
mem::forget(self);
let slice_ptr = inner.cast::<T>();
let slice_slice_ptr = NonNull::slice_from_raw_parts(slice_ptr, N);
POwn {
drop_flag,
inner: slice_slice_ptr,
}
}
}
impl<'a, T> POwn<'a, [T]> {
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
self.inner.len()
}
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[inline]
pub const fn to_array<const N: usize>(self) -> Result<POwn<'a, [T; N]>, Self> {
if self.len() == N {
let inner = self.inner;
let drop_flag = self.drop_flag;
mem::forget(self);
let first_ptr = inner.cast::<T>();
let array_ptr = first_ptr.cast::<[T; N]>();
let array = POwn { drop_flag, inner: array_ptr };
Ok(array)
} else {
Err(self)
}
}
#[inline]
#[must_use]
pub const unsafe fn to_chunks_unchecked<const N: usize>(self) -> POwn<'a, [[T; N]]> {
let drop_flag = self.drop_flag;
let inner = self.inner;
mem::forget(self);
let chunks_ptr = inner.cast::<[T; N]>();
let chunks_len = unsafe { inner.len().unchecked_div_exact(N) };
let chunks_slice_ptr = NonNull::slice_from_raw_parts(chunks_ptr, chunks_len);
POwn {
drop_flag,
inner: chunks_slice_ptr,
}
}
#[inline]
#[must_use]
pub fn to_chunks<const N: usize>(self) -> POwn<'a, [[T; N]]> {
assert!(N != 0, "chunk size must be non-zero");
assert!(
self.len().is_multiple_of(N),
"slice length must be a multiple of chunk size"
);
unsafe { self.to_chunks_unchecked::<N>() }
}
}
impl<'a, T, const N: usize> POwn<'a, [[T; N]]> {
#[inline]
#[must_use]
pub const fn flatten(self) -> POwn<'a, [T]> {
let flat_len = if const { size_of::<T>() == 0 } {
self.len().checked_mul(N).expect("slice len overflow")
} else {
unsafe { self.len().unchecked_mul(N) }
};
let drop_flag = self.drop_flag;
let inner = self.inner;
mem::forget(self);
let flat_ptr = inner.cast::<T>();
let flat_slice_ptr = NonNull::slice_from_raw_parts(flat_ptr, flat_len);
POwn { drop_flag, inner: flat_slice_ptr }
}
}