use core::marker::PhantomData;
use crate::{Split, SplitInplace, SplitProcess};
#[derive(Clone, Copy, Debug, Default)]
pub struct FrameMajor;
#[derive(Clone, Copy, Debug, Default)]
pub struct LaneMajor;
#[derive(Clone, Copy, Debug)]
pub struct View<'a, T, Layout, const L: usize> {
flat: &'a [T],
frames: usize,
_layout: PhantomData<Layout>,
}
#[derive(Debug)]
pub struct ViewMut<'a, T, Layout, const L: usize> {
flat: &'a mut [T],
frames: usize,
_layout: PhantomData<Layout>,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct PerFrame<C>(pub C);
impl<'a, T, Layout, const L: usize> View<'a, T, Layout, L> {
#[must_use]
pub fn flat(self) -> &'a [T] {
self.flat
}
#[must_use]
pub const fn frames(self) -> usize {
self.frames
}
#[must_use]
pub fn as_layout<Other>(self) -> View<'a, T, Other, L> {
View {
flat: self.flat,
frames: self.frames,
_layout: PhantomData,
}
}
}
impl<'a, T, Layout, const L: usize> ViewMut<'a, T, Layout, L> {
#[must_use]
pub fn flat(&self) -> &[T] {
self.flat
}
#[must_use]
pub fn flat_mut(&mut self) -> &mut [T] {
self.flat
}
#[must_use]
pub const fn frames(&self) -> usize {
self.frames
}
#[must_use]
pub fn as_layout<Other>(self) -> ViewMut<'a, T, Other, L> {
let Self { flat, frames, .. } = self;
ViewMut {
flat,
frames,
_layout: PhantomData,
}
}
}
impl<'a, T, const L: usize> View<'a, T, FrameMajor, L> {
#[must_use]
pub fn from_frames(frames: &'a [[T; L]]) -> Self {
Self {
flat: frames.as_flattened(),
frames: frames.len(),
_layout: PhantomData,
}
}
#[must_use]
pub fn as_frames(self) -> &'a [[T; L]] {
let (frames, []) = self.flat.as_chunks::<L>() else {
unreachable!()
};
frames
}
#[must_use]
pub fn frame(self, i: usize) -> &'a [T; L] {
&self.as_frames()[i]
}
}
impl<'a, T, const L: usize> ViewMut<'a, T, FrameMajor, L> {
#[must_use]
pub fn from_frames(frames: &'a mut [[T; L]]) -> Self {
let frames_len = frames.len();
Self {
flat: frames.as_flattened_mut(),
frames: frames_len,
_layout: PhantomData,
}
}
#[must_use]
pub fn as_frames(&self) -> &[[T; L]] {
let (frames, []) = self.flat.as_chunks::<L>() else {
unreachable!()
};
frames
}
#[must_use]
pub fn as_frames_mut(&mut self) -> &mut [[T; L]] {
let (frames, []) = self.flat.as_chunks_mut::<L>() else {
unreachable!()
};
frames
}
#[must_use]
pub fn frame(&self, i: usize) -> &[T; L] {
&self.as_frames()[i]
}
#[must_use]
pub fn frame_mut(&mut self, i: usize) -> &mut [T; L] {
&mut self.as_frames_mut()[i]
}
}
impl<'a, T, const L: usize> View<'a, T, LaneMajor, L> {
#[must_use]
pub fn from_flat(flat: &'a [T], frames: usize) -> Self {
assert_eq!(flat.len(), frames * L);
Self {
flat,
frames,
_layout: PhantomData,
}
}
#[must_use]
pub fn lane(self, i: usize) -> &'a [T] {
let start = i * self.frames;
&self.flat[start..start + self.frames]
}
}
impl<'a, T, const L: usize> ViewMut<'a, T, LaneMajor, L> {
#[must_use]
pub fn from_flat(flat: &'a mut [T], frames: usize) -> Self {
assert_eq!(flat.len(), frames * L);
Self {
flat,
frames,
_layout: PhantomData,
}
}
#[must_use]
pub fn lane(&self, i: usize) -> &[T] {
let start = i * self.frames;
&self.flat[start..start + self.frames]
}
#[must_use]
pub fn lane_mut(&mut self, i: usize) -> &mut [T] {
let start = i * self.frames;
&mut self.flat[start..start + self.frames]
}
}
pub trait ViewProcess<X, Y = X> {
fn process_view(&mut self, x: X, y: Y);
}
pub trait ViewInplace<X> {
fn inplace_view(&mut self, xy: X);
}
pub trait SplitViewProcess<X, Y = X, S: ?Sized = ()> {
fn process_view(&self, state: &mut S, x: X, y: Y);
}
pub trait SplitViewInplace<X, S: ?Sized = ()> {
fn inplace_view(&self, state: &mut S, xy: X);
}
impl<'a, 'b, X, Y, S: ?Sized, T, const L: usize>
SplitViewProcess<View<'a, X, FrameMajor, L>, ViewMut<'b, Y, FrameMajor, L>, S> for T
where
X: Copy,
T: SplitProcess<X, Y, S>,
{
fn process_view(
&self,
state: &mut S,
x: View<'a, X, FrameMajor, L>,
mut y: ViewMut<'b, Y, FrameMajor, L>,
) {
debug_assert_eq!(x.frames(), y.frames());
SplitProcess::block(self, state, x.flat(), y.flat_mut());
}
}
impl<'a, X, S: ?Sized, T, const L: usize> SplitViewInplace<ViewMut<'a, X, FrameMajor, L>, S> for T
where
X: Copy,
T: SplitInplace<X, S>,
{
fn inplace_view(&self, state: &mut S, mut xy: ViewMut<'a, X, FrameMajor, L>) {
SplitInplace::inplace(self, state, xy.flat_mut());
}
}
impl<X, Y, C, S> ViewProcess<X, Y> for Split<C, S>
where
C: SplitViewProcess<X, Y, S>,
{
fn process_view(&mut self, x: X, y: Y) {
self.config.process_view(&mut self.state, x, y);
}
}
impl<X, C, S> ViewInplace<X> for Split<C, S>
where
C: SplitViewInplace<X, S>,
{
fn inplace_view(&mut self, xy: X) {
self.config.inplace_view(&mut self.state, xy);
}
}
impl<C, S> Split<PerFrame<C>, S> {
pub fn process_frames<'a, 'b, X, Y, const Q: usize, const R: usize>(
&mut self,
x: View<'a, X, FrameMajor, Q>,
mut y: ViewMut<'b, Y, FrameMajor, R>,
) where
X: Copy,
C: SplitProcess<[X; Q], [Y; R], S>,
{
debug_assert_eq!(x.frames(), y.frames());
self.config
.0
.block(&mut self.state, x.as_frames(), y.as_frames_mut());
}
pub fn inplace_frames<'a, X, const L: usize>(&mut self, mut xy: ViewMut<'a, X, FrameMajor, L>)
where
X: Copy,
C: SplitInplace<[X; L], S>,
{
self.config.0.inplace(&mut self.state, xy.as_frames_mut());
}
}