Skip to content

Commit

Permalink
Merge e126065 into 73075f4
Browse files Browse the repository at this point in the history
  • Loading branch information
iliekturtles committed Sep 6, 2018
2 parents 73075f4 + e126065 commit 90cb561
Show file tree
Hide file tree
Showing 11 changed files with 632 additions and 74 deletions.
103 changes: 97 additions & 6 deletions src/lib.rs
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 @@ -274,27 +336,39 @@ pub trait Conversion<V> {
/// Conversion factor type specific to the underlying storage type.
type T: ConversionFactor<V>;

/// Static [conversion factor][factor] for the given unit to the base unit for the quantity.
/// Coefficient portion of [conversion factor][factor] for converting the given unit to the
/// base unit for the quantity: `(value * coefficient()) + constant()`.
///
/// Default implementation returns `Self::T::one()`.
///
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
#[inline(always)]
fn conversion() -> Self::T {
fn coefficient() -> Self::T {
<Self::T as num::One>::one()
}

/// Constant portion of [conversion factor][factor] for converting the given unit to the base
/// unit for the quantity: `(value * coefficient()) + constant()`.
///
/// Default implementation returns `Self::T::zero()`.
///
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
#[inline(always)]
fn constant() -> Self::T {
<Self::T as num::Zero>::zero()
}

/// Instance [conversion factor][factor].
///
/// Default implementation returns the static conversion `Self::conversion()`.
/// Default implementation returns the coefficient: `Self::coefficient()`.
///
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
#[inline(always)]
fn into_conversion(&self) -> Self::T
where
Self: Sized,
{
Self::conversion()
Self::coefficient()
}
}

Expand All @@ -303,9 +377,11 @@ pub trait Conversion<V> {
/// [factor]: https://jcgm.bipm.org/vim/en/1.24.html
#[cfg_attr(rustfmt, rustfmt_skip)]
pub trait ConversionFactor<V>
: lib::ops::Div<Self, Output = Self>
: lib::ops::Add<Self, Output = Self>
+ lib::ops::Sub<Self, Output = Self>
+ lib::ops::Mul<Self, Output = Self>
+ num::One
+ lib::ops::Div<Self, Output = Self>
+ num::Zero + num::One
{
/// Raises a `ConversionFactor<V>` to an integer power.
fn powi(self, e: i32) -> Self;
Expand All @@ -314,6 +390,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
104 changes: 82 additions & 22 deletions src/quantity.rs
Expand Up @@ -11,9 +11,15 @@
/// * `$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`).
/// * `$conversion`: Conversion (coefficient and constant factor) from the unit to the base unit of
/// the quantity (e.g. `3.048_E-1` to convert `foot` to `meter`. `1.0_E0, 273.15_E0` to convert
/// `celsius` to `kelvin`.). The coefficient is required and the constant factor is optional.
/// Note that using a unit with a non-zero constant factor is not currently supported as a base
/// unit.
/// * `$abbreviation`: Unit abbreviation (e.g. `"m"`).
/// * `$singular`: Singular unit description (e.g. `"meter"`).
/// * `$plural`: Plural unit description (e.g. `"meters"`).
Expand Down Expand Up @@ -87,18 +93,37 @@
///
/// [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 {
(
$(#[$quantity_attr:meta])* quantity: $quantity:ident; $description:expr;
$(#[$dim_attr:meta])* dimension: $system:ident<$($dimension:ident),+>;
units {
$($(#[$unit_attr:meta])* @$unit:ident: $conversion:expr;
$($(#[$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 Expand Up @@ -146,8 +171,13 @@ macro_rules! quantity {
type T = V;

#[inline(always)]
fn conversion() -> Self::T {
$conversion
fn coefficient() -> Self::T {
quantity!(@coefficient $($conversion),+)
}

#[inline(always)]
fn constant() -> Self::T {
quantity!(@constant $($conversion),+)
}
}

Expand All @@ -156,15 +186,24 @@ macro_rules! quantity {

storage_types! {
types: PrimInt, BigInt;
pub type T = $crate::num::rational::Ratio<V>;

#[inline(always)]
fn from_f64(value: f64) -> T {
<T as $crate::num::FromPrimitive>::from_f64(value).unwrap()
}

$(impl $crate::Conversion<V> for super::$unit {
type T = $crate::num::rational::Ratio<V>;
type T = T;

#[inline(always)]
fn conversion() -> Self::T {
use $crate::num::FromPrimitive;
fn coefficient() -> Self::T {
from_f64(quantity!(@coefficient $($conversion),+))
}

Self::T::from_f64($conversion).unwrap()
#[inline(always)]
fn constant() -> Self::T {
from_f64(quantity!(@constant $($conversion),+))
}
}

Expand All @@ -173,20 +212,29 @@ macro_rules! quantity {

storage_types! {
types: BigUint;
pub type T = $crate::num::rational::Ratio<V>;

#[inline(always)]
fn from_f64(value: f64) -> T {
use $crate::num::FromPrimitive;

let c = $crate::num::rational::Ratio::<$crate::num::BigInt>::from_f64(value)
.unwrap();

T::new(c.numer().to_biguint().unwrap(), c.denom().to_biguint().unwrap())
}

$(impl $crate::Conversion<V> for super::$unit {
type T = $crate::num::rational::Ratio<V>;
type T = T;

#[inline(always)]
fn conversion() -> Self::T {
use $crate::num::FromPrimitive;

let c = $crate::num::rational::Ratio::<$crate::num::BigInt>::from_f64(
$conversion)
.unwrap();
fn coefficient() -> Self::T {
from_f64(quantity!(@coefficient $($conversion),+))
}

Self::T::new(c.numer().to_biguint().unwrap(),
c.denom().to_biguint().unwrap())
#[inline(always)]
fn constant() -> Self::T {
from_f64(quantity!(@constant $($conversion),+))
}
}

Expand All @@ -196,14 +244,22 @@ macro_rules! quantity {
storage_types! {
types: Ratio;

#[inline(always)]
fn from_f64(value: f64) -> V {
<V as $crate::num::FromPrimitive>::from_f64(value).unwrap()
}

$(impl $crate::Conversion<V> for super::$unit {
type T = V;

#[inline(always)]
fn conversion() -> Self::T {
use $crate::num::FromPrimitive;
fn coefficient() -> Self::T {
from_f64(quantity!(@coefficient $($conversion),+))
}

Self::T::from_f64($conversion).unwrap()
#[inline(always)]
fn constant() -> Self::T {
from_f64(quantity!(@constant $($conversion),+))
}
}

Expand Down Expand Up @@ -336,4 +392,8 @@ macro_rules! quantity {
#[derive(Clone, Copy, Debug, Hash)]
pub struct $unit;
};
(@coefficient $factor:expr, $const:expr) => { $factor };
(@coefficient $factor:expr) => { $factor };
(@constant $factor:expr, $const:expr) => { $const };
(@constant $factor:expr) => { 0.0 };
}
1 change: 1 addition & 0 deletions src/si/mod.rs
Expand Up @@ -46,6 +46,7 @@ system! {
power::Power,
pressure::Pressure,
ratio::Ratio,
temperature_interval::TemperatureInterval,
thermodynamic_temperature::ThermodynamicTemperature,
time::Time,
velocity::Velocity,
Expand Down

0 comments on commit 90cb561

Please sign in to comment.