use crate::SubPixels;
#[cfg(feature = "std")]
use std::prelude::v1::*;
pub trait Matrix<T> {
fn get_width(&self) -> usize;
fn get_height(&self) -> usize;
fn get_data(&self) -> &[T];
fn get_value(&self, row: usize, col: usize) -> Option<&T> {
self.get_data().get(row * self.get_width() + col)
}
}
pub trait MatrixMut<T>: Matrix<T> {
fn get_data_mut(&mut self) -> &mut [T];
}
#[repr(transparent)]
pub(crate) struct FlippedMatrix<'a, M>(pub &'a M);
impl<'a, M, T> Matrix<T> for FlippedMatrix<'a, M>
where
M: Matrix<T>,
{
#[inline]
fn get_width(&self) -> usize {
self.0.get_width()
}
#[inline]
fn get_height(&self) -> usize {
self.0.get_height()
}
#[inline]
fn get_data(&self) -> &[T] {
self.0.get_data()
}
fn get_value(&self, row: usize, col: usize) -> Option<&T> {
let new_row = self.get_height() - row - 1;
let new_col = self.get_width() - col - 1;
self.0.get_value(new_row, new_col)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StaticMatrix<T, const N: usize> {
width: usize,
height: usize,
data: [T; N],
}
impl<T, const N: usize> StaticMatrix<T, N> {
pub fn new(width: usize, height: usize, data: [T; N]) -> Option<Self> {
if width * height == data.len() {
Some(Self {
width,
height,
data,
})
} else {
None
}
}
pub fn map<F, O>(self, operation: F) -> StaticMatrix<O, N>
where
F: Fn(T) -> O,
O: Default + Copy,
{
let mut arr = [O::default(); N];
for (i, x) in self.data.into_iter().enumerate() {
arr[i] = operation(x);
}
StaticMatrix::new(self.width, self.height, arr).unwrap()
}
pub fn into_parts(self) -> (usize, usize, [T; N]) {
(self.width, self.height, self.data)
}
}
impl<T: Copy, const M: usize, const N: usize> StaticMatrix<SubPixels<T, N>, M> {
pub fn map_subpixels<F, O>(self, operation: F) -> StaticMatrix<SubPixels<O, N>, M>
where
F: Fn(T) -> O + Copy,
O: Default + Copy,
{
let mut arr = [SubPixels::default(); M];
for (i, x) in self.data.into_iter().enumerate() {
arr[i] = x.map(operation);
}
StaticMatrix::new(self.width, self.height, arr).unwrap()
}
}
impl<T, const N: usize> Matrix<T> for StaticMatrix<T, N> {
fn get_width(&self) -> usize {
self.width
}
fn get_height(&self) -> usize {
self.height
}
fn get_data(&self) -> &[T] {
&self.data
}
}
impl<T, const N: usize> MatrixMut<T> for StaticMatrix<T, N> {
fn get_data_mut(&mut self) -> &mut [T] {
&mut self.data
}
}
#[cfg(feature = "std")]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DynamicMatrix<T> {
width: usize,
height: usize,
data: Vec<T>,
}
#[cfg(feature = "std")]
impl<T> DynamicMatrix<T> {
pub fn new(width: usize, height: usize, data: Vec<T>) -> Option<Self> {
if width * height == data.len() {
Some(Self {
width,
height,
data,
})
} else {
None
}
}
pub fn map<F: Fn(T) -> O, O>(self, operation: F) -> DynamicMatrix<O> {
let arr = self.data.into_iter().map(operation).collect();
DynamicMatrix::new(self.width, self.height, arr).unwrap()
}
pub fn into_parts(self) -> (usize, usize, Vec<T>) {
(self.width, self.height, self.data)
}
}
#[cfg(feature = "std")]
impl<T: Copy, const N: usize> DynamicMatrix<SubPixels<T, N>> {
pub fn map_subpixels<F, O>(self, operation: F) -> DynamicMatrix<SubPixels<O, N>>
where
F: Fn(T) -> O + Copy,
O: Default + Copy,
{
let arr = self.data.into_iter().map(|sp| sp.map(operation)).collect();
DynamicMatrix::new(self.width, self.height, arr).unwrap()
}
}
#[cfg(feature = "std")]
impl<T> Matrix<T> for DynamicMatrix<T> {
fn get_width(&self) -> usize {
self.width
}
fn get_height(&self) -> usize {
self.height
}
fn get_data(&self) -> &[T] {
self.data.as_slice()
}
}
#[cfg(feature = "std")]
impl<T> MatrixMut<T> for DynamicMatrix<T> {
fn get_data_mut(&mut self) -> &mut [T] {
self.data.as_mut_slice()
}
}
#[cfg(test)]
mod tests {
use super::FlippedMatrix;
use crate::{Matrix, StaticMatrix};
#[test]
fn flipped_matrix() {
let mat = StaticMatrix::new(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
let flipped = FlippedMatrix(&mat);
assert_eq!(flipped.get_value(0, 0), Some(&9));
assert_eq!(flipped.get_value(2, 1), Some(&2));
assert_eq!(flipped.get_value(0, 2), Some(&7));
assert_eq!(flipped.get_value(1, 1), Some(&5));
}
}