I'm trying to interface glium with cgmath. Following this answer, I have implemented a ToArray
trait to convert instances of cgmath::Matrix4
into a format usable by glium:
pub trait ToArray {
type Output;
fn to_array(&self) -> Self::Output;
}
impl<S: cgmath::BaseNum> ToArray for cgmath::Matrix4<S> {
type Output = [[S; 4]; 4];
fn to_array(&self) -> Self::Output {
(*self).into()
}
}
Since I don't always use Matrix4
directly, I need a similar implementation for cgmath transform types. For example for cgmath::Decomposed
:
impl<S: cgmath::BaseFloat, R: cgmath::Rotation3<S>> ToArray
for cgmath::Decomposed<cgmath::Vector3<S>, R> {
type Output = [[S; 4]; 4];
fn to_array(&self) -> Self::Output {
cgmath::Matrix4::<S>::from(*self).into()
}
}
This works, but I'd like to avoid duplicating the code for all transform types, so I thought I would define a generic implementation for anything that can be converted to a Matrix4
:
impl<S: cgmath::BaseFloat, T: Into<cgmath::Matrix4<S>>> ToArray for T {
type Output = [[S; 4]; 4];
fn to_array(&self) -> Self::Output {
cgmath::Matrix4::<S>::from(*self).into()
}
}
Unfortunately, this doesn't work:
error[E0207]: the type parameter `S` is not constrained by the impl trait, self type, or predicates
--> src/main.rs:23:6
|
23 | impl<S: cgmath::BaseFloat, T: Into<cgmath::Matrix4<S>>> ToArray for T {
| ^ unconstrained type parameter
I have two questions:
rustc --explain
output, I would expect the T: Into<cgmath::Matrix4<S>>
to act as a valid constraint on S
as well as T
.Matrix4
?Imagine I defined a type like this1:
struct PolymorphicMatrix;
impl Into<cgmath::Matrix4<f32>> for PolymorphicMatrix {
fn into(self) -> cgmath::Matrix4<f32> {
cgmath::Matrix4::new(
1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0)
}
}
impl Into<cgmath::Matrix4<f64>> for PolymorphicMatrix {
fn into(self) -> cgmath::Matrix4<f64> {
cgmath::Matrix4::new(
2.0, 2.0, 2.0, 2.0,
2.0, 2.0, 2.0, 2.0,
2.0, 2.0, 2.0, 2.0,
2.0, 2.0, 2.0, 2.0)
}
}
Which of these impls will be used to implement ToArray
? Both are applicable, but you can only implement ToArray
once for PolymorphicMatrix
, because ToArray
has no type parameters. That's what the error means: it's not valid because it would cause issues in a situation like this.
Since you control neither Into
nor cgmath::Matrix4
, the only aspect you can change is ToArray
. You can add a type parameter that is not used in the trait definition itself, and implementations can use that type parameter.
pub trait ToArray<S> {
type Output;
fn to_array(&self) -> Self::Output;
}
impl<S: cgmath::BaseFloat, T: Into<cgmath::Matrix4<S>>> ToArray<S> for T {
type Output = [[S; 4]; 4];
fn to_array(&self) -> Self::Output {
cgmath::Matrix4::<S>::from(*self).into()
}
}
Naturally, you can't enforce any kind of correlation between S
and Output
. Also, that type parameter might cause some ambiguities: since it's not used in the trait, the compiler might not be able to infer S
from usage in some situations, so you may have to specify it explicitly. If that becomes a problem, you might want to explore using generic-array
. It would let you lift the array dimensions to type parameters, so that you could get rid of the associated type and instead use the type parameters directly in the return type of to_array
, which would help the compiler's inference.
1 Normally, one would implement From
rather than Into
. I'm using Into
here to stay closer to the problem as stated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With