#traits #macro-derive #derive #macro #procedural

macro no-std symm_impl

Attribute macro that automatically implements a symmetric trait

3 releases

0.1.2 Feb 21, 2021
0.1.1 Feb 21, 2021
0.1.0 Feb 21, 2021

#2133 in Rust patterns

MIT/Apache

22KB
195 lines

Attribute macro that automatically implements a symmetric trait

crate Docs Apache2/MIT licensed Build Status

[dependencies]
symm_impl = "0.1"

Example

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)
    }
}
*/

Details

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.

License

Licensed under either of:

at your option.

Dependencies

~1.5MB
~37K SLoC