Reputation: 101513
I'm attempting to use nalgebra's VectorN
type to implement some dimension-agnostic calculations, but I'm getting some odd errors around the Copy
trait. The below contrived test case demonstrates the problem:
extern crate nalgebra;
use nalgebra::allocator::Allocator;
use nalgebra::{DefaultAllocator, DimName, Real, VectorN};
#[derive(Clone, Debug, Copy, PartialEq)]
pub struct LinearPathSegment<N: Real, D: DimName>
where
DefaultAllocator: Allocator<N, D>,
{
pub some_vec: VectorN<N, D>,
pub some_scalar: N,
}
Clone and run cargo build
in this repo to reproduce
The error output by the compiler (rustc 1.29.1 (b801ae664 2018-09-20)) is this:
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/lib.rs:6:24
|
6 | #[derive(Clone, Debug, Copy, PartialEq)]
| ^^^^
...
11 | pub some_vec: VectorN<N, D>,
| --------------------------- this field does not implement `Copy`
I'm certain that VectorN
does implement Copy
; by following the type aliases through the chain VectorN<...> -> MatrixMN<...> -> Matrix<...>
we see that Copy
is #[derive()]
d on Matrix
, which should mean it is derived for VectorN
too. Why is the compiler saying otherwise? What do I need to do to make VectorN
copyable?
Upvotes: 4
Views: 273
Reputation: 65822
You must add the bound Owned<N, D>: Copy
. Owned
is used as part of the MatrixMN
type alias. Owned
ends up being a type alias for MatrixArray
.
extern crate nalgebra;
use nalgebra::{DefaultAllocator, DimName, Real, VectorN};
use nalgebra::allocator::Allocator;
use nalgebra::storage::Owned;
#[derive(Clone, Debug, Copy, PartialEq)]
pub struct LinearPathSegment<N: Real, D: DimName>
where
DefaultAllocator: Allocator<N, D>,
Owned<N, D>: Copy,
{
pub some_vec: VectorN<N, D>,
pub some_scalar: N,
}
Real
requires Copy
, and DimName
requires Dim
which requires Copy
, so N
and D
don't need to have an explicit Copy
bound. But for some reason, the compiler is unable to prove that MatrixArray
is Copy
. I suspect this comes from the bound GenericArray<N, Prod<R::Value, C::Value>>: Copy
in its Copy
implementation.
Another option is to add the bound VectorN<N, D>: Copy
.
Note that either option forces every use of your struct to meet that bound. If that's not what you want, you must write a manual impl for Copy
with the appropriate bounds instead of deriving it.
impl<N, D> Copy for LinearPathSegment<N, D>
where
N: Real,
D: DimName,
DefaultAllocator: Allocator<N, D>,
VectorN<N, D>: Copy,
{
}
Upvotes: 4
Reputation: 42829
Deriving Copy
is special in this case, because Matrix
is generic:
#[repr(C)]
#[derive(Hash, Clone, Copy)]
pub struct Matrix<N: Scalar, R: Dim, C: Dim, S> {
/// The data storage that contains all the matrix components and informations about its number
/// of rows and column (if needed).
pub data: S,
_phantoms: PhantomData<(N, R, C)>,
}
The marker Copy
is implemented only if N
, R
, C
and S
are also Copy
.
Indeed, you can see this line in the Matrix
documentation page:
impl<N: Copy + Scalar, R: Copy + Dim, C: Copy + Dim, S: Copy> Copy for Matrix<N, R, C, S>
As a simpler example, this code compiles fine:
#[derive(Clone, Copy)]
struct DummyWrapper<T>(T);
fn main() {
}
But of course, you can copy DummyWrapper
only if T
is copyable too:
#[derive(Clone, Copy)]
struct DummyWrapper<T>(T);
fn consume<T>(_t: T) {}
fn main() {
// Ok
let a = DummyWrapper(42);
consume(a);
consume(a);
// Error: move occurs because `a` has type `DummyWrapper<std::string::String>`,
// which does not implement the `Copy` trait
let a = DummyWrapper(String::from("test"));
consume(a);
consume(a);
}
To make your struct copyable, I am only guessing, but you should add the following bounds:
N: Copy, D: Copy
Upvotes: 0