Created
May 20, 2024 20:41
-
-
Save forrestthewoods/486ec3b6cad8c0f7dad2e33183747ce1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---------------- quantity.rs | |
/*! | |
Declares foundational `QuantityT<T,U>` struct upon which fts_units is built. | |
`QuantityT<T,U>` defines a `Quantity` which stores an `amount` of type `T` with units type `U`. Mathematical operations with `QuantityT<T,U>` values produces new types of `QuantityT` with a different `U` type. | |
If `U` is zero sized then all the type checking done and compile time and boils down to nothing. No run-time overhead for either CPU or memory. | |
Mathematical operations for `QuantityT<T,U>` are defined so long as they are independently defined for both `T` and `U`. | |
*/ | |
use std::fmt; | |
use std::marker::PhantomData; | |
use crate::ops::*; | |
// -------------------------------- | |
// Trait declarations | |
// -------------------------------- | |
/// Must be implemented for `T` in `QuantityT<T,U>`. | |
pub trait Amount: Copy + Clone {} | |
/// Helper for performing generic computations with `QuantityT<T,U>` types. | |
pub trait Quantity { | |
type AmountType: Amount; | |
type UnitsType; | |
fn new(amount: Self::AmountType) -> Self; | |
fn amount(&self) -> Self::AmountType; | |
} | |
/// Helper for converting units. For example from Meters to Kilometers. | |
/// | |
/// ```rust | |
/// # use fts_units::si_system::quantities::f32::*; | |
/// # use fts_units::quantity::ConvertUnits; | |
/// let d = Kilometers::new(15.3); | |
/// let t = Hours::new(2.7); | |
/// let kph : KilometersPerHour = d / t; | |
/// | |
/// let mps : MetersPerSecond = kph.convert_into(); | |
/// let mps = MetersPerSecond::convert_from(kph); | |
/// ``` | |
pub trait ConvertUnits<T> { | |
fn convert_from(v: T) -> Self; | |
fn convert_into(self) -> T; | |
} | |
/// Helpers for casting `T` in `QuantityT<T,U>`. | |
/// | |
/// ```rust | |
/// # use fts_units::si_system::quantities::*; | |
/// # use fts_units::quantity::{CastAmount, Quantity}; | |
/// let m = Meters::<f32>::new(7.73); | |
/// let i : Meters<i32> = m.cast_into(); | |
/// assert_eq!(i.amount(), 7); | |
/// ``` | |
pub trait CastAmount<T> { | |
fn cast_from(v: T) -> Self; | |
fn cast_into(self) -> T; | |
} | |
// -------------------------------- | |
// Struct declarations | |
// -------------------------------- | |
/// Foundational struct used by all run-time quantities. | |
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] | |
pub struct QuantityT<T, U> | |
where | |
T: Amount, | |
{ | |
amount: T, | |
_u: PhantomData<U>, | |
} | |
// -------------------------------- | |
// QuantityT impls | |
// -------------------------------- | |
impl<T, U> QuantityT<T, U> | |
where | |
T: Amount, | |
{ | |
pub fn new(amount: T) -> QuantityT<T, U> { | |
QuantityT { | |
amount: amount, | |
_u: PhantomData, | |
} | |
} | |
} | |
impl<T, U> Quantity for QuantityT<T, U> | |
where | |
T: Amount, | |
{ | |
type AmountType = T; | |
type UnitsType = U; | |
fn new(amount: T) -> Self { | |
QuantityT::<T, U>::new(amount) | |
} | |
fn amount(&self) -> Self::AmountType { | |
self.amount | |
} | |
} | |
impl<T, Q> std::ops::Add<Self> for QuantityT<T, Q> | |
where | |
T: Amount + std::ops::Add<T>, | |
Q: std::ops::Add<Q>, | |
AddOutput<T, T>: Amount, | |
{ | |
type Output = QuantityT<AddOutput<T, T>, AddOutput<Q, Q>>; | |
fn add(self, other: Self) -> Self::Output { | |
Self::Output::new(self.amount + other.amount) | |
} | |
} | |
impl<T, Q> std::ops::Sub<Self> for QuantityT<T, Q> | |
where | |
T: Amount + std::ops::Sub<T>, | |
Q: std::ops::Sub<Q>, | |
SubOutput<T, T>: Amount, | |
{ | |
type Output = QuantityT<SubOutput<T, T>, SubOutput<Q, Q>>; | |
fn sub(self, other: Self) -> Self::Output { | |
Self::Output::new(self.amount - other.amount) | |
} | |
} | |
impl<T, Q0, Q1> std::ops::Mul<QuantityT<T, Q1>> for QuantityT<T, Q0> | |
where | |
T: Amount + std::ops::Mul<T>, | |
Q0: std::ops::Mul<Q1>, | |
MulOutput<T, T>: Amount, | |
{ | |
type Output = QuantityT<MulOutput<T, T>, MulOutput<Q0, Q1>>; | |
fn mul(self, other: QuantityT<T, Q1>) -> Self::Output { | |
Self::Output::new(self.amount * other.amount) | |
} | |
} | |
impl<T, Q0, Q1> std::ops::Div<QuantityT<T, Q1>> for QuantityT<T, Q0> | |
where | |
T: Amount + std::ops::Div<T>, | |
Q0: std::ops::Div<Q1>, | |
DivOutput<T, T>: Amount, | |
{ | |
type Output = QuantityT<DivOutput<T, T>, DivOutput<Q0, Q1>>; | |
fn div(self, other: QuantityT<T, Q1>) -> Self::Output { | |
Self::Output::new(self.amount / other.amount) | |
} | |
} | |
impl<T, U> std::fmt::Display for QuantityT<T, U> | |
where | |
T: std::fmt::Display + Amount, | |
U: std::fmt::Display + Default, | |
{ | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "{} {}", self.amount, U::default()) | |
} | |
} | |
impl<T, U> Invert for QuantityT<T, U> | |
where | |
T: Invert + Amount, | |
U: Invert, | |
InvertOutput<T>: Amount, | |
{ | |
type Output = QuantityT<InvertOutput<T>, InvertOutput<U>>; | |
fn invert(self) -> Self::Output { | |
Self::Output::new(self.amount.invert()) | |
} | |
} | |
impl<T, U> Sqrt for QuantityT<T, U> | |
where | |
T: num_traits::float::Float + Amount, | |
U: Sqrt, | |
{ | |
type Output = QuantityT<T, SqrtOutput<U>>; | |
fn sqrt(self) -> Self::Output { | |
Self::Output::new(self.amount.sqrt()) | |
} | |
} | |
impl<T, U> std::convert::From<T> for QuantityT<T, U> | |
where | |
T: Amount, | |
{ | |
fn from(value: T) -> Self { | |
Self::new(value) | |
} | |
} | |
impl Amount for i8 {} | |
impl Amount for i16 {} | |
impl Amount for i32 {} | |
impl Amount for i64 {} | |
impl Amount for i128 {} | |
impl Amount for u8 {} | |
impl Amount for u16 {} | |
impl Amount for u32 {} | |
impl Amount for u64 {} | |
impl Amount for u128 {} | |
impl Amount for f32 {} | |
impl Amount for f64 {} | |
// ------------------- ratio.rs | |
/*! | |
Storage and operations for compile-type Ratio types. | |
*/ | |
use std::marker::PhantomData; | |
use typenum::consts::*; | |
use typenum::int::{NInt, PInt}; | |
use typenum::{Integer, NonZero}; | |
use crate::ops::*; | |
// -------------------------------- | |
// Trait declarations | |
// -------------------------------- | |
/// Helper to faciliate working with Ratio types generically. | |
pub trait Ratio { | |
fn numerator() -> i64; | |
fn denominator() -> i64; | |
} | |
// -------------------------------- | |
// Struct declarations | |
// -------------------------------- | |
/// Special type to represent a Zero Ratio. | |
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] | |
pub struct RatioZero; | |
/// Ratio type with positive, non-zero numerator and denominator. | |
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] | |
pub struct RatioT<NUM, DEN> | |
where | |
NUM: Integer + NonZero, | |
DEN: Integer + NonZero, | |
{ | |
_num: PhantomData<NUM>, | |
_den: PhantomData<DEN>, | |
} | |
// -------------------------------- | |
// Ratio impls | |
// -------------------------------- | |
impl<NUM, DEN> Ratio for RatioT<NUM, DEN> | |
where | |
NUM: Integer + NonZero, | |
DEN: Integer + NonZero, | |
{ | |
fn numerator() -> i64 { | |
NUM::I64 | |
} | |
fn denominator() -> i64 { | |
DEN::I64 | |
} | |
} | |
impl<N, D> NonZero for RatioT<N, D> | |
where | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
{ | |
} | |
impl Ratio for RatioZero { | |
fn numerator() -> i64 { | |
0 | |
} | |
fn denominator() -> i64 { | |
0 | |
} | |
} | |
impl Xor<RatioZero> for RatioZero | |
where | |
RatioZero: Default, | |
{ | |
type Output = RatioZero; | |
fn xor(self, _other: RatioZero) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<N, D> Xor<RatioT<N, D>> for RatioT<N, D> | |
where | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
RatioT<N, D>: Default, | |
{ | |
type Output = RatioT<N, D>; | |
fn xor(self, _other: RatioT<N, D>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<N, D> Xor<RatioZero> for RatioT<N, D> | |
where | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
RatioT<N, D>: Default, | |
{ | |
type Output = RatioT<N, D>; | |
fn xor(self, _other: RatioZero) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<N, D> Xor<RatioT<N, D>> for RatioZero | |
where | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
RatioT<N, D>: Default, | |
{ | |
type Output = RatioT<N, D>; | |
fn xor(self, _other: RatioT<N, D>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<E> ReduceWith<E> for RatioZero { | |
type Output = RatioZero; | |
fn reduce_with(self, _other: E) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<N, D> ReduceWith<Z0> for RatioT<N, D> | |
where | |
Self: Default, | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
{ | |
type Output = RatioZero; | |
fn reduce_with(self, _other: Z0) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<N, D, U> ReduceWith<PInt<U>> for RatioT<N, D> | |
where | |
Self: Default, | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
U: typenum::Unsigned + NonZero, | |
{ | |
type Output = Self; | |
fn reduce_with(self, _other: PInt<U>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<N, D, U> ReduceWith<NInt<U>> for RatioT<N, D> | |
where | |
Self: Default, | |
N: Integer + NonZero, | |
D: Integer + NonZero, | |
U: typenum::Unsigned + NonZero, | |
{ | |
type Output = Self; | |
fn reduce_with(self, _other: NInt<U>) -> Self::Output { | |
Default::default() | |
} | |
} | |
// --------------- ops.rs | |
//! Traits and helpers to faciliate working with generic Quantities. | |
// -------------------------------- | |
// Traits | |
// -------------------------------- | |
/// Helper to reduce Ratios to RatioZero when Exponent becomes zero | |
pub trait Reduce { | |
type Output; | |
fn reduce(self) -> Self::Output; | |
} | |
/// Helper to reduce Ratios to RatioZero when Exponent becomes zero | |
pub trait ReduceWith<T> { | |
type Output; | |
fn reduce_with(self, other: T) -> Self::Output; | |
} | |
/// Provide generic Invert interface for invertable types (such as floats) | |
pub trait Invert { | |
type Output; | |
fn invert(self) -> Self::Output; | |
} | |
/// Provide generic Sqrt interface for supported types (such as floats) | |
pub trait Sqrt { | |
type Output; | |
fn sqrt(self) -> Self::Output; | |
} | |
/// Used only at the type level for Xor'ing Zero and Non-Zero Ratios | |
pub trait Xor<T> { | |
type Output; | |
fn xor(self, other: T) -> Self::Output; | |
} | |
// -------------------------------- | |
// Utilities | |
// -------------------------------- | |
pub type AddOutput<T, U> = <T as std::ops::Add<U>>::Output; | |
pub type SubOutput<T, U> = <T as std::ops::Sub<U>>::Output; | |
pub type MulOutput<T, U> = <T as std::ops::Mul<U>>::Output; | |
pub type DivOutput<T, U> = <T as std::ops::Div<U>>::Output; | |
pub type XorOutput<T, U> = <T as Xor<U>>::Output; | |
pub type MulOutput3<T, U, V> = MulOutput<MulOutput<T, U>, V>; | |
pub type MulOutput4<T, U, V, W> = MulOutput<MulOutput<MulOutput<T, U>, V>, W>; | |
pub type InvertOutput<T> = <T as Invert>::Output; | |
pub type SqrtOutput<T> = <T as Sqrt>::Output; | |
pub type ReduceOutput<T> = <T as Reduce>::Output; | |
pub type ReduceWithOutput<T, U> = <T as ReduceWith<U>>::Output; | |
// -------------------------------- | |
// Impls for built-in types | |
// -------------------------------- | |
impl Invert for f32 { | |
type Output = f32; | |
fn invert(self) -> Self::Output { | |
1.0 / self | |
} | |
} | |
impl Invert for f64 { | |
type Output = f64; | |
fn invert(self) -> Self::Output { | |
1.0 / self | |
} | |
} | |
// ----------- si_system.rs | |
/*! | |
Structs and traits to enable SI Unit quantities. | |
There are three core structs with matching traits. | |
```no_compile | |
pub struct SIUnitsT<RATIOS,EXPONENTS> { ... } | |
pub struct SIRatiosT<LENGTH, MASS, TIME> { ... } | |
pub struct SIExponentsT<LENGTH, MASS, TIME> { ... } | |
pub trait SIUnits { type Ratios: SIRatios; type Exponents: SIExponents; } | |
pub trait SIRatios { type Length; type Mass; type Time; } | |
pub trait SIExponents { type Length; type Mass; type Time; } | |
``` | |
`SIUnitsT` has `RATIOS` and `EXPONENTS`. Traits such as `std::ops::Add` are implemented for `SIUnitsT<R,E>` when `R` and `E` are the same. `std::ops::mul` is implemented for any pair of exponents, but with an `Xor` restriction on `R`. | |
*/ | |
use std::fmt; | |
use std::marker::PhantomData; | |
use typenum::consts::*; | |
use typenum::{Diff, Integer, NonZero, PartialDiv, Sum}; | |
use crate::ops::*; | |
use crate::quantity::*; | |
use crate::ratio::*; | |
use crate::typenum_ext::*; | |
pub use self::ratios::*; | |
// -------------------------------- | |
// SI System Traits | |
// -------------------------------- | |
/// Helper to faciliate generic operations on `SIUnitsT<R,E>`. | |
pub trait SIUnits { | |
type Ratios: SIRatios; | |
type Exponents: SIExponents; | |
} | |
/// Helper to faciliate generic operations on `SIRatiosT<L,M,T>`. | |
pub trait SIRatios { | |
type Length: Ratio; | |
type Mass: Ratio; | |
type Time: Ratio; | |
} | |
/// Helper to faciliate generic operations on `SIExponentsT<L,M,T>`. | |
pub trait SIExponents { | |
type Length: Integer; | |
type Mass: Integer; | |
type Time: Integer; | |
} | |
// -------------------------------- | |
// SI System Structs | |
// -------------------------------- | |
/// Foundational type of `si_system`. Holds all Ratios and Exponents as types. | |
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] | |
pub struct SIUnitsT<RATIOS, EXPONENTS> | |
where | |
RATIOS: SIRatios, | |
EXPONENTS: SIExponents, | |
{ | |
_r: PhantomData<RATIOS>, | |
_e: PhantomData<EXPONENTS>, | |
} | |
/// Holds type Ratios for each `si_system` dimension. | |
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] | |
pub struct SIRatiosT<L, M, T> | |
where | |
L: Ratio, | |
M: Ratio, | |
T: Ratio, | |
{ | |
_l: PhantomData<L>, | |
_m: PhantomData<M>, | |
_t: PhantomData<T>, | |
} | |
/// Holds type exponents for each `si_system` dimension. | |
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] | |
pub struct SIExponentsT<L, M, T> | |
where | |
L: Integer, | |
M: Integer, | |
T: Integer, | |
{ | |
_l: PhantomData<L>, | |
_m: PhantomData<M>, | |
_t: PhantomData<T>, | |
} | |
/// Internal type used for `SIUnitsT` operations. | |
#[doc(hidden)] | |
#[derive(Default)] | |
pub struct RatioExponentT<R: Ratio, E: Integer> { | |
_r: PhantomData<R>, | |
_e: PhantomData<E>, | |
} | |
/// Internal type used for `SIUnitsT` operations. | |
#[doc(hidden)] | |
#[derive(Copy, Clone)] | |
pub struct AmountT<T: Amount>(T); | |
// -------------------------------- | |
// impls | |
// -------------------------------- | |
// Basic invert (always possible) | |
impl<R, E> Invert for SIUnitsT<R, E> | |
where | |
R: SIRatios, | |
E: SIExponents, | |
units::Dimensionless: std::ops::Div<Self>, | |
DivOutput<units::Dimensionless, Self>: Default, | |
{ | |
type Output = DivOutput<units::Dimensionless, Self>; | |
fn invert(self) -> Self::Output { | |
Default::default() | |
} | |
} | |
// Basic SIUnitsT add | |
impl<R, E> std::ops::Add<SIUnitsT<R, E>> for SIUnitsT<R, E> | |
where | |
R: SIRatios, | |
E: SIExponents, | |
{ | |
type Output = Self; | |
fn add(self, _other: Self) -> Self::Output { | |
SIUnitsT { | |
_r: PhantomData, | |
_e: PhantomData, | |
} | |
} | |
} | |
// Basic SIUnitsT subtract | |
impl<R, E> std::ops::Sub<SIUnitsT<R, E>> for SIUnitsT<R, E> | |
where | |
R: SIRatios, | |
E: SIExponents, | |
{ | |
type Output = Self; | |
fn sub(self, _other: Self) -> Self::Output { | |
SIUnitsT { | |
_r: PhantomData, | |
_e: PhantomData, | |
} | |
} | |
} | |
// SIExponents Add | |
impl<L0, M0, T0, L1, M1, T1> std::ops::Add<SIExponentsT<L1, M1, T1>> for SIExponentsT<L0, M0, T0> | |
where | |
L0: Integer + std::ops::Add<L1>, | |
M0: Integer + std::ops::Add<M1>, | |
T0: Integer + std::ops::Add<T1>, | |
L1: Integer, | |
M1: Integer, | |
T1: Integer, | |
AddOutput<L0, L1>: Integer, | |
AddOutput<M0, M1>: Integer, | |
AddOutput<T0, T1>: Integer, | |
{ | |
type Output = SIExponentsT<Sum<L0, L1>, Sum<M0, M1>, Sum<T0, T1>>; | |
fn add(self, _other: SIExponentsT<L1, M1, T1>) -> Self::Output { | |
SIExponentsT { | |
_l: PhantomData, | |
_m: PhantomData, | |
_t: PhantomData, | |
} | |
} | |
} | |
// SIExponents Sub | |
impl<L0, M0, T0, L1, M1, T1> std::ops::Sub<SIExponentsT<L1, M1, T1>> for SIExponentsT<L0, M0, T0> | |
where | |
L0: Integer + std::ops::Sub<L1>, | |
M0: Integer + std::ops::Sub<M1>, | |
T0: Integer + std::ops::Sub<T1>, | |
L1: Integer, | |
M1: Integer, | |
T1: Integer, | |
SubOutput<L0, L1>: Integer, | |
SubOutput<M0, M1>: Integer, | |
SubOutput<T0, T1>: Integer, | |
{ | |
type Output = SIExponentsT<Diff<L0, L1>, Diff<M0, M1>, Diff<T0, T1>>; | |
fn sub(self, _other: SIExponentsT<L1, M1, T1>) -> Self::Output { | |
SIExponentsT { | |
_l: PhantomData, | |
_m: PhantomData, | |
_t: PhantomData, | |
} | |
} | |
} | |
/// Multiplying a pair of SIUnits is complicated | |
/// Ratios: must be XOR-able | |
/// meters * meters is fine. | |
/// meters * kilometers is not. The output type is ambiguous. | |
/// Exponents: can be anything. will be added together | |
/// meters * meters = meters squared | |
/// However exponents which become zero must zero out their corresponding ratio | |
/// 10 kilometers per hour * 2 hours = 20 kilometers. The time Ratio was hours, but needs to be zero'd out. | |
impl<R0, E0, R1, E1> std::ops::Mul<SIUnitsT<R1, E1>> for SIUnitsT<R0, E0> | |
where | |
R0: SIRatios + Xor<R1>, | |
E0: SIExponents + std::ops::Add<E1>, | |
R1: SIRatios, | |
E1: SIExponents, | |
XorOutput<R0, R1>: SIRatios + ReduceWith<AddOutput<E0, E1>> + Default, | |
AddOutput<E0, E1>: SIExponents + Default, | |
ReduceWithOutput<XorOutput<R0, R1>, AddOutput<E0, E1>>: SIRatios + Default, | |
ReduceOutput<SIUnitsT<XorOutput<R0, R1>, AddOutput<E0, E1>>>: Default, | |
{ | |
type Output = ReduceOutput<SIUnitsT<XorOutput<R0, R1>, AddOutput<E0, E1>>>; | |
fn mul(self, _other: SIUnitsT<R1, E1>) -> Self::Output { | |
Default::default() | |
} | |
} | |
/// See coments on `std::ops::Mul<SIUnitsT<_,_>>` | |
impl<R0, E0, R1, E1> std::ops::Div<SIUnitsT<R1, E1>> for SIUnitsT<R0, E0> | |
where | |
R0: SIRatios + Xor<R1>, | |
E0: SIExponents + std::ops::Sub<E1>, | |
R1: SIRatios, | |
E1: SIExponents, | |
XorOutput<R0, R1>: SIRatios + ReduceWith<SubOutput<E0, E1>> + Default, | |
SubOutput<E0, E1>: SIExponents + Default, | |
ReduceWithOutput<XorOutput<R0, R1>, SubOutput<E0, E1>>: SIRatios + Default, | |
ReduceOutput<SIUnitsT<XorOutput<R0, R1>, SubOutput<E0, E1>>>: Default, | |
{ | |
type Output = ReduceOutput<SIUnitsT<XorOutput<R0, R1>, SubOutput<E0, E1>>>; | |
fn div(self, _other: SIUnitsT<R1, E1>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<L, M, T> SIRatios for SIRatiosT<L, M, T> | |
where | |
L: Ratio, | |
M: Ratio, | |
T: Ratio, | |
{ | |
type Length = L; | |
type Mass = M; | |
type Time = T; | |
} | |
impl<L, M, T> SIExponents for SIExponentsT<L, M, T> | |
where | |
L: Integer, | |
M: Integer, | |
T: Integer, | |
{ | |
type Length = L; | |
type Mass = M; | |
type Time = T; | |
} | |
impl<R, E> SIUnits for SIUnitsT<R, E> | |
where | |
R: SIRatios, | |
E: SIExponents, | |
{ | |
type Ratios = R; | |
type Exponents = E; | |
} | |
impl<L0, M0, T0, L1, M1, T1> Xor<SIRatiosT<L1, M1, T1>> for SIRatiosT<L0, M0, T0> | |
where | |
L0: Ratio + Xor<L1>, | |
M0: Ratio + Xor<M1>, | |
T0: Ratio + Xor<T1>, | |
L1: Ratio, | |
M1: Ratio, | |
T1: Ratio, | |
XorOutput<L0, L1>: Ratio + Default, | |
XorOutput<M0, M1>: Ratio + Default, | |
XorOutput<T0, T1>: Ratio + Default, | |
{ | |
type Output = SIRatiosT<XorOutput<L0, L1>, XorOutput<M0, M1>, XorOutput<T0, T1>>; | |
fn xor(self, _other: SIRatiosT<L1, M1, T1>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<L0, M0, T0, L1, M1, T1> Xor<SIExponentsT<L1, M1, T1>> for SIExponentsT<L0, M0, T0> | |
where | |
L0: Integer + Xor<L1>, | |
M0: Integer + Xor<M1>, | |
T0: Integer + Xor<T1>, | |
L1: Integer, | |
M1: Integer, | |
T1: Integer, | |
XorOutput<L0, L1>: Integer + Default, | |
XorOutput<M0, M1>: Integer + Default, | |
XorOutput<T0, T1>: Integer + Default, | |
{ | |
type Output = SIExponentsT<XorOutput<L0, L1>, XorOutput<M0, M1>, XorOutput<T0, T1>>; | |
fn xor(self, _other: SIExponentsT<L1, M1, T1>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<R0, E0, R1, E1> Xor<SIUnitsT<R1, E1>> for SIUnitsT<R0, E0> | |
where | |
R0: SIRatios + Xor<R1>, | |
E0: SIExponents + Xor<E1>, | |
R1: SIRatios, | |
E1: SIExponents, | |
XorOutput<R0, R1>: SIRatios, | |
XorOutput<E0, E1>: SIExponents, | |
SIUnitsT<XorOutput<R0, R1>, XorOutput<E0, E1>>: Default, | |
{ | |
type Output = SIUnitsT<XorOutput<R0, R1>, XorOutput<E0, E1>>; | |
fn xor(self, _other: SIUnitsT<R1, E1>) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<L, M, T, E> ReduceWith<E> for SIRatiosT<L, M, T> | |
where | |
L: Ratio + ReduceWith<E::Length>, | |
M: Ratio + ReduceWith<E::Mass>, | |
T: Ratio + ReduceWith<E::Time>, | |
E: SIExponents, | |
ReduceWithOutput<L, E::Length>: Ratio + Default, | |
ReduceWithOutput<M, E::Mass>: Ratio + Default, | |
ReduceWithOutput<T, E::Time>: Ratio + Default, | |
{ | |
type Output = SIRatiosT< | |
ReduceWithOutput<L, E::Length>, | |
ReduceWithOutput<M, E::Mass>, | |
ReduceWithOutput<T, E::Time>, | |
>; | |
fn reduce_with(self, _other: E) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<R, E> Reduce for SIUnitsT<R, E> | |
where | |
R: SIRatios + ReduceWith<E>, | |
E: SIExponents, | |
ReduceWithOutput<R, E>: SIRatios, | |
SIUnitsT<ReduceWithOutput<R, E>, E>: Default, | |
{ | |
type Output = SIUnitsT<ReduceWithOutput<R, E>, E>; | |
fn reduce(self) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<T, R, E> std::ops::Mul<SIUnitsT<R, E>> for AmountT<T> | |
where | |
T: Amount, | |
AmountT<T>: std::ops::Mul<RatioExponentT<R::Length, E::Length>, Output = Self> | |
+ std::ops::Mul<RatioExponentT<R::Mass, E::Mass>, Output = Self> | |
+ std::ops::Mul<RatioExponentT<R::Time, E::Time>, Output = Self>, | |
R: SIRatios, | |
E: SIExponents, | |
{ | |
type Output = Self; | |
fn mul(self, _other: SIUnitsT<R, E>) -> Self::Output { | |
let mut result = self; | |
result = result | |
* RatioExponentT::<R::Length, E::Length> { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
result = result | |
* RatioExponentT::<R::Mass, E::Mass> { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
result = result | |
* RatioExponentT::<R::Time, E::Time> { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
result | |
} | |
} | |
impl<T, R, E> std::ops::Div<SIUnitsT<R, E>> for AmountT<T> | |
where | |
T: Amount, | |
AmountT<T>: std::ops::Div<RatioExponentT<R::Length, E::Length>, Output = Self> | |
+ std::ops::Div<RatioExponentT<R::Mass, E::Mass>, Output = Self> | |
+ std::ops::Div<RatioExponentT<R::Time, E::Time>, Output = Self>, | |
R: SIRatios, | |
E: SIExponents, | |
{ | |
type Output = Self; | |
fn div(self, _other: SIUnitsT<R, E>) -> Self::Output { | |
let mut result = self; | |
result = result | |
/ RatioExponentT::<R::Length, E::Length> { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
result = result | |
/ RatioExponentT::<R::Mass, E::Mass> { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
result = result | |
/ RatioExponentT::<R::Time, E::Time> { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
result | |
} | |
} | |
impl<T, R1, R2, E> ConvertUnits<QuantityT<T, SIUnitsT<R1, E>>> for QuantityT<T, SIUnitsT<R2, E>> | |
where | |
T: Amount, | |
AmountT<T>: std::ops::Mul<SIUnitsT<R1, E>, Output = AmountT<T>> | |
+ std::ops::Div<SIUnitsT<R1, E>, Output = AmountT<T>> | |
+ std::ops::Mul<SIUnitsT<R2, E>, Output = AmountT<T>> | |
+ std::ops::Div<SIUnitsT<R2, E>, Output = AmountT<T>>, | |
R1: SIRatios, | |
R2: SIRatios, | |
E: SIExponents, | |
{ | |
fn convert_from(other: QuantityT<T, SIUnitsT<R1, E>>) -> Self { | |
let amount = AmountT(other.amount()); | |
let r1: SIUnitsT<R1, E> = SIUnitsT { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
let r2: SIUnitsT<R2, E> = SIUnitsT { | |
_r: PhantomData, | |
_e: PhantomData, | |
}; | |
let result = amount / r2 * r1; | |
Self::new(result.0) | |
} | |
fn convert_into(self) -> QuantityT<T, SIUnitsT<R1, E>> { | |
QuantityT::<T, SIUnitsT<R1, E>>::convert_from(self) | |
} | |
} | |
impl<T1, T2, U> CastAmount<QuantityT<T2, U>> for QuantityT<T1, U> | |
where | |
T1: Amount + num_traits::NumCast, | |
T2: Amount + num_traits::NumCast, | |
{ | |
fn cast_from(other: QuantityT<T2, U>) -> Self { | |
Self::new(num_traits::cast(other.amount()).unwrap()) | |
} | |
fn cast_into(self) -> QuantityT<T2, U> { | |
QuantityT::<T2, U>::new(num_traits::cast(self.amount()).unwrap()) | |
} | |
} | |
impl<R, E> std::fmt::Display for SIUnitsT<R, E> | |
where | |
R: SIRatios, | |
E: SIExponents, | |
{ | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
let mut any = false; | |
// Length | |
let e = E::Length::to_i64(); | |
if e != 0 { | |
assert!(R::Length::numerator() != 0 && R::Length::denominator() != 0); | |
any = true; | |
write_ratio_symbol_short::<R::Length>(f)?; | |
write!(f, "m")?; | |
if e != 1 { | |
write_superscript(e, f)?; | |
} | |
}; | |
// Mass | |
let e = E::Mass::to_i64(); | |
if e != 0 { | |
assert!(R::Mass::numerator() != 0 && R::Mass::denominator() != 0); | |
if any { | |
write!(f, "·")?; | |
} | |
any = true; | |
write_ratio_symbol_short::<R::Mass>(f)?; | |
write!(f, "g")?; | |
if e != 1 { | |
write_superscript(e, f)?; | |
} | |
}; | |
// Time | |
let e = E::Time::to_i64(); | |
if e != 0 { | |
assert!(R::Time::numerator() != 0 && R::Time::denominator() != 0); | |
if any { | |
write!(f, "·")?; | |
} | |
write_ratio_symbol_time_short::<R::Time>(f)?; | |
if e != 1 { | |
write_superscript(e, f)?; | |
} | |
}; | |
Ok(()) | |
} | |
} | |
fn write_superscript(num: i64, f: &mut fmt::Formatter) -> fmt::Result { | |
const NEG: &char = &'⁻'; | |
const DIGITS: &[char; 10] = &[ | |
'⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹', | |
]; | |
let mut digits: [u8; 48] = [0; 48]; | |
let mut num_digits = 0; | |
let mut num = num; | |
if num < 0 { | |
write!(f, "{}", NEG)?; | |
num = num.abs(); | |
} | |
while num != 0 { | |
let digit = num % 10; | |
num /= 10; | |
digits[num_digits] = digit as u8; | |
num_digits += 1; | |
} | |
let slice = &digits[0..num_digits]; | |
for digit in slice.iter().rev() { | |
let idx = *digit as usize; | |
write!(f, "{}", DIGITS[idx])?; | |
} | |
Ok(()) | |
} | |
fn write_ratio_symbol_short<R: Ratio>(f: &mut fmt::Formatter) -> fmt::Result { | |
let n = R::numerator(); | |
let d = R::denominator(); | |
// Print Ratio; Kilo, centi, (18/7), etc | |
match (n, d) { | |
(1_000_000_000_000_000, 1) => write!(f, "P"), | |
(1_000_000_000_000, 1) => write!(f, "T"), | |
(1_000_000_000, 1) => write!(f, "G"), | |
(1_000_000, 1) => write!(f, "M"), | |
(1_000, 1) => write!(f, "k"), | |
(100, 1) => write!(f, "h"), | |
(10, 1) => write!(f, "da"), | |
(1, 1) => Ok(()), | |
(1, 10) => write!(f, "d"), | |
(1, 100) => write!(f, "c"), | |
(1, 1_000) => write!(f, "m"), | |
(1, 1_000_000) => write!(f, "μ"), | |
(1, 1_000_000_000) => write!(f, "n"), | |
(1, 1_000_000_000_000) => write!(f, "p"), | |
(1, 1_000_000_000_000_000) => write!(f, "f"), | |
(_, _) => write!(f, "({}/{})", n, d), | |
} | |
} | |
fn write_ratio_symbol_time_short<R: Ratio>(f: &mut fmt::Formatter) -> fmt::Result { | |
let n = R::numerator(); | |
let d = R::denominator(); | |
// Print Ratio; Kilo, centi, (18/7), etc | |
match (n, d) { | |
(3_600, 1) => write!(f, "h"), | |
(60, 1) => write!(f, "m"), | |
(1, 1) => write!(f, "s"), | |
(1, 10) => write!(f, "ds"), | |
(1, 100) => write!(f, "cs"), | |
(1, 1_000) => write!(f, "ms"), | |
(1, 1_000_000) => write!(f, "μs"), | |
(1, 1_000_000_000) => write!(f, "ns"), | |
(1, 1_000_000_000_000) => write!(f, "ps"), | |
(1, 1_000_000_000_000_000) => write!(f, "fs"), | |
(_, _) => write!(f, "({}/{})", n, d), | |
} | |
} | |
impl<R, E> Sqrt for SIUnitsT<R, E> | |
where | |
R: SIRatios, | |
E: SIExponents, | |
E::Length: PartialDiv<P2>, | |
E::Mass: PartialDiv<P2>, | |
E::Time: PartialDiv<P2>, | |
<E::Length as PartialDiv<P2>>::Output: Integer, | |
<E::Mass as PartialDiv<P2>>::Output: Integer, | |
<E::Time as PartialDiv<P2>>::Output: Integer, | |
SIUnitsT< | |
R, | |
SIExponentsT< | |
<E::Length as PartialDiv<P2>>::Output, | |
<E::Mass as PartialDiv<P2>>::Output, | |
<E::Time as PartialDiv<P2>>::Output, | |
>, | |
>: Default, | |
{ | |
type Output = SIUnitsT< | |
R, | |
SIExponentsT< | |
<E::Length as PartialDiv<P2>>::Output, | |
<E::Mass as PartialDiv<P2>>::Output, | |
<E::Time as PartialDiv<P2>>::Output, | |
>, | |
>; | |
fn sqrt(self) -> Self::Output { | |
Default::default() | |
} | |
} | |
impl<T, R, U> std::ops::Mul<RatioExponentT<R, typenum::PInt<U>>> for AmountT<T> | |
where | |
T: Amount + std::ops::Mul<T> + num_traits::NumCast, | |
R: Ratio, | |
U: typenum::Unsigned + NonZero, | |
MulOutput<T, T>: std::ops::Div<T, Output = T>, | |
{ | |
type Output = AmountT<T>; | |
fn mul(self, _other: RatioExponentT<R, typenum::PInt<U>>) -> Self::Output { | |
let amount = self.0; | |
let n: T = num_traits::cast(R::numerator()).unwrap(); | |
let d: T = num_traits::cast(R::denominator()).unwrap(); | |
let result = amount * n / d; | |
AmountT(result) | |
} | |
} | |
impl<T, R, U> std::ops::Div<RatioExponentT<R, typenum::PInt<U>>> for AmountT<T> | |
where | |
T: Amount + std::ops::Mul<T> + num_traits::NumCast, | |
R: Ratio, | |
U: typenum::Unsigned + NonZero, | |
MulOutput<T, T>: std::ops::Div<T, Output = T>, | |
{ | |
type Output = AmountT<T>; | |
fn div(self, _other: RatioExponentT<R, typenum::PInt<U>>) -> Self::Output { | |
let amount = self.0; | |
let n: T = num_traits::cast(R::numerator()).unwrap(); | |
let d: T = num_traits::cast(R::denominator()).unwrap(); | |
let result = amount * d / n; | |
AmountT(result) | |
} | |
} | |
impl<T, R, U> std::ops::Mul<RatioExponentT<R, typenum::NInt<U>>> for AmountT<T> | |
where | |
T: Amount + std::ops::Mul<T> + num_traits::NumCast, | |
R: Ratio, | |
U: typenum::Unsigned + NonZero, | |
MulOutput<T, T>: std::ops::Div<T, Output = T>, | |
{ | |
type Output = AmountT<T>; | |
fn mul(self, _other: RatioExponentT<R, typenum::NInt<U>>) -> Self::Output { | |
let amount = self.0; | |
let n: T = num_traits::cast(R::numerator()).unwrap(); | |
let d: T = num_traits::cast(R::denominator()).unwrap(); | |
let result = amount * d / n; | |
AmountT(result) | |
} | |
} | |
impl<T, R, U> std::ops::Div<RatioExponentT<R, typenum::NInt<U>>> for AmountT<T> | |
where | |
T: Amount + std::ops::Mul<T> + num_traits::NumCast, | |
R: Ratio, | |
U: typenum::Unsigned + NonZero, | |
MulOutput<T, T>: std::ops::Div<T, Output = T>, | |
{ | |
type Output = AmountT<T>; | |
fn div(self, _other: RatioExponentT<R, typenum::NInt<U>>) -> Self::Output { | |
let amount = self.0; | |
let n: T = num_traits::cast(R::numerator()).unwrap(); | |
let d: T = num_traits::cast(R::denominator()).unwrap(); | |
let result = amount * n / d; | |
AmountT(result) | |
} | |
} | |
impl<T> std::ops::Mul<RatioExponentT<RatioZero, typenum::Z0>> for AmountT<T> | |
where | |
T: Amount, | |
{ | |
type Output = AmountT<T>; | |
fn mul(self, _other: RatioExponentT<RatioZero, typenum::Z0>) -> AmountT<T> { | |
self | |
} | |
} | |
impl<T> std::ops::Div<RatioExponentT<RatioZero, typenum::Z0>> for AmountT<T> | |
where | |
T: Amount, | |
{ | |
type Output = AmountT<T>; | |
fn div(self, _other: RatioExponentT<RatioZero, typenum::Z0>) -> AmountT<T> { | |
self | |
} | |
} | |
/// Convenient `RatioT` types — Mega, Kilo, Centi, Nano, etc. | |
pub mod ratios { | |
use super::*; | |
use typenum::Exp; | |
// Limited to 10^15 with i64. | |
// Can cover "full" 10^24 spectrum with i128 support | |
// Missing: Yotta | |
// Missing: Zetta | |
// Missing: Exa | |
pub type Peta = RatioT<Exp<P10, P15>, P1>; | |
pub type Tera = RatioT<Exp<P10, P12>, P1>; | |
pub type Giga = RatioT<Exp<P10, P9>, P1>; | |
pub type Mega = RatioT<Exp<P10, P6>, P1>; | |
pub type Kilo = RatioT<Exp<P10, P3>, P1>; | |
pub type Hecto = RatioT<Exp<P10, P2>, P1>; | |
pub type Deca = RatioT<Exp<P10, P1>, P1>; | |
pub type Zero = RatioZero; | |
pub type Unit = RatioT<P1, P1>; | |
pub type Deci = RatioT<P1, Exp<P10, P1>>; | |
pub type Centi = RatioT<P1, Exp<P10, P2>>; | |
pub type Milli = RatioT<P1, Exp<P10, P3>>; | |
pub type Micro = RatioT<P1, Exp<P10, P6>>; | |
pub type Nano = RatioT<P1, Exp<P10, P9>>; | |
pub type Pico = RatioT<P1, Exp<P10, P12>>; | |
pub type Femto = RatioT<P1, Exp<P10, P15>>; | |
// Missing: Atto | |
// Missing: Zepto | |
// Missing: Yocto | |
// Time | |
pub type Second = Unit; | |
pub type Minute = RatioT<P60, P1>; | |
pub type Hour = RatioT<P3600, P1>; | |
pub type Day = RatioT<P86400, P1>; | |
pub type Year = RatioT<P31536000, P1>; | |
// BaseTypes | |
pub type Length<R> = SIRatiosT<R, Zero, Zero>; | |
pub type Mass<R> = SIRatiosT<Zero, R, Zero>; | |
pub type Time<R> = SIRatiosT<Zero, Zero, R>; | |
} | |
/// Convenient `SIExponentsT` types — Length, Mass, etc. | |
pub mod exponents { | |
use super::*; | |
// Base types | |
pub type Length = SIExponentsT<P1, Z0, Z0>; | |
pub type Mass = SIExponentsT<Z0, P1, Z0>; | |
pub type Time = SIExponentsT<Z0, Z0, P1>; | |
} | |
/// Convenient `SIUnitsT` types — `Length<R>`, `Mass<R>`, etc. | |
pub mod units { | |
use super::*; | |
pub type Dimensionless = SIUnitsT<SIRatiosT<Zero, Zero, Zero>, SIExponentsT<Z0, Z0, Z0>>; | |
pub type Length<R> = SIUnitsT<ratios::Length<R>, exponents::Length>; | |
pub type Mass<R> = SIUnitsT<ratios::Mass<R>, exponents::Mass>; | |
pub type Time<R> = SIUnitsT<ratios::Time<R>, exponents::Time>; | |
} | |
/// Convenient `QuantityT` types — `Length<T,R>`, `Velocity<T,RL,RT>`, etc. | |
pub mod quantities { | |
use super::*; | |
// Base | |
pub type Dimensionless<T> = | |
QuantityT<T, SIUnitsT<SIRatiosT<Zero, Zero, Zero>, SIExponentsT<Z0, Z0, Z0>>>; | |
pub type Length<T, R> = QuantityT<T, units::Length<R>>; | |
pub type Mass<T, R> = QuantityT<T, units::Mass<R>>; | |
pub type Time<T, R> = QuantityT<T, units::Time<R>>; | |
// Derived | |
pub type Area<T, R> = | |
QuantityT<T, SIUnitsT<SIRatiosT<R, Zero, Zero>, SIExponentsT<P2, Z0, Z0>>>; | |
pub type Velocity<T, RL, RT> = | |
QuantityT<T, SIUnitsT<SIRatiosT<RL, Zero, RT>, SIExponentsT<P1, Z0, N1>>>; | |
pub type Acceleration<T, RL, RT> = | |
QuantityT<T, SIUnitsT<SIRatiosT<RL, Zero, RT>, SIExponentsT<P1, Z0, N2>>>; | |
// Lengths | |
pub type Petameters<T> = Length<T, Peta>; | |
pub type Terameters<T> = Length<T, Tera>; | |
pub type Gigameters<T> = Length<T, Giga>; | |
pub type Megameters<T> = Length<T, Mega>; | |
pub type Kilometers<T> = Length<T, Kilo>; | |
pub type Hectometers<T> = Length<T, Hecto>; | |
pub type Decameters<T> = Length<T, Deca>; | |
pub type Zerometers<T> = Length<T, Zero>; | |
pub type Meters<T> = Length<T, Unit>; | |
pub type Decimeters<T> = Length<T, Deci>; | |
pub type Centimeters<T> = Length<T, Centi>; | |
pub type Millimeters<T> = Length<T, Milli>; | |
pub type Micrometers<T> = Length<T, Micro>; | |
pub type Nanometers<T> = Length<T, Nano>; | |
pub type Picometers<T> = Length<T, Pico>; | |
pub type Femtometers<T> = Length<T, Femto>; | |
// Masses | |
pub type Petagrams<T> = Mass<T, Peta>; | |
pub type Teragrams<T> = Mass<T, Tera>; | |
pub type Gigagrams<T> = Mass<T, Giga>; | |
pub type Megagrams<T> = Mass<T, Mega>; | |
pub type Kilograms<T> = Mass<T, Kilo>; | |
pub type Hectograms<T> = Mass<T, Hecto>; | |
pub type Decagrams<T> = Mass<T, Deca>; | |
pub type Zerograms<T> = Mass<T, Zero>; | |
pub type Grams<T> = Mass<T, Unit>; | |
pub type Decigrams<T> = Mass<T, Deci>; | |
pub type Centigrams<T> = Mass<T, Centi>; | |
pub type Milligrams<T> = Mass<T, Milli>; | |
pub type Micrograms<T> = Mass<T, Micro>; | |
pub type Nanograms<T> = Mass<T, Nano>; | |
pub type Picograms<T> = Mass<T, Pico>; | |
pub type Femtograms<T> = Mass<T, Femto>; | |
// Times | |
pub type Years<T> = Time<T, Year>; | |
pub type Days<T> = Time<T, Day>; | |
pub type Hours<T> = Time<T, Hour>; | |
pub type Minutes<T> = Time<T, Minute>; | |
pub type Seconds<T> = Time<T, Unit>; | |
pub type Milliseconds<T> = Time<T, Milli>; | |
pub type Microseconds<T> = Time<T, Micro>; | |
pub type Nanoseconds<T> = Time<T, Nano>; | |
pub type Picoseconds<T> = Time<T, Pico>; | |
pub type Femtoseconds<T> = Time<T, Femto>; | |
// Derived Units | |
pub type MetersPerSecond<T> = Velocity<T, Unit, Unit>; | |
pub type MetersPerSecond2<T> = Acceleration<T, Unit, Unit>; | |
pub type KilometersPerHour<T> = Velocity<T, Kilo, Hour>; | |
/// Convenient `QuantityT<f32, SIUnitsT<_,_>>` types — Meters, Kilograms, MetersPerSecond, etc. | |
pub mod f32 { | |
use super::*; | |
pub type Dimensionless = | |
QuantityT<f32, SIUnitsT<SIRatiosT<Zero, Zero, Zero>, SIExponentsT<Z0, Z0, Z0>>>; | |
pub type Length<R> = QuantityT<f32, units::Length<R>>; | |
pub type Mass<R> = QuantityT<f32, units::Mass<R>>; | |
pub type Time<R> = QuantityT<f32, units::Time<R>>; | |
pub type Petameters = Length<Peta>; | |
pub type Terameters = Length<Tera>; | |
pub type Gigameters = Length<Giga>; | |
pub type Megameters = Length<Mega>; | |
pub type Kilometers = Length<Kilo>; | |
pub type Hectometers = Length<Hecto>; | |
pub type Decameters = Length<Deca>; | |
pub type Zerometers = Length<Zero>; | |
pub type Meters = Length<Unit>; | |
pub type Decimeters = Length<Deci>; | |
pub type Centimeters = Length<Centi>; | |
pub type Millimeters = Length<Milli>; | |
pub type Micrometers = Length<Micro>; | |
pub type Nanometers = Length<Nano>; | |
pub type Picometers = Length<Pico>; | |
pub type Femtometers = Length<Femto>; | |
pub type Kilograms = Mass<Kilo>; | |
pub type Grams = Mass<Unit>; | |
pub type Years = Time<Year>; | |
pub type Days = Time<Day>; | |
pub type Hours = Time<Hour>; | |
pub type Minutes = Time<Minute>; | |
pub type Seconds = Time<Unit>; | |
pub type Milliseconds = Time<Milli>; | |
pub type Microseconds = Time<Micro>; | |
pub type Nanoseconds = Time<Nano>; | |
pub type Picoseconds = Time<Pico>; | |
pub type Femtoseconds = Time<Femto>; | |
pub type MetersPerSecond = super::MetersPerSecond<f32>; | |
pub type MetersPerSecond2 = super::MetersPerSecond2<f32>; | |
pub type KilometersPerHour = super::KilometersPerHour<f32>; | |
} | |
/// Dimensional traits for `impl Trait` use — `trait Length`, `trait Velocity`, etc. | |
pub mod traits { | |
use crate::quantity::{Amount, ConvertUnits, Quantity}; | |
use crate::ratio::Ratio; | |
// -------------------------------- | |
// Trait Declarations | |
// -------------------------------- | |
pub trait Length: Quantity + Copy { | |
fn convert<R>(self) -> super::Length<Self::AmountType, R> | |
where | |
R: Ratio, | |
Self::AmountType: Amount; | |
} | |
pub trait Time: Quantity + Copy { | |
fn convert<R>(self) -> super::Time<Self::AmountType, R> | |
where | |
R: Ratio, | |
Self::AmountType: Amount; | |
} | |
pub trait Area: Quantity { | |
fn convert<R>(self) -> super::Area<Self::AmountType, R> | |
where | |
R: Ratio, | |
Self::AmountType: Amount; | |
} | |
pub trait Velocity: Quantity { | |
fn convert<RL, RT>(self) -> super::Velocity<Self::AmountType, RL, RT> | |
where | |
RL: Ratio, | |
RT: Ratio, | |
Self::AmountType: Amount; | |
} | |
pub trait Acceleration: Quantity { | |
fn convert<RL, RT>(self) -> super::Acceleration<Self::AmountType, RL, RT> | |
where | |
RL: Ratio, | |
RT: Ratio, | |
Self::AmountType: Amount; | |
} | |
// -------------------------------- | |
// Trait Impls | |
// -------------------------------- | |
impl<T, R> Length for super::Length<T, R> | |
where | |
T: Amount | |
+ num_traits::NumCast | |
+ std::ops::Mul<T, Output = T> | |
+ std::ops::Div<T, Output = T>, | |
R: Ratio + Copy, | |
{ | |
fn convert<R2>(self) -> super::Length<Self::AmountType, R2> | |
where | |
R2: Ratio, | |
Self: super::ConvertUnits<super::Length<Self::AmountType, R2>>, | |
{ | |
self.convert_into() | |
} | |
} | |
impl<T, R> Time for super::Time<T, R> | |
where | |
T: Amount | |
+ num_traits::NumCast | |
+ std::ops::Mul<T, Output = T> | |
+ std::ops::Div<T, Output = T>, | |
R: Ratio + Copy, | |
{ | |
fn convert<R2>(self) -> super::Time<Self::AmountType, R2> | |
where | |
R2: Ratio, | |
Self: super::ConvertUnits<super::Time<Self::AmountType, R2>>, | |
{ | |
self.convert_into() | |
} | |
} | |
impl<T, R> Area for super::Area<T, R> | |
where | |
T: Amount | |
+ num_traits::NumCast | |
+ std::ops::Mul<T, Output = T> | |
+ std::ops::Div<T, Output = T>, | |
R: Ratio + Copy, | |
{ | |
fn convert<R2>(self) -> super::Area<Self::AmountType, R2> | |
where | |
R2: Ratio, | |
Self: super::ConvertUnits<super::Area<Self::AmountType, R2>>, | |
{ | |
self.convert_into() | |
} | |
} | |
impl<T, RL, RT> Velocity for super::Velocity<T, RL, RT> | |
where | |
T: Amount | |
+ num_traits::NumCast | |
+ std::ops::Mul<T, Output = T> | |
+ std::ops::Div<T, Output = T>, | |
RL: Ratio + Copy, | |
RT: Ratio + Copy, | |
{ | |
fn convert<RL2, RT2>(self) -> super::Velocity<Self::AmountType, RL2, RT2> | |
where | |
RL2: Ratio, | |
RT2: Ratio, | |
Self: super::ConvertUnits<super::Velocity<Self::AmountType, RL2, RT2>>, | |
{ | |
self.convert_into() | |
} | |
} | |
impl<T, RL, RT> Acceleration for super::Acceleration<T, RL, RT> | |
where | |
T: Amount | |
+ num_traits::NumCast | |
+ std::ops::Mul<T, Output = T> | |
+ std::ops::Div<T, Output = T>, | |
RL: Ratio + Copy, | |
RT: Ratio + Copy, | |
{ | |
fn convert<RL2, RT2>(self) -> super::Acceleration<Self::AmountType, RL2, RT2> | |
where | |
RL2: Ratio, | |
RT2: Ratio, | |
Self: super::ConvertUnits<super::Acceleration<Self::AmountType, RL2, RT2>>, | |
{ | |
self.convert_into() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment