Skip to content

Commit

Permalink
Add a Kind associated type to Dimensions.
Browse files Browse the repository at this point in the history
The new `Kind` associated type, defaulting to `uom::Kind`, allows for
multiple quantities that have the same dimensions. Quantities of
different kinds are not comparable. The marker traits implemented by a
quantity's `Kind` control which operations are automatically
implemented. Resolves #78.
  • Loading branch information
iliekturtles committed Aug 29, 2018
1 parent 73075f4 commit 2e5f237
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 5 deletions.
77 changes: 77 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,68 @@ pub mod num {
}
}

/// Primitive traits and types representing basic properties of types.
pub mod marker {
/// Trait to denote that a quantity is able to be added with a quantity of the same dimensions.
/// When a specific quantity's kind inherits this trait `ops::Add` is implemented
/// automatically.
pub trait Add {}

/// Trait to denote that a quantity is able to be added with a quantity of the same dimensions.
/// When a specific quantity's kind inherits this trait `ops::AddAssign` is implemented
/// automatically.
pub trait AddAssign {}

/// Trait to denote that a quantity is able to be subtracted with a quantity of the same
/// dimensions. When a specific quantity's kind inherits this trait `ops::Sub` is implemented
/// automatically.
pub trait Sub {}

/// Trait to denote that a quantity is able to be subtracted with a quantity of the same
/// dimensions. When a specific quantity's kind inherits this trait `ops::SubAssign` is
/// implemented automatically.
pub trait SubAssign {}

/// Trait to denote that a quantity is able to be multiplied with a quantity of the same
/// dimensions. When a specific quantity's kind inherits this trait `ops::Mul` is implemented
/// automatically.
pub trait Mul {}

/// Trait to denote that a quantity is able to be multiplied with a quantity of the same
/// dimensions. When a specific quantity's kind inherits this trait `ops::MulAssign` is
/// implemented automatically.
pub trait MulAssign {}

/// Trait to denote that a quantity is able to be divided with a quantity of the same
/// dimensions. When a specific quantity's kind inherits this trait `ops::Div` is implemented
/// automatically.
pub trait Div {}

/// Trait to denote that a quantity is able to be divided with a quantity of the same
/// dimensions. When a specific quantity's kind inherits this trait `ops::DivAssign` is
/// implemented automatically.
pub trait DivAssign {}

/// Trait to denote that a quantity is able to be negated. When a specific quantity's kind
/// inherits this trait `ops::Neg` is implemented automatically.
pub trait Neg {}

/// Trait to denote that a quantity is able to calculate a remainder with a quantity of the
/// same dimensions. When a specific quantity's kind inherits this trait `ops::Rem` is
/// implemented automatically.
pub trait Rem {}

/// Trait to denote that a quantity is able to calculate a remainder with a quantity of the
/// same dimensions. When a specific quantity's kind inherits this trait `ops::RemAssign` is
/// implemented automatically.
pub trait RemAssign {}

/// Trait to denote that a quantity is able to perform saturating additions and subtractions
/// with a quantity of the same dimensions. When a specific quantity's kind inherits this trait
/// `ops::Saturating` is implemented automatically.
pub trait Saturating {}
}

#[macro_use]
mod features;

Expand Down Expand Up @@ -314,6 +376,21 @@ pub trait ConversionFactor<V>
fn value(self) -> V;
}

/// Default [kind][kind] of quantities to allow addition, subtraction, multiplication, division,
/// remainder, negation, and saturating addition/subtraction.
///
/// [kind]: https://jcgm.bipm.org/vim/en/1.2.html
#[cfg_attr(rustfmt, rustfmt_skip)]
pub trait Kind
: marker::Add + marker::AddAssign
+ marker::Sub + marker::SubAssign
+ marker::Mul + marker::MulAssign
+ marker::Div + marker::DivAssign
+ marker::Rem + marker::RemAssign
+ marker::Neg + marker::Saturating
{
}

storage_types! {
types: Float;

Expand Down
24 changes: 23 additions & 1 deletion src/quantity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
/// * `$system`: System of quantities type (e.g. `ISQ`).
/// * `$dimension`: Power of a factor for each base quantity in the system. Power should be
/// represented as a `typenum` type-level integer (e.g. `N1`, `Z0`, `P1`, `P2`, ...).
/// * `$kind`: [Kind][kind] of the quantity. Optional. This variable should only be specified when
/// defining a quantity that has the same dimensions as another quantity but isn't comparable.
/// When not specified [`uom::Kind`](trait.Kind.html) is used.
/// * `$unit`: Unit name (e.g. `meter`, `foot`).
/// * `$conversion`: Conversion from the unit to the base unit of the quantity (e.g. `3.048E-1` to
/// convert `foot` to `meter`).
Expand Down Expand Up @@ -87,6 +90,7 @@
///
/// [quantity]: http://jcgm.bipm.org/vim/en/1.1.html
/// [measurement]: http://jcgm.bipm.org/vim/en/1.9.html
/// [kind]: https://jcgm.bipm.org/vim/en/1.2.html
#[macro_export]
macro_rules! quantity {
(
Expand All @@ -96,9 +100,27 @@ macro_rules! quantity {
$($(#[$unit_attr:meta])* @$unit:ident: $conversion:expr;
$abbreviation:expr, $singular:expr, $plural:expr;)+
}
) => {
quantity! {
$(#[$quantity_attr])* quantity: $quantity; $description;
$(#[$dim_attr])* dimension: $system<$($dimension),+>;
kind: $crate::Kind;
units {
$($(#[$unit_attr])* @$unit: $conversion; $abbreviation, $singular, $plural;)+
}
}
};
(
$(#[$quantity_attr:meta])* quantity: $quantity:ident; $description:expr;
$(#[$dim_attr:meta])* dimension: $system:ident<$($dimension:ident),+>;
kind: $kind:ty;
units {
$($(#[$unit_attr:meta])* @$unit:ident: $conversion:expr; $abbreviation:expr,
$singular:expr, $plural:expr;)+
}
) => {
$(#[$dim_attr])*
pub type Dimension = super::$system<$($crate::typenum::$dimension),+>;
pub type Dimension = super::$system<$($crate::typenum::$dimension),+, $kind>;

$(#[$quantity_attr])*
pub type $quantity<U, V> = super::Quantity<Dimension, U, V>;
Expand Down
9 changes: 9 additions & 0 deletions src/si/thermodynamic_temperature.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
//! Thermodynamic temperature (base unit kelvin, K<sup>1</sup>).
/// Kind of thermodynamic temperature.
pub trait Temperature
: ::marker::Mul + ::marker::MulAssign
+ ::marker::Div + ::marker::DivAssign
+ ::marker::Rem + ::marker::RemAssign
{
}

quantity! {
/// Thermodynamic temperature (base unit kelvin, K<sup>1</sup>).
quantity: ThermodynamicTemperature; "thermodynamic temperature";
Expand All @@ -12,6 +20,7 @@ quantity! {
P1, // thermodynamic temperature
Z0, // amount of substance
Z0>; // luminous intensity
kind: Temperature;
units {
@yottakelvin: prefix!(yotta); "YK", "yottakelvin", "yottakelvins";
@zettakelvin: prefix!(zetta); "ZK", "zettakelvin", "zettakelvins";
Expand Down
41 changes: 37 additions & 4 deletions src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ macro_rules! system {
pub trait Dimension: Send + Sync {
$(/// Quantity dimension.
type $symbol: $crate::typenum::Integer;)+

/// [Kind][kind] of the quantity. Quantities of the same dimension but differing kinds
/// are not comparable.
///
/// [kind]: https://jcgm.bipm.org/vim/en/1.2.html
type Kind: ?Sized;
}

/// Marker trait to identify a [system of units][units] based on a set of [base units][base]
Expand Down Expand Up @@ -229,14 +235,16 @@ macro_rules! system {
{
/// Quantity dimension. See [`Dimension`](./trait.Dimension.html).
pub dimension: $crate::lib::marker::PhantomData<D>,

/// Quantity base units. See [`Units`](./trait.Units.html).
pub units: $crate::lib::marker::PhantomData<U>,

/// Quantity value stored in the base units for the quantity.
pub value: V,
}

// Type alias for dimensions where all exponents of the factors are the given value.
type DN<N> = Dimension<$($symbol = system!(@replace $symbol N)),+>;
type DN<N> = Dimension<$($symbol = system!(@replace $symbol N),)+ Kind = $crate::Kind>;

/// Type alias for [dimension one][one] for which all the exponents of the factors
/// corresponding to the [base quantities][base] are zero.
Expand All @@ -247,7 +255,8 @@ macro_rules! system {
pub type DimensionOne = DN<$crate::typenum::Z0>;

$(#[$quantities_attr])*
pub type $quantities<$($symbol),+> = Dimension<$($symbol = $symbol),+>;
pub type $quantities<$($symbol,)+ K = $crate::Kind> =
Dimension<$($symbol = $symbol,)+ Kind = K>;

$(#[$units_attr])*
#[allow(unused_qualifications)]
Expand Down Expand Up @@ -324,6 +333,7 @@ macro_rules! system {
for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubTrait,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
Expand All @@ -344,6 +354,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::$AddSubTrait for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
Expand All @@ -364,6 +375,7 @@ macro_rules! system {
for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubAssignTrait,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>
Expand All @@ -379,6 +391,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::$AddSubAssignTrait for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$AddSubAssignTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>
+ $crate::lib::ops::$AddSubAssignTrait<V>,
Expand All @@ -395,7 +408,9 @@ macro_rules! system {
where
Dl: Dimension + ?Sized,
$(Dl::$symbol: $crate::lib::ops::$AddSubTrait<Dr::$symbol>,)+
Dl::Kind: $crate::marker::$MulDivTrait,
Dr: Dimension + ?Sized,
Dr::Kind: $crate::marker::$MulDivTrait,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::$MulDivTrait<V>,
Expand All @@ -409,8 +424,7 @@ macro_rules! system {
Quantity {
dimension: $crate::lib::marker::PhantomData,
units: $crate::lib::marker::PhantomData,
value: self.value
$muldiv_op change_base::<Dr, Ul, Ur, V>(&rhs.value),
value: self.value $muldiv_op change_base::<Dr, Ul, Ur, V>(&rhs.value),
}
}
}}
Expand All @@ -421,7 +435,9 @@ macro_rules! system {
where
Dl: Dimension + ?Sized,
$(Dl::$symbol: $crate::lib::ops::$AddSubTrait<Dr::$symbol>,)+
Dl::Kind: $crate::marker::$MulDivTrait,
Dr: Dimension + ?Sized,
Dr::Kind: $crate::marker::$MulDivTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::$MulDivTrait<V>,
{
Expand All @@ -442,6 +458,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::$MulDivTrait<V> for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$MulDivTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
Expand All @@ -460,6 +477,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::$MulDivAssignTrait<V> for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$MulDivAssignTrait,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>
+ $crate::lib::ops::$MulDivAssignTrait<V>,
Expand All @@ -478,6 +496,7 @@ macro_rules! system {
impl<D, U> $crate::lib::ops::$MulDivTrait<Quantity<D, U, V>> for V
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::$MulDivTrait,
U: Units<V> + ?Sized,
$($crate::typenum::Z0: $crate::lib::ops::$AddSubTrait<D::$symbol>,)+
{
Expand Down Expand Up @@ -592,6 +611,7 @@ macro_rules! system {
U, V>
where
$(D::$symbol: $crate::lib::ops::PartialDiv<$crate::typenum::P3>,)+
D::Kind: $crate::marker::Div,
V: $crate::num::Float,
{
Quantity {
Expand Down Expand Up @@ -667,8 +687,10 @@ macro_rules! system {
) -> Quantity<$quantities<$($crate::typenum::Sum<D::$symbol, Da::$symbol>),+>, U, V>
where
$(D::$symbol: $crate::lib::ops::Add<Da::$symbol>,)+
D::Kind: $crate::marker::Mul,
V: $crate::num::Float,
Da: Dimension + ?Sized,
Da::Kind: $crate::marker::Mul,
Ua: Units<V> + ?Sized,
Ub: Units<V> + ?Sized,
{
Expand All @@ -694,6 +716,7 @@ macro_rules! system {
) -> Quantity<$quantities<$($crate::typenum::Negate<D::$symbol>),+>, U, V>
where
$(D::$symbol: $crate::lib::ops::Neg,)+
D::Kind: $crate::marker::Div,
V: $crate::num::Float,
{
Quantity {
Expand All @@ -717,6 +740,7 @@ macro_rules! system {
) -> Quantity<$quantities<$($crate::typenum::Prod<D::$symbol, E>),+>, U, V>
where
$(D::$symbol: $crate::lib::ops::Mul<E>,)+
D::Kind: $crate::marker::Mul,
E: $crate::typenum::Integer,
V: $crate::typenum::Pow<E, Output = V> + $crate::Conversion<V>,
{
Expand Down Expand Up @@ -755,6 +779,7 @@ macro_rules! system {
U, V>
where
$(D::$symbol: $crate::typenum::PartialDiv<$crate::typenum::P2>,)+
D::Kind: $crate::marker::Div,
V: $crate::num::Float,
{
Quantity {
Expand Down Expand Up @@ -878,6 +903,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::Neg for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Neg,
U: Units<V> + ?Sized,
V: $crate::num::Signed + $crate::Conversion<V>,
{
Expand Down Expand Up @@ -1026,6 +1052,7 @@ macro_rules! system {
impl<D, Ul, Ur, V> $crate::lib::ops::Rem<Quantity<D, Ur, V>> for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Rem,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
Expand All @@ -1046,6 +1073,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::Rem for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Rem,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
Expand All @@ -1065,6 +1093,7 @@ macro_rules! system {
impl<D, Ul, Ur, V> $crate::lib::ops::RemAssign<Quantity<D, Ur, V>> for Quantity<D, Ul, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::RemAssign,
Ul: Units<V> + ?Sized,
Ur: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::RemAssign,
Expand All @@ -1079,6 +1108,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::ops::RemAssign for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::RemAssign,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::ops::RemAssign,
{
Expand All @@ -1091,6 +1121,7 @@ macro_rules! system {
impl<D, U, V> $crate::num::Saturating for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Saturating,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::num::Saturating,
{
Expand All @@ -1106,6 +1137,7 @@ macro_rules! system {
impl<D, U, V> $crate::lib::iter::Sum for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Add,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V> + $crate::lib::iter::Sum,
{
Expand Down Expand Up @@ -1148,6 +1180,7 @@ macro_rules! system {
impl<D, U, V> $crate::num::Zero for Quantity<D, U, V>
where
D: Dimension + ?Sized,
D::Kind: $crate::marker::Add,
U: Units<V> + ?Sized,
V: $crate::num::Num + $crate::Conversion<V>,
{
Expand Down

0 comments on commit 2e5f237

Please sign in to comment.