[dependencies]
symm_impl = "0.1"
use symm_impl::symmetric;
trait Distance<Other> {
fn distance(&self, other: &Other) -> f64;
}
struct Point2D {
x: f64,
y: f64,
}
struct Disk {
center: Point2D,
radius: f64
}
impl Distance<Point2D> for Point2D {
fn distance(&self, other: &Point2D) -> f64 {
let dx = self.x - other.x;
let dy = self.y - other.y;
(dx * dx + dy * dy).sqrt()
}
}
#[symmetric]
impl Distance<Disk> for Point2D {
fn distance(&self, other: &Disk) -> f64 {
let p_diff = self.distance(&other.center);
if p_diff.le(&other.radius) {
0.0_f64
} else {
p_diff - other.radius
}
}
}
/* Expands to
impl Distance<Point2D> for Disk {
#[allow(unused_mut)]
#[inline]
fn distance(&self, other: &Point2D) -> f64 {
<Point2D as Distance>::distance(other, self)
}
}
*/
In computational geometry (and potentially other areas), it is common to have symmetric binary operator between two different types. For example, distance between two different shapes, and intersection between two different shapes. In these cases, one would expect to only need to implement the operator in one direction and automatically derive the other.
This attribute macro automatically implements the "mirrored" version of an implementation to save a few keystroke and make the code looks slightly cleaner.
We require the trait to have the following property to be symmetric:
- Trait must be generic, with the first non-lifetime parameter being the type for the symmetry.
- All the methods in the trait must take exactly 2 arguments, where the first argument is a receiver (
self
,&self
,&mut self
) and the other argument is of the type for the symmetry. The two arguments must have the same family in the sense that they should both or neither be reference or mutable.
Licensed under either of:
at your option.