metron_core/unit/scale/
exp.rs

1// use crate::convert::FromUnit;
2use crate::{Measure, Unit};
3use num_traits::Pow;
4use std::cmp::Ordering;
5use std::ops::{Mul, Sub};
6
7pub trait ExponentialScaledUnit {
8    type ExponentialScale;
9    type BaseUnit: Unit;
10}
11pub trait ExponentialScaleDefault
12where
13    Self: ExponentialScale<Self::ScaleBase>,
14    Self::ScaleBase: ScaleBase<Self::Base>,
15    <Self as ExponentialScale<Self::ScaleBase>>::ScaleExponent: ScaleExponent<Self::Exponent>,
16    Self::Base: Pow<<Self::Exponent as Sub<Self::Exponent>>::Output>,
17    Self::Exponent: PartialOrd<Self::Exponent> + Sub<Self::Exponent>,
18{
19    type ScaleBase;
20    type Base;
21    type Exponent;
22}
23pub trait ExponentialScale<SB> {
24    type ScaleExponent;
25}
26pub trait ScaleBase<B> {
27    const BASE: B;
28}
29pub trait ScaleExponent<E> {
30    const EXPONENT: E;
31}
32
33macro_rules! exp_scale_def {
34    ($unit:ident, $name:ident) => {
35        <<$unit as ExponentialScaledUnit>::ExponentialScale as ExponentialScaleDefault>::$name
36    };
37}
38
39impl<N, USelf> Measure<N, USelf>
40where
41    USelf
42        : Unit
43        + ExponentialScaledUnit,
44    <USelf as ExponentialScaledUnit>::ExponentialScale
45        : ExponentialScale<exp_scale_def!(USelf, ScaleBase)>
46        + ExponentialScaleDefault,
47    <<USelf as ExponentialScaledUnit>
48            ::ExponentialScale as ExponentialScale<exp_scale_def!(USelf, ScaleBase)>>
49            ::ScaleExponent
50        : ScaleExponent<exp_scale_def!(USelf, Exponent)>,
51    exp_scale_def!(USelf, ScaleBase)
52        : ScaleBase<exp_scale_def!(USelf, Base)>,
53    exp_scale_def!(USelf, Base)
54        : Pow<<exp_scale_def!(USelf, Exponent) as Sub<exp_scale_def!(USelf, Exponent)>>::Output>,
55    exp_scale_def!(USelf, Exponent)
56        : PartialOrd<exp_scale_def!(USelf, Exponent)>
57        + Sub<exp_scale_def!(USelf, Exponent)>,
58    N   : Mul<
59            <exp_scale_def!(USelf, Base) as Pow<
60                <exp_scale_def!(USelf, Exponent) as Sub>::Output,
61            >>::Output,
62            Output = N,
63        >,
64{
65    pub fn from_scale<UFrom>(from: Measure<N, UFrom>) -> Self
66    where
67        UFrom
68            : Unit
69            + ExponentialScaledUnit<
70                BaseUnit
71                    = <USelf as ExponentialScaledUnit>::BaseUnit,
72                ExponentialScale
73                    : ExponentialScale<
74                        exp_scale_def!(USelf, ScaleBase),
75                        ScaleExponent: ScaleExponent<exp_scale_def!(USelf, Exponent)>,
76                    >
77                    + ExponentialScaleDefault<
78                        ScaleBase = exp_scale_def!(USelf, ScaleBase),
79                        Base = exp_scale_def!(USelf, Base),
80                        Exponent = exp_scale_def!(USelf, Exponent),
81                    >,
82            >,
83    {
84        Self::from_scale_spec::<
85            UFrom,
86            exp_scale_def!(UFrom, ScaleBase),
87            exp_scale_def!(UFrom, Base),
88            exp_scale_def!(UFrom, Exponent),
89        >(from)
90    }
91}
92impl<N, USelf> Measure<N, USelf>
93where
94    USelf: Unit + ExponentialScaledUnit,
95{
96    fn from_scale_spec<UFrom, SB, B, E>(from: Measure<N, UFrom>) -> Self
97    where
98        USelf
99            : Unit
100            + ExponentialScaledUnit<
101                ExponentialScale: ExponentialScale<SB, ScaleExponent: ScaleExponent<E>>,
102            >,
103        UFrom
104            : Unit
105            + ExponentialScaledUnit<
106                BaseUnit = <USelf as ExponentialScaledUnit>::BaseUnit,
107                ExponentialScale: ExponentialScale<SB, ScaleExponent: ScaleExponent<E>>,
108            >,
109        SB  : ScaleBase<B>,
110        E   : PartialOrd<E> + Sub<E>,
111        B   : Pow<<E as Sub<E>>::Output>,
112        N   : Mul<<B as Pow<<E as Sub>::Output>>::Output, Output = N>,
113    {
114        let from_exp = <<<UFrom as ExponentialScaledUnit>::ExponentialScale as ExponentialScale<
115            SB,
116        >>::ScaleExponent as ScaleExponent<E>>::EXPONENT;
117        let into_exp = <<<USelf as ExponentialScaledUnit>::ExponentialScale as ExponentialScale<
118            SB,
119        >>::ScaleExponent as ScaleExponent<E>>::EXPONENT;
120        let ordering = {
121            let opt = from_exp.partial_cmp(&into_exp);
122            if opt.is_none() {
123                // anyhow::bail!("Can't compare exponents");
124                panic!("Can't compare exponents")
125            }
126            opt.unwrap()
127        };
128        let num = match ordering {
129            Ordering::Equal => from.num.into(),
130            _ => {
131                let base = <SB as ScaleBase<B>>::BASE;
132                let exp = from_exp - into_exp;
133                let ratio = base.pow(exp);
134                from.num * ratio
135            }
136        };
137        Self::new(num)
138    }
139}
140#[cfg(test)]
141mod test {
142    mod units {
143        use crate::unit::scale::exp::{
144            ExponentialScaleDefault, ExponentialScaledUnit,
145        };
146        use crate::Unit;
147        use crate::{def_exp_scale, def_exp_scale_base, def_exp_scale_exp};
148
149        def_exp_scale! {
150            pub    One[ BP10 =^ E0, BP1000 =^ E0, ],
151        }
152        def_exp_scale! {
153            pub   Kilo[ BP10 =^  EP3, BP1000 =^ EP1, ],
154            pub  Milli[ BP10 =^  EM3, BP1000 =^ EM1, ],
155        }
156        def_exp_scale_base! {
157            pub BP1000[f32 = 1000.0, f64 = 1000.0,],
158            pub   BP10[f32 =   10.0, f64 =   10.0,],
159        }
160        def_exp_scale_exp! {
161            pub    EP3[f32 =    3.0, f64 =    3.0,],
162            pub    EP1[f32 =    1.0, f64 =    1.0,],
163            pub     E0[f32 =    0.0, f64 =    0.0,],
164            pub    EM1[f32 = -  1.0, f64 = -  1.0,],
165            pub    EM3[f32 = -  3.0, f64 = -  3.0,],
166        }
167        impl ExponentialScaleDefault for Milli {
168            type ScaleBase = BP1000;
169            type Base = f32;
170            type Exponent = f32;
171        }
172        impl ExponentialScaleDefault for Kilo {
173            type ScaleBase = BP1000;
174            type Base = f32;
175            type Exponent = f32;
176        }
177        pub struct Meter;
178        impl Unit for Meter {}
179        pub struct MilliMeter;
180        impl Unit for MilliMeter{}
181        impl ExponentialScaledUnit for MilliMeter {
182            type ExponentialScale = Milli;
183            type BaseUnit = Meter;
184        }
185        pub struct KiloMeter;
186        impl Unit for KiloMeter{}
187        impl ExponentialScaledUnit for KiloMeter {
188            type ExponentialScale = Kilo;
189            type BaseUnit = Meter;
190        }
191    }
192    use crate::unit::scale::exp::Measure;
193    type MilliMeter<N> = Measure<N, units::MilliMeter>;
194    type KiloMeter<N> = Measure<N, units::KiloMeter>;
195
196    #[test]
197    fn test() {
198        let milli_meter = MilliMeter::new(1000.0);
199        let kilo_meter: KiloMeter<_> = KiloMeter::from_scale(milli_meter);
200        println!("{:?}", kilo_meter);
201    }
202}