use crate::{
layout::{
AlignedOffset, Decay, Layout, Matrix, MatrixBytes, MismatchedPixelError, PlaneOf, Relocate,
SliceLayout, TexelLayout, TryMend,
},
texel::Texel,
};
use super::relocated::Relocated;
#[derive(Clone)]
pub struct Planes<Storage: ?Sized> {
inner: Storage,
}
impl<Storage> Planes<Storage> {
pub fn into_inner(self) -> Storage {
self.inner
}
}
impl<Pl, const N: usize> Planes<[Pl; N]>
where
Pl: Layout,
{
pub fn new(inner: [Pl; N]) -> Self {
Self { inner }
}
pub fn as_ref(&self) -> Planes<[&'_ Pl; N]> {
Planes {
inner: self.inner.each_ref(),
}
}
pub fn as_mut(&mut self) -> Planes<[&'_ mut Pl; N]> {
Planes {
inner: self.inner.each_mut(),
}
}
}
impl<Pl, const N: usize> Layout for Planes<[Pl; N]>
where
Pl: Layout,
{
fn byte_len(&self) -> usize {
let lengths: [usize; N] = self.inner.each_ref().map(|p| p.byte_len());
lengths.iter().copied().max().unwrap_or(0)
}
}
impl<Pl> Layout for Planes<[Pl]>
where
Pl: Layout,
{
fn byte_len(&self) -> usize {
let lengths = self.inner.iter().map(|p| p.byte_len());
lengths.max().unwrap_or(0)
}
}
impl<Pl, const N: usize> PlaneOf<Planes<[Pl; N]>> for usize
where
Pl: Layout + Clone,
{
type Plane = Pl;
fn get_plane(self, layout: &Planes<[Pl; N]>) -> Option<Self::Plane> {
layout.inner.get(self).cloned()
}
}
impl<Pl> PlaneOf<Planes<[Pl]>> for usize
where
Pl: Layout + Clone,
{
type Plane = Pl;
fn get_plane(self, layout: &Planes<[Pl]>) -> Option<Self::Plane> {
layout.inner.get(self).cloned()
}
}
#[derive(Clone)]
pub struct PlaneBytes<const N: usize> {
planes: Planes<[Relocated<MatrixBytes>; N]>,
}
impl<const N: usize> PlaneBytes<N> {
pub fn new(inner: [MatrixBytes; N]) -> Self {
let mut inner = inner.map(Relocated::new);
let mut offset = AlignedOffset::default();
for plane in inner.iter_mut() {
plane.relocate(offset);
offset = plane.next_aligned_offset().expect("layout too large");
}
PlaneBytes {
planes: Planes::new(inner),
}
}
pub fn plane_ref(&self, idx: usize) -> Option<&Relocated<MatrixBytes>> {
self.planes.inner.get(idx)
}
#[must_use]
pub fn retain_coefficients_like(&self, texel: TexelLayout) -> Self {
let matrices = self.planes.inner.clone();
let inner = matrices.map(|plane| {
if plane.inner.element() == texel {
plane
} else {
Relocated {
offset: plane.offset,
inner: MatrixBytes::empty(texel),
}
}
});
PlaneBytes {
planes: Planes::new(inner),
}
}
}
impl<const N: usize> Layout for PlaneBytes<N> {
fn byte_len(&self) -> usize {
if N == 0 {
0
} else {
self.planes.inner[N - 1].byte_len()
}
}
}
impl<const N: usize> Relocate for PlaneBytes<N> {
fn byte_offset(&self) -> usize {
if N == 0 {
0
} else {
self.planes.inner[0].byte_len()
}
}
fn relocate(&mut self, mut offset: AlignedOffset) {
for plane in self.planes.inner.iter_mut() {
plane.relocate(offset);
offset = plane.next_aligned_offset().expect("layout too large");
}
}
}
impl<const N: usize> PlaneOf<PlaneBytes<N>> for usize {
type Plane = Relocated<MatrixBytes>;
fn get_plane(self, layout: &PlaneBytes<N>) -> Option<Self::Plane> {
layout.planes.inner.get(self).copied()
}
}
impl<T, const N: usize> TryMend<PlaneBytes<N>> for Texel<T> {
type Into = PlaneMatrices<T, N>;
type Err = MismatchedPixelError;
fn try_mend(self, from: &PlaneBytes<N>) -> Result<Self::Into, Self::Err> {
let planes = from.planes.inner.each_ref();
let mut results: [Result<_, MismatchedPixelError>; N] = planes.map(|plane| {
let matrix = self.try_mend(&plane.inner)?;
Ok(Relocated {
offset: plane.offset,
inner: matrix,
})
});
if let Some(err) = results.iter().position(|e| e.is_err()) {
let mut replacement = Ok(Relocated::new(Matrix::empty(self)));
core::mem::swap(&mut results[err], &mut replacement);
return Err(match replacement {
Err(err) => err,
Ok(_) => unreachable!(),
});
}
let inner = results.map(|res| res.unwrap());
Ok(PlaneMatrices {
planes: Planes::new(inner),
texel: self,
})
}
}
#[derive(Clone)]
pub struct PlaneMatrices<T, const N: usize> {
planes: Planes<[Relocated<Matrix<T>>; N]>,
texel: Texel<T>,
}
impl<T, const N: usize> PlaneMatrices<T, N> {
pub fn new(texel: Texel<T>, inner: [Matrix<T>; N]) -> Self {
use crate::layout::{Decay, TryMend};
let bytes = inner.each_ref().map(|m| MatrixBytes::decay(m));
let planes = PlaneBytes::new(bytes);
texel
.try_mend(&planes)
.expect("input matrices have this texel")
}
pub fn from_repeated(matrix: Matrix<T>) -> Self {
let texel = matrix.pixel();
Self::new(texel, [matrix; N])
}
pub fn plane_ref(&self, idx: usize) -> Option<&Relocated<Matrix<T>>> {
self.planes.inner.get(idx)
}
}
impl<T, const N: usize> PlaneOf<PlaneMatrices<T, N>> for usize {
type Plane = Relocated<Matrix<T>>;
fn get_plane(self, layout: &PlaneMatrices<T, N>) -> Option<Self::Plane> {
layout.planes.inner.get(self).copied()
}
}
impl<T, const N: usize> Layout for PlaneMatrices<T, N> {
fn byte_len(&self) -> usize {
if N == 0 {
0
} else {
self.planes.inner[N - 1].byte_len()
}
}
}
impl<T, const N: usize> SliceLayout for PlaneMatrices<T, N> {
type Sample = T;
fn sample(&self) -> Texel<Self::Sample> {
self.texel
}
}
impl<T, const N: usize> Decay<PlaneMatrices<T, N>> for PlaneBytes<N> {
fn decay(from: PlaneMatrices<T, N>) -> PlaneBytes<N> {
let bytes = from.planes.inner.each_ref().map(|rel| Relocated {
offset: rel.offset,
inner: MatrixBytes::decay(&rel.inner),
});
PlaneBytes {
planes: Planes::new(bytes),
}
}
}