diff --git a/src/Container2D.rs b/src/Container2D.rs deleted file mode 100644 index 00f5399..0000000 --- a/src/Container2D.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::Index2D::Index2D; - -pub trait Container2D { - type Output; - const HEIGHT: u32; - const WIDTH: u32; - - fn get(&self, i: I) -> Option<&Self::Output>; -} - -pub trait Container2DMut: Container2D { - fn get_mut(&mut self, i: I) -> Option<&mut Self::Output>; -} - -/// A 2D owning array of T -#[derive(Debug)] -pub struct Array2D { - pub data: [[T; N as usize]; M as usize], -} - -impl Container2D for Array2D { - type Output = T; - const HEIGHT: u32 = M; - const WIDTH: u32 = N; - - fn get(&self, i: I) -> Option<&Self::Output> { - let (r, c) = i.to_2d(Self::WIDTH); - self.data.get(r)?.get(c) - } -} - -impl Container2DMut for Array2D { - fn get_mut(&mut self, i: I) -> Option<&mut Self::Output> { - let (r, c) = i.to_2d(Self::WIDTH); - self.data.get_mut(r)?.get_mut(c) - } -} - -/// A 2D immutable view into a Container2D -#[derive(Debug)] -pub struct View2D<'a, D: Container2D, const M: u32, const N: u32> { - r: u32, - c: u32, - data: &'a D, -} - -impl<'a, D: Container2D, const M: u32, const N: u32> Container2D for View2D<'a, D, M, N> { - type Output = D::Output; - const HEIGHT: u32 = M; - const WIDTH: u32 = N; - - fn get(&self, i: I) -> Option<&Self::Output> { - self.data - .get(i.to_2d_offset(Self::WIDTH, Self::HEIGHT, self.r, self.c)?) - } -} - -impl<'a, D: Container2DMut, const M: u32, const N: u32> Container2D for Slice2D<'a, D, M, N> { - type Output = D::Output; - const HEIGHT: u32 = M; - const WIDTH: u32 = N; - - fn get(&self, i: I) -> Option<&Self::Output> { - self.data - .get(i.to_2d_offset(Self::WIDTH, Self::HEIGHT, self.r, self.c)?) - } -} - -/// A 2D mutable view into a Container2D -#[derive(Debug)] -pub struct Slice2D<'a, D: Container2DMut, const M: u32, const N: u32> { - r: u32, - c: u32, - data: &'a mut D, -} - -impl<'a, D: Container2DMut, const M: u32, const N: u32> Container2DMut for Slice2D<'a, D, M, N> { - fn get_mut(&mut self, i: I) -> Option<&mut Self::Output> { - self.data - .get_mut(i.to_2d_offset(Self::WIDTH, Self::HEIGHT, self.r, self.c)?) - } -} - -// An immutable transposition of a Container2D -#[derive(Debug)] -pub struct Transpose<'a, D: Container2D> { - pub data: &'a D, -} - -impl<'a, D: Container2D> Container2D for Transpose<'a, D> { - type Output = D::Output; - const HEIGHT: u32 = D::WIDTH; - const WIDTH: u32 = D::HEIGHT; - - fn get(&self, i: I) -> Option<&Self::Output> { - let (r, c) = i.to_2d(Self::WIDTH); - self.data.get((c, r)) - } -} diff --git a/src/Index2D.rs b/src/Index2D.rs deleted file mode 100644 index c43317f..0000000 --- a/src/Index2D.rs +++ /dev/null @@ -1,28 +0,0 @@ -pub trait Index2D { - fn to_1d(&self, width: u32) -> u32 { - let (r, c) = self.to_2d(width); - r * width + c - } - - fn to_2d(&self, width: u32) -> (u32, u32); - - fn to_2d_offset(&self, width: u32, height: u32, r: u32, c: u32) -> Option<(u32, u32)> { - let (row, col) = self.to_2d(width); - if row >= height || col >= width { - return None; - }; - Some((row + r, col + c)) - } -} - -impl Index2D for u32 { - fn to_2d(&self, width: u32) -> (u32, u32) { - (*self / width, *self % width) - } -} - -impl Index2D for (u32, u32) { - fn to_2d(&self, _: u32) -> (u32, u32) { - *self - } -} diff --git a/src/containers.rs b/src/containers.rs new file mode 100644 index 0000000..f6601fa --- /dev/null +++ b/src/containers.rs @@ -0,0 +1,180 @@ +use index::Index2D; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; + +pub mod index; +pub mod iter; + +/// This trait exists to allow structs like Slice2D to require Get2D, without +/// storing the dimensions of the target as part of its own generic parameters +pub trait Get2D { + type Scalar: Sized + Copy; + const HEIGHT: usize; + const WIDTH: usize; + + fn get(&self, i: I) -> Option<&Self::Scalar>; +} + +pub trait Get2DMut: Get2D { + fn get_mut(&mut self, i: I) -> Option<&mut Self::Scalar>; +} + +pub trait Get2DSized: Get2D {} + +/// A 2D owning array of T +#[derive(Debug, Clone, Copy)] +pub struct Array2D +where + T: Copy + 'static, +{ + pub data: [[T; N]; M], +} + +impl Default for Array2D +where + T: Default + Copy, +{ + fn default() -> Self { + Array2D { + data: [[T::default(); N]; M], + } + } +} + +impl Get2D for Array2D { + type Scalar = T; + const HEIGHT: usize = M; + const WIDTH: usize = N; + + fn get(&self, i: I) -> Option<&Self::Scalar> { + let (r, c) = i.to_2d(Self::WIDTH); + self.data.get(r)?.get(c) + } +} + +impl Get2DMut for Array2D { + fn get_mut(&mut self, i: I) -> Option<&mut Self::Scalar> { + let (r, c) = i.to_2d(Self::WIDTH); + self.data.get_mut(r)?.get_mut(c) + } +} + +impl Get2DSized for Array2D {} + +/// A 2D mutable view into a container +#[derive(Debug, Clone, Copy)] +pub struct Slice2D<'a, R, const M: usize, const N: usize> +where + R: Deref, + R::Target: Get2D + 'a, +{ + target: R, + r: usize, + c: usize, + phantom: PhantomData<&'a ()>, +} + +impl<'a, R, const M: usize, const N: usize> Slice2D<'a, R, M, N> +where + R: Deref, + R::Target: Get2D + 'a, +{ + pub fn new(target: R, r: usize, c: usize) -> Self { + Self { + target, + r, + c, + phantom: PhantomData, + } + } +} + +impl<'a, R, D, const M: usize, const N: usize> Get2D for Slice2D<'a, R, M, N> +where + R: Deref, + D: Get2D, +{ + type Scalar = <::Target as Get2D>::Scalar; + const HEIGHT: usize = M; + const WIDTH: usize = N; + + fn get(&self, i: I) -> Option<&Self::Scalar> { + self.target + .get(i.to_2d_offset(Self::WIDTH, Self::HEIGHT, self.r, self.c)?) + } +} + +impl<'a, R, D, const M: usize, const N: usize> Get2DMut for Slice2D<'a, R, M, N> +where + R: Deref + DerefMut, + D: Get2DMut, +{ + fn get_mut(&mut self, i: I) -> Option<&mut Self::Scalar> { + self.target + .get_mut(i.to_2d_offset(Self::WIDTH, Self::HEIGHT, self.r, self.c)?) + } +} + +impl<'a, R, D, const M: usize, const N: usize> Get2DSized for Slice2D<'a, R, M, N> +where + R: Deref, + D: Get2D, +{ +} + +// A transposition of a 2D container +#[derive(Debug, Clone, Copy)] +pub struct Transpose<'a, R> +where + R: Deref, + R::Target: Get2D + 'a, +{ + target: R, + phantom: std::marker::PhantomData<&'a ()>, +} + +impl<'a, R> Transpose<'a, R> +where + R: Deref, + R::Target: Get2D + 'a, +{ + fn new(target: R) -> Self { + Self { + target, + phantom: PhantomData, + } + } +} + +impl<'a, R, D> Get2D for Transpose<'a, R> +where + R: Deref, + D: Get2D, +{ + type Scalar = D::Scalar; + const HEIGHT: usize = D::WIDTH; + const WIDTH: usize = D::HEIGHT; + + fn get(&self, i: I) -> Option<&Self::Scalar> { + let (r, c) = i.to_2d(Self::WIDTH); + self.target.get((c, r)) + } +} + +impl<'a, R, D> Get2DMut for Transpose<'a, R> +where + R: DerefMut, + D: Get2DMut, +{ + fn get_mut(&mut self, i: I) -> Option<&mut Self::Scalar> { + let (r, c) = i.to_2d(Self::WIDTH); + self.target.get_mut((c, r)) + } +} + +impl<'a, R, D, const M: usize, const N: usize> Get2DSized for Transpose<'a, R> +where + R: Deref, + D: Get2DSized, +{ +} diff --git a/src/containers/index.rs b/src/containers/index.rs new file mode 100644 index 0000000..40ab86b --- /dev/null +++ b/src/containers/index.rs @@ -0,0 +1,34 @@ +pub trait Index2D: Copy { + fn to_1d(&self, width: usize) -> usize { + let (r, c) = self.to_2d(width); + r * width + c + } + + fn to_2d(&self, width: usize) -> (usize, usize); + + fn to_2d_offset( + &self, + width: usize, + height: usize, + r: usize, + c: usize, + ) -> Option<(usize, usize)> { + let (row, col) = self.to_2d(width); + if row >= height || col >= width { + return None; + }; + Some((row + r, col + c)) + } +} + +impl Index2D for usize { + fn to_2d(&self, width: usize) -> (usize, usize) { + (*self / width, *self % width) + } +} + +impl Index2D for (usize, usize) { + fn to_2d(&self, _: usize) -> (usize, usize) { + *self + } +} diff --git a/src/containers/iter.rs b/src/containers/iter.rs new file mode 100644 index 0000000..71b8bef --- /dev/null +++ b/src/containers/iter.rs @@ -0,0 +1,39 @@ +use super::Get2D; +use std::iter::FusedIterator; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct ElementIter<'a, D> +where + D: Get2D, +{ + data: &'a D, + index: usize, +} + +impl<'a, D: Get2D> ElementIter<'a, D> { + pub(crate) fn new(data: &'a D) -> ElementIter { + ElementIter { data, index: 0 } + } +} + +impl<'a, D: Get2D> Iterator for ElementIter<'a, D> { + type Item = &'a D::Scalar; + + fn next(&mut self) -> Option { + let result = self.data.get(self.index); + self.index += 1; + result + } + + fn size_hint(&self) -> (usize, Option) { + let total = D::WIDTH * D::HEIGHT; + (total - self.index, Some(total - self.index)) + } +} + +impl<'a, D: Get2D> ExactSizeIterator for ElementIter<'a, D> { + fn len(&self) -> usize { + self.index - D::WIDTH * D::HEIGHT + } +} +impl<'a, D: Get2D> FusedIterator for ElementIter<'a, D> {} diff --git a/src/lib.rs b/src/lib.rs index eeaca96..6be022b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,2 @@ -mod Container2D; -mod Index2D; +mod containers; +mod matrix; diff --git a/src/matrix.rs b/src/matrix.rs new file mode 100644 index 0000000..0243e69 --- /dev/null +++ b/src/matrix.rs @@ -0,0 +1,90 @@ +use crate::containers::index::Index2D; +use crate::containers::iter::ElementIter; +use crate::containers::{Array2D, Get2D, Get2DMut, Get2DSized, Slice2D}; +use std::ops::{Add, Index, IndexMut}; + +type Matrix = GenericMatrix, M, N>; + +#[derive(Debug, Copy, Clone)] +struct GenericMatrix, const M: usize, const N: usize> { + data: D, +} + +impl, const M: usize, const N: usize> GenericMatrix { + fn elements(&self) -> ElementIter> { + ElementIter::new(self) + } +} + +impl + Copy, const M: usize, const N: usize> Default for GenericMatrix +where + D: Default, +{ + fn default() -> Self { + GenericMatrix { data: D::default() } + } +} +// impl Matrix +// where +// D::Scalar: Default, +// { +// fn new(data: &[&[D::Scalar]]) -> Result {} +// } + +impl, const M: usize, const N: usize> Get2D for GenericMatrix { + type Scalar = D::Scalar; + const HEIGHT: usize = D::HEIGHT; + const WIDTH: usize = D::WIDTH; + + fn get(&self, i: I) -> Option<&Self::Scalar> { + self.data.get(i) + } +} + +impl, const M: usize, const N: usize> Get2DMut + for GenericMatrix +{ + fn get_mut(&mut self, i: I) -> Option<&mut Self::Scalar> { + self.data.get_mut(i) + } +} + +impl, I: Index2D, const M: usize, const N: usize> Index + for GenericMatrix +{ + type Output = D::Scalar; + + fn index(&self, index: I) -> &Self::Output { + self.get(index).expect(&*format!( + "Index {:?} out of range for {} x {} matrix", + index.to_2d(D::WIDTH), + D::HEIGHT, + D::WIDTH + )) + } +} + +impl, I: Index2D, const M: usize, const N: usize> IndexMut + for GenericMatrix +{ + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.get_mut(index).expect(&*format!( + "Index {:?} out of range for {} x {} matrix", + index.to_2d(D::WIDTH), + D::HEIGHT, + D::WIDTH + )) + } +} + +impl, const M: usize, const N: usize> Get2DSized + for GenericMatrix +{ +} + +fn foo() { + let mut a: Matrix = Default::default(); + let c = Slice2D::<&Matrix, 3, 3>::new(&a, 2, 2); + let b = Slice2D::<&mut Matrix, 3, 3>::new(&mut a, 1, 1); + println!("{:?} {:?}", b, c) +}