use crate::types::{DimLen, UDim};
#[macro_export]
macro_rules! repeat_for_dims {
($macro: tt) => {
$macro!(1, 2, 3, 4, 5, 6, 7, 8);
};
}
pub trait Dimension:
std::fmt::Debug + Clone + std::ops::Index<DimLen, Output = Self::IndexScalar>
{
type IndexScalar: From<u16>
+ std::ops::Mul
+ std::ops::MulAssign
+ Copy
+ std::fmt::Debug;
type Index: std::ops::Index<usize, Output = Self::IndexScalar>
+ std::ops::IndexMut<usize>
+ Clone;
fn zero() -> Self;
fn ndim(&self) -> DimLen;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
unsafe fn get_mut(&mut self) -> &mut Self::Index;
}
pub struct Dim<Index> {
pub(crate) index: Index,
}
impl<Index> Dim<Index> {
pub const fn new(index: Index) -> Self {
Self { index }
}
pub const fn get(&self) -> &Index {
&self.index
}
}
macro_rules! dim_def {
($($n: literal),*) => {
$(
paste::paste! {
pub type [< Dim $n >] = Dim<[UDim; $n]>;
impl Dimension for [< Dim $n >] {
type IndexScalar = UDim;
type Index = [UDim; $n];
fn zero() -> Self {
Self::new([UDim::from(0u16); $n])
}
fn ndim(&self) -> DimLen {
$n
}
fn len(&self) -> usize {
(0..$n).into_iter().fold(1, |acc, i| acc * self.index[i])
}
unsafe fn get_mut(&mut self) -> &mut Self::Index {
&mut self.index
}
}
impl std::fmt::Debug for [< Dim $n >] {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{:?}", self.index))
}
}
impl std::ops::Index<DimLen> for [< Dim $n >] {
type Output = UDim;
fn index(&self, index: DimLen) -> &Self::Output {
&self.index[index as usize]
}
}
impl Clone for [< Dim $n >] {
fn clone(&self) -> Self {
Self::new(self.index.clone())
}
}
}
)*
};
}
repeat_for_dims!(dim_def);
#[cfg(test)]
mod test {
use super::*;
macro_rules! test_dim {
($($dim: literal),*) => {
$(
paste::paste! {
#[test]
pub fn [< test_dim $dim >]() {
let mut data = [0; $dim];
for i in 0..$dim {
data[i] = i + 1;
}
let dim = [< Dim $dim >]::new(data);
assert_eq!(dim.ndim(), $dim);
for i in 0 as DimLen..$dim {
assert_eq!(dim.get()[i as usize], (i + 1) as UDim);
assert_eq!(dim[i], (i + 1) as UDim);
}
}
}
)*
};
}
macro_rules! test_dim_mut {
($($dim: literal),*) => {
$(
paste::paste! {
#[test]
pub fn [< test_dim $dim _mut >]() {
let mut data = [0; $dim];
for i in 0..$dim {
data[i as usize] = i + 1;
}
let mut dim = [< Dim $dim >]::new(data);
assert_eq!(dim.ndim(), $dim);
for i in 0 as DimLen..$dim {
assert_eq!(dim.get()[i as usize], (i + 1) as UDim);
assert_eq!(dim[i], (i + 1) as UDim);
}
unsafe {
for i in 0..$dim {
dim.get_mut()[i as usize] = i + 2;
}
}
for i in 0 as DimLen..$dim {
assert_eq!(dim.get()[i as usize], (i + 2) as UDim);
assert_eq!(dim[i], (i + 2) as UDim);
}
}
}
)*
};
}
macro_rules! test_dim_size {
($($dim: literal),*) => {
$(
paste::paste! {
#[test]
pub fn [< test_dim_size_ $dim >]() {
let mut data = [0; $dim];
let mut target = 1;
for i in 0..$dim {
data[i] = i + 1;
target *= data[i];
}
let dim = [< Dim $dim >]::new(data);
assert_eq!(dim.len(), target);
}
}
)*
};
}
macro_rules! test_dim_str {
($($dim: literal),*) => {
$(
paste::paste! {
#[test]
pub fn [< test_dim_str_ $dim >]() {
let mut data = [0; $dim];
for i in 0..$dim {
data[i] = i + 1;
}
let dim = [< Dim $dim >]::new(data);
assert_eq!(format!("{dim:?}"), format!("{data:?}"));
}
}
)*
};
}
repeat_for_dims!(test_dim);
repeat_for_dims!(test_dim_mut);
repeat_for_dims!(test_dim_size);
repeat_for_dims!(test_dim_str);
}