#[cfg(feature = "i256")]
use i256::{I256, U256};
use crate::{Fraction, TryMul};
pub trait ConvertUnit<From, Into>
where
From: ?Sized,
Into: ?Sized,
{
fn convert(self) -> Self;
}
macro_rules! impl_identity_conversion {
($repr:ty) => {
impl<T> ConvertUnit<T, T> for $repr
where
T: UnitRatio,
{
fn convert(self) -> Self {
self
}
}
};
}
impl_identity_conversion!(u8);
impl_identity_conversion!(u16);
impl_identity_conversion!(u32);
impl_identity_conversion!(u64);
impl_identity_conversion!(u128);
#[cfg(feature = "i256")]
impl_identity_conversion!(U256);
impl_identity_conversion!(i8);
impl_identity_conversion!(i16);
impl_identity_conversion!(i32);
impl_identity_conversion!(i64);
impl_identity_conversion!(i128);
#[cfg(feature = "i256")]
impl_identity_conversion!(I256);
impl<From, Into> ConvertUnit<From, Into> for f64
where
From: UnitRatio + ?Sized,
Into: UnitRatio + ?Sized,
{
fn convert(self) -> Self {
let combined_ratio = From::FRACTION.divide_by(&Into::FRACTION);
combined_ratio * self
}
}
impl<From, Into> ConvertUnit<From, Into> for f32
where
From: UnitRatio + ?Sized,
Into: UnitRatio + ?Sized,
{
fn convert(self) -> Self {
let combined_ratio = From::FRACTION.divide_by(&Into::FRACTION);
combined_ratio * self
}
}
pub trait TryConvertUnit<From, Into>: Sized
where
From: ?Sized,
Into: ?Sized,
{
fn try_convert(self) -> Option<Self>;
}
impl<T, From, Into> TryConvertUnit<From, Into> for T
where
T: TryMul<Fraction, Output = T>,
From: UnitRatio + ?Sized,
Into: UnitRatio + ?Sized,
{
fn try_convert(self) -> Option<Self> {
let combined_ratio = From::FRACTION.divide_by(&Into::FRACTION);
self.try_mul(combined_ratio)
}
}
pub trait UnitRatio {
const FRACTION: Fraction;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum LiteralRatio<const NUMERATOR: u128, const DENOMINATOR: u128 = 1> {}
impl<const NUMERATOR: u128, const DENOMINATOR: u128> UnitRatio
for LiteralRatio<NUMERATOR, DENOMINATOR>
{
const FRACTION: Fraction = Fraction::new(NUMERATOR, DENOMINATOR);
}
macro_rules! valid_integer_conversions {
(
$from:ty => $( $to:ty ),+ $(,)?
) => {
$(
valid_integer_conversion!(u8, $from, $to);
valid_integer_conversion!(u16, $from, $to);
valid_integer_conversion!(u32, $from, $to);
valid_integer_conversion!(u64, $from, $to);
valid_integer_conversion!(u128, $from, $to);
valid_integer_conversion!(i8, $from, $to);
valid_integer_conversion!(i16, $from, $to);
valid_integer_conversion!(i32, $from, $to);
valid_integer_conversion!(i64, $from, $to);
valid_integer_conversion!(i128, $from, $to);
#[cfg(feature = "i256")]
impl ConvertUnit<$from, $to> for U256 {
fn convert(self) -> Self {
let combined_ratio = <$from>::FRACTION.divide_by(&<$to>::FRACTION);
let factor = combined_ratio.numerator() / combined_ratio.denominator();
self * Self::from(factor)
}
}
#[cfg(feature = "i256")]
impl ConvertUnit<$from, $to> for I256 {
fn convert(self) -> Self {
let combined_ratio = <$from>::FRACTION.divide_by(&<$to>::FRACTION);
let factor = combined_ratio.numerator() / combined_ratio.denominator();
self * Self::from(factor)
}
}
)+
};
}
macro_rules! valid_integer_conversion {
($repr:ty, $from:ty, $into:ty) => {
impl ConvertUnit<$from, $into> for $repr {
fn convert(self) -> Self {
let combined_ratio = <$from>::FRACTION.divide_by(&<$into>::FRACTION);
let factor = combined_ratio.numerator() / combined_ratio.denominator();
self * (factor as Self)
}
}
};
}
pub type Quecto = LiteralRatio<1, 1_000_000_000_000_000_000_000_000_000_000>;
pub type Ronto = LiteralRatio<1, 1_000_000_000_000_000_000_000_000_000>;
pub type Yocto = LiteralRatio<1, 1_000_000_000_000_000_000_000_000>;
pub type Zepto = LiteralRatio<1, 1_000_000_000_000_000_000_000>;
pub type Atto = LiteralRatio<1, 1_000_000_000_000_000_000>;
pub type Femto = LiteralRatio<1, 1_000_000_000_000_000>;
pub type Pico = LiteralRatio<1, 1_000_000_000_000>;
pub type Nano = LiteralRatio<1, 1_000_000_000>;
pub type Micro = LiteralRatio<1, 1_000_000>;
pub type Milli = LiteralRatio<1, 1_000>;
pub type Centi = LiteralRatio<1, 100>;
pub type Deci = LiteralRatio<1, 10>;
pub type Deca = LiteralRatio<10>;
pub type Hecto = LiteralRatio<100>;
pub type Kilo = LiteralRatio<1_000>;
pub type Mega = LiteralRatio<1_000_000>;
pub type Giga = LiteralRatio<1_000_000_000>;
pub type Tera = LiteralRatio<1_000_000_000_000>;
pub type Peta = LiteralRatio<1_000_000_000_000_000>;
pub type Exa = LiteralRatio<1_000_000_000_000_000_000>;
pub type Zetta = LiteralRatio<1_000_000_000_000_000_000_000>;
pub type Yotta = LiteralRatio<1_000_000_000_000_000_000_000_000>;
pub type Ronna = LiteralRatio<1_000_000_000_000_000_000_000_000_000>;
pub type Quetta = LiteralRatio<1_000_000_000_000_000_000_000_000_000_000>;
valid_integer_conversions!(Ronto => Quecto);
valid_integer_conversions!(Yocto => Ronto, Quecto);
valid_integer_conversions!(Zepto => Yocto, Ronto, Quecto);
valid_integer_conversions!(Atto => Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Femto => Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Pico => Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Nano => Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Micro => Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Milli => Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Centi => Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Deci => Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Second => Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Deca => Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Hecto => Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Kilo => Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Mega => Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Giga => Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Tera => Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Peta => Tera, Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Exa => Peta, Tera, Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Zetta => Exa, Peta, Tera, Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Yotta => Zetta, Exa, Peta, Tera, Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Ronna => Yotta, Zetta, Exa, Peta, Tera, Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
valid_integer_conversions!(Quetta => Ronna, Yotta, Zetta, Exa, Peta, Tera, Giga, Mega, Kilo, Hecto, Deca, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto, Zepto, Yocto, Ronto, Quecto);
pub type Second = LiteralRatio<1>;
pub type SecondsPerMinute = LiteralRatio<60>;
pub type SecondsPerHour = LiteralRatio<3600>;
pub type SecondsPerHalfDay = LiteralRatio<43200>;
pub type SecondsPerDay = LiteralRatio<86400>;
pub type SecondsPerWeek = LiteralRatio<604800>;
pub type SecondsPerMonth = LiteralRatio<2629746>;
pub type SecondsPerYear = LiteralRatio<31556952>;
valid_integer_conversions!(SecondsPerMinute => Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
valid_integer_conversions!(SecondsPerHour => SecondsPerMinute, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
valid_integer_conversions!(SecondsPerHalfDay => SecondsPerHour, SecondsPerMinute, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
valid_integer_conversions!(SecondsPerDay => SecondsPerHalfDay, SecondsPerHour, SecondsPerMinute, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
valid_integer_conversions!(SecondsPerWeek => SecondsPerDay, SecondsPerHalfDay, SecondsPerHour, SecondsPerMinute, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
valid_integer_conversions!(SecondsPerMonth => SecondsPerWeek, SecondsPerDay, SecondsPerHalfDay, SecondsPerHour, SecondsPerMinute, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
valid_integer_conversions!(SecondsPerYear => SecondsPerMonth, SecondsPerWeek, SecondsPerDay, SecondsPerHalfDay, SecondsPerHour, SecondsPerMinute, Second, Deci, Centi, Milli, Micro, Nano, Pico, Femto, Atto);
pub type BinaryFraction1 = LiteralRatio<1, 0x100>;
pub type BinaryFraction2 = LiteralRatio<1, 0x10000>;
pub type BinaryFraction3 = LiteralRatio<1, 0x1000000>;
pub type BinaryFraction4 = LiteralRatio<1, 0x100000000>;
pub type BinaryFraction5 = LiteralRatio<1, 0x10000000000>;
pub type BinaryFraction6 = LiteralRatio<1, 0x1000000000000>;
pub type BinaryFraction7 = LiteralRatio<1, 0x100000000000000>;
pub type BinaryFraction8 = LiteralRatio<1, 0x10000000000000000>;
pub type BinaryFraction9 = LiteralRatio<1, 0x1000000000000000000>;
pub type BinaryFraction10 = LiteralRatio<1, 0x100000000000000000000>;
valid_integer_conversions!(BinaryFraction9 => BinaryFraction10);
valid_integer_conversions!(BinaryFraction8 => BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction7 => BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction6 => BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction5 => BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction4 => BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction3 => BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction2 => BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(BinaryFraction1 => BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Second => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Deca => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Hecto => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Kilo => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Mega => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Giga => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Tera => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Peta => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(Exa => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(SecondsPerMinute => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(SecondsPerHour => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(SecondsPerDay => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(SecondsPerWeek => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(SecondsPerMonth => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);
valid_integer_conversions!(SecondsPerYear => BinaryFraction1, BinaryFraction2, BinaryFraction3, BinaryFraction4, BinaryFraction5, BinaryFraction6, BinaryFraction7, BinaryFraction8, BinaryFraction9, BinaryFraction10);