use crate::image::{ImageMut, ImageRef};
use crate::layout::{
Coord, Decay, Layout, MismatchedPixelError, Raster, RasterMut, SliceLayout, Take, TexelLayout,
TryMend,
};
use crate::{AsTexel, Texel};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct MatrixBytes {
pub(crate) element: TexelLayout,
pub(crate) first_dim: usize,
pub(crate) second_dim: usize,
}
pub trait MatrixLayout: Layout {
fn matrix(&self) -> MatrixBytes;
}
impl<L> MatrixLayout for &'_ L
where
L: MatrixLayout,
{
fn matrix(&self) -> MatrixBytes {
L::matrix(*self)
}
}
impl<L> MatrixLayout for &'_ mut L
where
L: MatrixLayout,
{
fn matrix(&self) -> MatrixBytes {
L::matrix(*self)
}
}
impl MatrixBytes {
pub fn empty(element: TexelLayout) -> Self {
MatrixBytes {
element,
first_dim: 0,
second_dim: 0,
}
}
pub fn from_width_height(
element: TexelLayout,
first_dim: usize,
second_dim: usize,
) -> Option<Self> {
let max_index = first_dim.checked_mul(second_dim)?;
let _ = max_index.checked_mul(element.size)?;
Some(MatrixBytes {
element,
first_dim,
second_dim,
})
}
pub const fn element(&self) -> TexelLayout {
self.element
}
pub const fn width(&self) -> usize {
self.first_dim
}
pub const fn height(&self) -> usize {
self.second_dim
}
pub const fn byte_len(self) -> usize {
self.element.size * self.len()
}
pub const fn len(self) -> usize {
self.first_dim * self.second_dim
}
}
impl Layout for MatrixBytes {
fn byte_len(&self) -> usize {
MatrixBytes::byte_len(*self)
}
}
impl Take for MatrixBytes {
fn take(&mut self) -> Self {
core::mem::replace(self, MatrixBytes::empty(self.element))
}
}
pub struct Matrix<P> {
pub(crate) width: usize,
pub(crate) height: usize,
pub(crate) pixel: Texel<P>,
}
impl<P> Matrix<P> {
pub fn from_width_height(pixel: Texel<P>, width: usize, height: usize) -> Option<Self> {
let max_index = Self::max_index(width, height)?;
let _ = max_index.checked_mul(pixel.size())?;
Some(Matrix {
width,
height,
pixel,
})
}
pub fn width_and_height(width: usize, height: usize) -> Option<Self>
where
P: AsTexel,
{
Self::from_width_height(P::texel(), width, height)
}
pub const fn empty(pixel: Texel<P>) -> Self {
Matrix {
pixel,
width: 0,
height: 0,
}
}
pub fn into_matrix_bytes(self) -> MatrixBytes {
MatrixBytes {
element: self.pixel.into(),
first_dim: self.width,
second_dim: self.height,
}
}
pub fn byte_len(self) -> usize {
self.pixel.size() * self.width * self.height
}
pub fn len(self) -> usize {
self.width * self.height
}
pub fn width(self) -> usize {
self.width
}
pub fn height(self) -> usize {
self.height
}
pub fn pixel(self) -> Texel<P> {
self.pixel
}
pub fn transmute<Q: AsTexel>(self) -> Matrix<Q> {
self.transmute_to(Q::texel())
}
pub fn transmute_to<Q>(self, pixel: Texel<Q>) -> Matrix<Q> {
assert!(
self.pixel.size() == pixel.size(),
"{} vs {}",
self.pixel.size(),
pixel.size()
);
Matrix {
width: self.width,
height: self.height,
pixel,
}
}
pub fn map<Q: AsTexel>(self) -> Option<Matrix<Q>> {
self.map_to(Q::texel())
}
pub fn map_to<Q>(self, pixel: Texel<Q>) -> Option<Matrix<Q>> {
Matrix::from_width_height(pixel, self.width, self.height)
}
}
impl<P> MatrixLayout for Matrix<P> {
fn matrix(&self) -> MatrixBytes {
self.into_matrix_bytes()
}
}
impl<L: MatrixLayout> Decay<L> for MatrixBytes {
fn decay(from: L) -> MatrixBytes {
from.matrix()
}
}
impl<P> TryMend<MatrixBytes> for Texel<P> {
type Into = Matrix<P>;
type Err = MismatchedPixelError;
fn try_mend(self, matrix: &MatrixBytes) -> Result<Matrix<P>, Self::Err> {
Matrix::with_matrix(self, *matrix).ok_or_else(MismatchedPixelError::default)
}
}
impl<P> From<Matrix<P>> for MatrixBytes {
fn from(mat: Matrix<P>) -> Self {
MatrixBytes {
element: mat.pixel().into(),
first_dim: mat.width(),
second_dim: mat.height(),
}
}
}
impl<P> Raster<P> for Matrix<P> {
fn dimensions(&self) -> Coord {
use core::convert::TryFrom;
let width = u32::try_from(self.width()).unwrap_or(u32::MAX);
let height = u32::try_from(self.height()).unwrap_or(u32::MAX);
Coord(width, height)
}
fn get(from: ImageRef<&Self>, Coord(x, y): Coord) -> Option<P> {
if from.layout().in_bounds(x as usize, y as usize) {
let index = from.layout().index_of(x as usize, y as usize);
let texel = from.layout().sample();
from.as_slice().get(index).map(|v| texel.copy_val(v))
} else {
None
}
}
}
impl<P> RasterMut<P> for Matrix<P> {
fn put(into: ImageMut<&mut Self>, Coord(x, y): Coord, val: P) {
if into.layout().in_bounds(x as usize, y as usize) {
let index = into.layout().index_of(x as usize, y as usize);
if let Some(dst) = into.into_mut_slice().get_mut(index) {
*dst = val;
}
}
}
}