1use 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 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}