uom
uom copied to clipboard
Suggestion: Use one of `std::ops` to gain support for "literals"
So it does what the title says: use one of std::ops
, so that it can be used to create "literals" of that unit.
implementation should be simple, something like (I'm using metre and f64 as an example here, but it should be possible to do for all units, and Rem can be any of std::ops
)
impl Rem<meter> for f64 {
type Output = Length<meter, f64>;
fn rem(self, _: meter) -> Self::Output {
Length::new::<meter>(self)
}
}
and then the user can use
let a = 5.0 % meter;
I'm not sure of the implementation of Length
and other things within uom
, but this should be able to provide a simple syntax sugar, which should make it easier and less verbose to use uom
I've written up a demo of what this could look like here:
https://github.com/shingtaklam1324/units-test/blob/f0c7868c875ecf0057a02dd1130a0cae2a9b0f01/src/main.rs#L20-L42
The syntax seems to be quite clean, although it may be better to choose an operator which isn't used as much, or something like &&
which shouldn't be implemented for the number types
Using *
or /
should likely be possible rather than choosing an arbitrary operator since all units are their own type. It may be as simple as adding impl blocks in quantity.rs
for each storage type/unit combination. I'll take a look in more detail as I get some time. Until then PRs are welcome.
uom $ cargo run --example mks
Compiling uom v0.18.0 (file:///.../uom)
error[E0277]: cannot multiply `length::meter` to `{float}`
--> examples\mks.rs:9:18
|
9 | let _x = 1.0 * meter;
| ^ no implementation for `{float} * length::meter`
|
= help: the trait `std::ops::Mul<length::meter>` is not implemented for `{float}`
Any news on this?
I haven't had much time recently, but this issue is on the short list for review and likely inclusion in a v1.0.0 release.
I was also looking for being able to use Add
and Mul
between primitive types and units to be able to give them a unit:
use uom::si::units::*;
let len = 1 * m; // si::Length
let freq = 1 / s; // si::Frequency
let vel = len * freq; // si::Velocity
I feel like it's frowned upon to use operator overloads for an operation which doesn't match the symbol you normally use it for (e.g. *
would be good for matrix multiplies, but %
to attach a unit to a number feels odd)... What about defining extension traits which add methods to the primitive types instead?
For example,
trait LengthExt {
fn metres(self) -> Length;
}
impl LengthExt for f64 {
fn metres(self) -> Length { Length::new::<meter>(self) }
}
Then you'd be able to write code like 3.0.metres() * 5.0.seconds()
.
You'd need to try it out in your own code to tell whether this is going to be just a cute trick or genuinely useful syntactic sugar though...