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?