use core::{
array,
ptr::NonNull,
};
use crate::{
Field,
dim::Dim,
type_lists::{
GetMetadata,
GetPtr,
Mutate,
TupleSet,
},
};
#[inline]
#[must_use]
pub unsafe fn elem_ptr<T, Elt, Index, const N: usize>(
storage: &T::Cons<N>,
pos: Dim<usize, N>,
) -> *mut Elt::Type
where
T: TupleSet,
Elt: Field,
T::Cons<N>: GetPtr<N, Elt, Index> + GetMetadata<N, Elt, Index>,
{
let base: *mut Elt::Type = storage.get_ptr().as_ptr();
let strides = *storage.get_metadata();
let pos: Dim<isize, N> = unsafe { pos.try_into().unwrap_unchecked() };
unsafe { base.byte_offset((strides * pos).sum()) }
}
#[inline]
#[must_use]
pub unsafe fn project_point<T, const N: usize>(
storage: &T::Cons<N>,
pos: Dim<usize, N>,
) -> T::Cons<0>
where
T: TupleSet,
T::Cons<N>: Mutate<N, 0, Result = T::Cons<0>>,
{
let pos: Dim<isize, N> = unsafe { pos.try_into().unwrap_unchecked() };
unsafe {
storage
.clone()
.mutate(|ptr, _size, strides| (ptr.byte_offset((*strides * pos).sum()), Dim([])))
}
}
#[inline]
#[must_use]
pub unsafe fn project_slice<T, const N: usize>(
storage: &T::Cons<N>,
start: Dim<usize, N>,
) -> T::Cons<N>
where
T: TupleSet,
T::Cons<N>: Mutate<N, N, Result = T::Cons<N>>,
{
let pos: Dim<isize, N> = unsafe { start.try_into().unwrap_unchecked() };
unsafe {
storage.clone().mutate(|ptr, _size, strides| {
(
NonNull::new_unchecked(ptr.as_ptr().wrapping_byte_offset((*strides * pos).sum())),
*strides,
)
})
}
}
#[expect(
clippy::indexing_slicing,
reason = "axis indices are bounded by N, and M is always N - 1"
)]
#[inline]
#[must_use]
pub unsafe fn drop_last_axis<T, const N: usize, const M: usize>(storage: &T::Cons<N>) -> T::Cons<M>
where
T: TupleSet,
T::Cons<N>: Mutate<N, M, Result = T::Cons<M>>,
{
const { assert!(N - 1 == M, "drop_last_axis requires M == N - 1") };
unsafe {
storage
.clone()
.mutate(|ptr, _size, strides| (ptr, Dim(array::from_fn(|axis| strides.0[axis]))))
}
}
#[expect(clippy::indexing_slicing, reason = "axis indices are bounded by N")]
#[inline]
#[must_use]
pub unsafe fn advance_last_axis<T, const N: usize>(storage: &T::Cons<N>) -> T::Cons<N>
where
T: TupleSet,
T::Cons<N>: Mutate<N, N, Result = T::Cons<N>>,
{
unsafe {
storage.clone().mutate(|ptr, _size, strides| {
(
NonNull::new_unchecked(ptr.as_ptr().wrapping_byte_offset(strides.0[N - 1])),
*strides,
)
})
}
}
#[expect(
clippy::indexing_slicing,
reason = "axis indices are bounded by N, and M is always N - 1"
)]
#[inline]
#[must_use]
pub unsafe fn project_hyperplane<T, const N: usize, const M: usize>(
storage: &T::Cons<N>,
index: isize,
) -> T::Cons<M>
where
T: TupleSet,
T::Cons<N>: Mutate<N, M, Result = T::Cons<M>>,
{
const { assert!(N - 1 == M, "project_hyperplane requires M == N - 1") };
unsafe {
storage.clone().mutate(|ptr, _size, strides| {
(
NonNull::new_unchecked(ptr.as_ptr().wrapping_byte_offset(strides.0[N - 1] * index)),
Dim(array::from_fn(|axis| strides.0[axis])),
)
})
}
}