Reputation: 33
I'm working on a simple opengl wrapper library in rust.
Im using nalgebra_glm crate for the math operations. Lots of types implement AsRef
for the access to the underlying array. I manually implemented Uniform
for array types that match common matrix sizes like [[T; 4]; 4]
, [T; 16]
, [T; 3]
and so on.
So I can obtain a new Box<dyn Uniform>
by calling Box::new(<nalgebra_glm matrix or vector>.as_ref().clone())
but it's unnecessarily verbose.
I wanted to create a convenience function that converts any &[T]
which is Clone
and AsRef
to some type U
that implements Uniform
into Vec<Box<dyn Uniform>>
. Something similar to ToOwned
trait.
Here's what I came up with.
pub trait Uniform {
fn bind(&self, location: GLint);
}
pub fn to_owned<U: Uniform + Clone, T: AsRef<U>>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
where Vec<Box<dyn Uniform>>: FromIterator<Box<U>>
{
uniforms.into_iter()
.map(AsRef::as_ref)
.map(Clone::clone)
.map(Box::new)
.collect()
}
But then when I tried using this function in the following context it caused and error which I'm struggling to understand.
perspective_matrix()
and view_matrix()
are both of type Mat4
and provide a AsRef<[[f32; 4]; 4]
.
let common_uniforms = to_owned(&[camera.perspective_matrix(), camera.view_matrix()]);
error[E0277]: the trait bound `(dyn Uniform + 'static): Clone` is not satisfied
--> src\main.rs:167:27
|
167 | let common_uniforms = to_owned(&[camera.perspective_matrix(), camera.view_matrix()]);
| ^^^^^^^^ the trait `Clone` is not implemented for `(dyn Uniform + 'static)`
|
note: required by a bound in `uniform::to_owned`
--> src\uniform.rs:9:30
|
9 | pub fn to_owned<U: Uniform + Clone, T: AsRef<U>>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
| ^^^^^ required by this bound in `uniform::to_owned`
Why is Clone
required by the resulting trait object? clone
is only needed during operations on generic U
and thus only U
should implement Clone
. Why does it have anything to do with the final trait object? I would expect that since U
implements Uniform
it should be possible to create a dyn Uniform
trait object out of it.
Also I cannot require Clone
as super trait for Uniform
since it would make it not object safe.
I have tried explicitly casting resulting box type into trait object, adding 'static
lifetime bound but to no avail.
pub fn to_owned<U: 'static + Uniform + Clone, T: AsRef<U>>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
where Vec<Box<dyn Uniform>>: FromIterator<Box<U>>
{
uniforms.into_iter()
.map(AsRef::as_ref)
.map(Clone::clone)
.map(|uniform| Box::new(uniform) as Box<dyn Uniform>)
.collect()
}
I really don't understand what's wrong with my code. It's either that I'm doing some syntactic mistake or there's deeper logical error with what I'm trying to accomplish here.
I would greatly appreciate any help.
Upvotes: 1
Views: 229
Reputation: 22728
The main problem is your to_owned
function.
With where Vec<Box<dyn Uniform>>: FromIterator<Box<U>>
you are actually hiding the real problem, causing very confusing compiler messages.
You probably added this because the compiler suggested it. But the compiler also warns that while this is what it needs, adding the where
clause is probably not the correct solution.
With the where
clause, instead of specifying correct bounds that make the conversion possible, you just move the problem out of the function. I agree with the compiler that this is the wrong solution.
Your second attempt is almost correct, all you are missing is that you need to remove the where
clause:
use nalgebra_glm::Mat4;
fn perspective_matrix() -> Mat4 {
todo!()
}
pub trait Uniform {
fn bind(&self, location: i32);
}
impl Uniform for [[f32; 4]; 4] {
fn bind(&self, _location: i32) {
todo!()
}
}
pub fn to_owned<T, U>(uniforms: &[T]) -> Vec<Box<dyn Uniform>>
where
T: AsRef<U>,
U: Uniform + Clone + 'static,
{
uniforms
.into_iter()
.map(AsRef::as_ref)
.map(Clone::clone)
.map(|uniform| Box::new(uniform) as Box<dyn Uniform>)
.collect()
}
fn main() {
let _common_uniforms = to_owned(&[perspective_matrix()]);
}
Also, this is how a minimal reproducible example looks like ;)
Upvotes: 0