I am using nalgebra 0.31.4
and I successfully implemented a custom type called MyNum<T>
which I can store in nalgebra
vectors and matrices. My end goal is a bit more complicated, but the example below isolates the key issue I am having trouble with.
I want my custom type to be able to freely interact with other floats both as a scalar (e.g., my_num * 2
, etc.) and when part of a nalgebra
container, like a Vector2
.
By implementing Add
and AddAssign
I can support adding nalgebra vectors of MyNum
. I also implemented the traits necessary to add MyNum<f64>
and f64
instances.
However, I am struggling to come up with a way to add, e.g., a Vector3<MyNum<f64>>
to a Vector3<f64>>
. I cannot figure out which trait I am missing.
Here is the code I have so far, which allows the operations above, but not mixing vectors of MyNum and plain doubles, as noted by the comment on top of the last line of code:
use nalgebra::{RealField, Vector2};
use std::ops::{Add, AddAssign};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
struct MyNum<T> {
a: T,
b: T,
}
impl<T: RealField + Copy> Add for &MyNum<T> {
type Output = MyNum<T>;
fn add(self, rhs: Self) -> Self::Output {
MyNum {
a: self.a + rhs.a,
b: self.b + rhs.b,
}
}
}
impl<T: RealField + Copy> Add for MyNum<T> {
type Output = MyNum<T>;
fn add(self, rhs: Self) -> Self::Output {
MyNum {
a: self.a + rhs.a,
b: self.b + rhs.b,
}
}
}
// Note that we need this AddAssigns to support adding vectors containing MyNums, even if you don't explicitly AddAssign
// i.e., even if you just do '&v1 + &v2'.
impl<T: RealField + Copy> AddAssign for MyNum<T> {
fn add_assign(&mut self, rhs: Self) {
self.a += rhs.a;
self.b += rhs.b;
}
}
/// Adding a non-MyNum to MyNum.
impl<T: RealField + Copy> Add<T> for MyNum<T> {
type Output = MyNum<T>;
fn add(self, rhs: T) -> Self::Output {
MyNum {
a: self.a + rhs,
b: self.b + rhs,
}
}
}
impl<T: RealField + Copy> Add<&T> for MyNum<T> {
type Output = MyNum<T>;
fn add(self, rhs: &T) -> Self::Output {
MyNum {
a: self.a + *rhs,
b: self.b + *rhs,
}
}
}
impl<T: RealField + Copy> Add<T> for &MyNum<T> {
type Output = MyNum<T>;
fn add(self, rhs: T) -> Self::Output {
MyNum {
a: self.a + rhs,
b: self.b + rhs,
}
}
}
impl<T: RealField + Copy> Add<&T> for &MyNum<T> {
type Output = MyNum<T>;
fn add(self, rhs: &T) -> Self::Output {
MyNum {
a: self.a + *rhs,
b: self.b + *rhs,
}
}
}
impl<T: RealField + Copy> AddAssign<T> for MyNum<T> {
fn add_assign(&mut self, rhs: T) {
self.a += rhs;
self.b += rhs;
}
}
impl<T: RealField + Copy> AddAssign<T> for &mut MyNum<T> {
fn add_assign(&mut self, rhs: T) {
self.a += rhs;
self.b += rhs;
}
}
impl<T: RealField + Copy> AddAssign<&T> for MyNum<T> {
fn add_assign(&mut self, rhs: &T) {
self.a += *rhs;
self.b += *rhs;
}
}
impl<T: RealField + Copy> AddAssign<&T> for &mut MyNum<T> {
fn add_assign(&mut self, rhs: &T) {
self.a += *rhs;
self.b += *rhs;
}
}
fn main() {
let my_num = MyNum { a: 0.0, b: 15.0 };
println!("This works: {:?}", &my_num + 32.0f64);
let vec_a = Vector2::<MyNum<f64>>::new(MyNum { a: 0.0, b: 0.0 }, MyNum { a: 0.0, b: 0.0 });
let vec_b = Vector2::<MyNum<f64>>::new(MyNum { a: 0.0, b: 0.0 }, MyNum { a: 32.0, b: 64.0 });
println!("vec_a + vec_b: {:?}", &vec_a + &vec_b);
let vec_float = Vector2::<f64>::new(1.0, 2.0);
// The line below does not compile
println!("vec_float + a = {}", &vec_a + &vec_float);
}
Here is the error I get:
â°â⤠cargo run --release --bin my_num_vec_add 101 âĩ
Compiling fmad v0.1.0 (/Users/andrei/work/fmad)
error[E0277]: cannot add `&Matrix<f64, Const<3>, Const<1>, ArrayStorage<f64, 3, 1>>` to `&Matrix<MyNum<f64>, Const<3>, Const<1>, ArrayStorage<MyNum<f64>, 3, 1>>`
--> src/bin/my_num_vec_add.rs:147:43
|
147 | println!("vec_float + a = {}", &vec_a + &vec_float);
| ^ no implementation for `&Matrix<MyNum<f64>, Const<3>, Const<1>, ArrayStorage<MyNum<f64>, 3, 1>> + &Matrix<f64, Const<3>, Const<1>, ArrayStorage<f64, 3, 1>>`
|
= help: the trait `Add<&Matrix<f64, Const<3>, Const<1>, ArrayStorage<f64, 3, 1>>>` is not implemented for `&Matrix<MyNum<f64>, Const<3>, Const<1>, ArrayStorage<MyNum<f64>, 3, 1>>`
= help: the following other types implement trait `Add<Rhs>`:
<&'a Matrix<T, R1, C1, SA> as Add<&'b Matrix<T, R2, C2, SB>>>
<&'a Matrix<T, R1, C1, SA> as Add<Matrix<T, R2, C2, SB>>>
<Matrix<T, R1, C1, SA> as Add<&'b Matrix<T, R2, C2, SB>>>
<Matrix<T, R1, C1, SA> as Add<Matrix<T, R2, C2, SB>>>
For more information about this error, try `rustc --explain E0277`.
Thank you in advance for any pointers!