iliekturtles / uom

Units of measurement -- type-safe zero-cost dimensional analysis
Apache License 2.0
1.01k stars 92 forks source link

Support references to other units in a unit's conversion factor #154

Open iliekturtles opened 5 years ago

iliekturtles commented 5 years ago

Support references to other units in a unit's conversion factor.

via #31

For unit aliases it would be cool if the following were possible:

@bit: prefix!(none) / 8.0; "b", "bit", "bits";
@shannon: @bit; "Sh", "shannon", "shannons";

And for conversions:

@deciban: prefix!(deci) * @hartley; "dHart", "deciban", "decibans";
Lukazoid commented 5 years ago

I have found I am able to do this:

@shannon: <super::bit as crate::Conversion<Self::T>>::coefficient(); "Sh", "shannon", "shannons";

And

@deciban: prefix!(deci) * <super::hartley as crate::Conversion<Self::T>>::coefficient(); "dHart", "deciban", "decibans";

However it's not the most concise, perhaps a macro to generate the equivalent?

iliekturtles commented 5 years ago

Updating the @coefficient and @constant arms of the quantity! macro was what I was first thinking. I've had troubles replacing a single token (e.g. @bit) in an arbitrary expression in the past but that is where to start looking.

https://github.com/iliekturtles/uom/blob/0dd06308484ea415c87b0b762004286966e3fc3e/src/quantity.rs#L497-L505

Alternatively, and I just thought of this while writing my response, would be to do the expansion with a totally separate macro (or arm of an existing macro):

@deciban: prefix!(deci) * unit_macro_or_arm_in_existing_macro!(hartley); "dHart", "deciban", "decibans";
iliekturtles commented 5 years ago

For reference this didn't end up getting completed as part of #158. There were issues with some underlying storage types such as BigInt. See the error message below along with the code for the two macros.

error[E0277]: the trait bound `si::information_rate::bit_per_second: Conversion<num_rational::Ratio<num_
bigint::BigInt>>` is not satisfied
  --> src\unit_coef.rs:6:9
   |
6  |         <super::$other_unit as $crate::Conversion<Self::T>>::coefficient()
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Conversion<num_
rational::Ratio<num_bigint::BigInt>>` is not implemented for `si::information_rate::bit_per_second`
   |
  ::: src\si\information_rate.rs:53:46
   |
53 |         @yobibit_per_second: prefix!(yobi) * unit_coef!(bit_per_second); "Yib/s",
   |                                              -------------------------- in this macro invocation
   |
   = help: the following implementations were found:
             <si::information_rate::bit_per_second as Conversion<num_bigint::BigInt>>
/// A macro to reference the coefficient for another unit in the same quantity.
/// Note that this macro must be executed within a unit's conversion definition.
#[macro_export]
macro_rules! unit_coef {
    ($other_unit:ident) => {
        <super::$other_unit as $crate::Conversion<Self::T>>::coefficient()
    };
}
/// A macro to reference the constant for another unit in the same quantity.
/// Note that this macro must be executed within a unit's conversion definition.
#[macro_export]
macro_rules! unit_const {
    ($other_unit:ident) => {
        <super::$other_unit as $crate::Conversion<Self::T>>::constant()
    };
}