Hi there. I'm working on a small library that does some matrix math and decided to make it more generic. Instead of having a Matrix4x4 type, I was hoping to build a Matrix<M, N> type and use associated constants to create the underlying array. It seemed like this should be straight forward, but I have not been able to make the compiler happy.
I tried a handful of permutations, but the errors are the same and make me think I've run into an edge case not supported by the compiler--or I've completely misunderstood something (more likely). Any insight into what I could do here?
Thanks!
pub trait Size {
const VALUE: usize; // Two warnings here...
}
pub struct One;
pub struct Two;
pub struct Three;
pub struct Four;
impl Size for One { const VALUE: usize = 1; }
impl Size for Two { const VALUE: usize = 2; }
impl Size for Three { const VALUE: usize = 3; }
impl Size for Four { const VALUE: usize = 4; }
pub struct Matrix<M: Size, N: Size> {
matrix: [f32; <M as Size>::VALUE * <N as Size>::VALUE], // Two errors here
m: std::marker::PhantomData<M>,
n: std::marker::PhantomData<N>,
}
impl<M: Size, N: Size> Matrix<M, N> {
pub fn is_square(&self) -> bool {
// No errors, this works
<M as Size>::VALUE == <N as Size>::VALUE
}
pub fn size(&self) -> f32 {
// No errors, this works
<M as Size>::VALUE * <N as Size>::VALUE
}
pub fn new() -> Self {
// No errors, this works
let matrix = [0; <M as Size>::VALUE * <N as Size>::VALUE];
Self {
matrix,
m: std::marker::PhantomData,
n: std::marker::PhantomData,
}
}
}
impl<M: Size> Matrix<M, M> {
fn det(&self) -> f32 {
42.
}
}
#[inline]
pub fn new_zero<M: Size, N: Size>() -> Matrix<M, N> {
// This function appears to work...
let matrix = [0; <M as Size>::VALUE * <N as Size>::VALUE];
Matrix {
matrix,
m: std::marker::PhantomData,
n: std::marker::PhantomData,
}
}
type Matrix3x4 = Matrix<Three, Four>;
fn main() {
let matrix4x4 = new_zero::<Four, Four>();
let det = matrix4x4.det();
assert_eq!(det, 42.);
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `M: Size` is not satisfied
--> src/main.rs:16:19
|
16 | matrix: [f32; <M as Size>::VALUE * <N as Size>::VALUE], // Two errors here
| ^^^^^^^^^^^^^^^^^^ the trait `Size` is not implemented for `M`
|
= help: consider adding a `where M: Size` bound
note: required by `Size::VALUE`
--> src/main.rs:2:5
|
2 | const VALUE: usize; // Two warnings here...
| ^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `N: Size` is not satisfied
--> src/main.rs:16:40
|
16 | matrix: [f32; <M as Size>::VALUE * <N as Size>::VALUE], // Two errors here
| ^^^^^^^^^^^^^^^^^^ the trait `Size` is not implemented for `N`
|
= help: consider adding a `where N: Size` bound
note: required by `Size::VALUE`
--> src/main.rs:2:5
|
2 | const VALUE: usize; // Two warnings here...
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
error: Could not compile `playground`.
To learn more, run the command again with --verbose.