I am doing my CG homework using Rust. When it comes to overloading operators, it seems I have to write really verbose code to get it usable.
Say, I have a pub struct Vec3
, and I want an element-wise addition and a broadcast addition. I have to write the below, so that +
can work with references.
#[derive(Debug, Copy, Clone)]
pub struct Vec3
{
data: [f32; 3]
}
impl Vec3
{
pub fn new(x: f32, y: f32, z: f32) -> Self
{
Vec3 {
data: [x, y, z]
}
}
}
// impl ops::Add for Vec3
// {
// type Output = Vec3;
//
// fn add(self, rhs: Self) -> Self::Output {
// let data = [self.data[0] + rhs.data[0], self.data[1] + rhs.data[1], self.data[2] + rhs.data[2]];
// Vec3 {
// data
// }
// }
// }
// impl ops::Add<Vec3> for &Vec3
// {
// type Output = Vec3;
//
// fn add(self, rhs: Vec3) -> Self::Output {
// let data = [self.data[0] + rhs.data[0], self.data[1] + rhs.data[1], self.data[2] + rhs.data[2]];
// Vec3 {
// data
// }
// }
// }
impl ops::Add for &Vec3
{
type Output = Vec3;
fn add(self, rhs: Self) -> Self::Output {
let data = [self.data[0] + rhs.data[0], self.data[1] + rhs.data[1], self.data[2] + rhs.data[2]];
Vec3 {
data
}
}
}
impl ops::Add<&Self> for Vec3
{
type Output = Vec3;
fn add(self, rhs: &Self) -> Self::Output {
let data = [self.data[0] + rhs.data[0], self.data[1] + rhs.data[1], self.data[2] + rhs.data[2]];
Vec3 {
data
}
}
}
// broadcasting
impl ops::Add<f32> for Vec3
{
type Output = Vec3;
fn add(self, rhs: f32) -> Self::Output {
let data = [self.data[0] + rhs, self.data[1] + rhs, self.data[2] + rhs];
Vec3 {
data
}
}
}
impl ops::Add<f32> for &Vec3
{
type Output = Vec3;
fn add(self, rhs: f32) -> Self::Output {
let data = [self.data[0] + rhs, self.data[1] + rhs, self.data[2] + rhs];
Vec3 {
data
}
}
}
I understand that the ownership matters, so I commented codes in the middle to avoid taking the ownership, but I think the rest is basically the same (conceptually). Is there any macros or ways to overload operators regardless whether the left hand side is a reference or a value?
Since the below lines should be equivalent, it makes sense to ignore whether the left hand side is a reference.
let val = Vec3::new(1.0,1.0,1.0);
let reference = &val;
let result1 = val + 1.0;
let result2 = val.add(1.0);
let result3 = reference.add(1.0);
// so why not like below?
let result4 = reference + 1.0; // my code compiles, but I have to explicitly `impl ops::Add<f32> for &Vec3`
I tried the below code using blanket implementation, but it cannot compile due to the orphan rule.
impl<T: Add<f32>> Add<f32> for &T
{
type Output = T::Output;
fn add(self, rhs: f32) -> Self::Output {
self.add(rhs)
}
}