0

I'm trying to create a nice interface for physics measures like angles, mass, velocities, etc. I want them to offer dimensional analysis checking at compile-time, ideally with zero runtime overhead. I think Rust could be very well-suited for this, especially with traits.

What I have so far looks something like this:

pub trait Measure {
    type Underlying: Clone; // the underlying storage type (most often a Float)

    fn name() -> &'static str;
    fn default_unit() -> &'static str;
    fn in_default_unit(&self) -> Self::Underlying;
    fn from_default_unit(m: Self::Underlying) -> Self;
}

and an implementation would be something like:

#[derive(Debug, Clone, PartialEq)]
pub struct Angle<'a> {
    radians: Float, // dynamic but either a `f64` or `f32`
}

impl<'a> Angle<'a> {
    fn from_radians(radians: Float) -> Self {
        Self { radians }
    }
}

impl<'a> Measure<'a> for Angle<'a> {
    type Underlying = Float;

    fn name() -> &'static str {
        "angle"
    }

    fn default_unit() -> &'static str {
        "radian"
    }

    fn in_default_unit(&self) -> Self::Underlying {
        self.radians
    }

    fn from_default_unit(m: Self::Underlying) -> Self {
        Self::from_radians(m)
    }
}

I want to add common operations like overloading the + operator and similar, but I want to do this in such a way that it's linked to the Measure trait so I don't have to create it for every Measure.

I've tried making an intermediate class for operations that Angle could Deref but ran into some issues with lifetimes, and I think that route might actually be impossible.

This seems to me like it's a common enough need that there's a solution. How can I do this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
River Tam
  • 3,096
  • 4
  • 31
  • 51

1 Answers1

0

There are a number of ways to do this, primarily involving either macros or procedural macros. This method is actually pretty well described in one of Shepmaster's answers, but the route I'm going to take will probably use the derive_more crate which will allow me to very easily provide these convenience functions.

Then I can just

#[macro_use]
extern crate derive_more;

#[derive(Add)]
struct Angle {
    radians: Float,
}
River Tam
  • 3,096
  • 4
  • 31
  • 51