1use crate::dimension::*;
2use crate::*;
3
4use crate::complex::c64;
5use crate::tensor::element::*;
6
7#[derive(Clone, Copy)]
10pub struct UnitParameters {
11 pub(crate) scale: f64,
12 pub(crate) offset: f64,
13 pub(crate) symbol: &'static str,
14 pub(crate) name: &'static str,
15}
16
17pub trait Unit {
18 type Dimension; fn parameters() -> UnitParameters;
21
22 fn to<S: Unit<Dimension = Self::Dimension>, E: TensorElement>(value: E) -> E
23 {
24 let base = Self::to_base(value.into());
25 S::from_base(base).into()
26 }
27
28 fn from<S: Unit<Dimension = Self::Dimension>, E: TensorElement>(value: E) -> E
29 {
30 let base = S::to_base(value.into());
31 Self::from_base(base).into()
32 }
33
34 fn to_base(value: c64) -> c64
35 {
36 let params = Self::parameters();
37 c64::from(( ((value.a * params.scale) + params.offset) as f64, ((value.b * params.scale) + params.offset) as f64))
38 }
39
40 fn from_base(value: c64) -> c64
41 {
42 let params = Self::parameters();
43 c64::from(( ((value.a / params.scale) - params.offset) as f64, ((value.b / params.scale) - params.offset) as f64))
44 }
45
46 fn symbol() -> &'static str {
48 Self::parameters().symbol
49 }
50 fn name() -> &'static str {
51 Self::parameters().name
52 }
53
54 fn ratio<T: Unit<Dimension = Self::Dimension>>() -> f64 {
62 let self_params = Self::parameters();
63 let other_params = T::parameters();
64 self_params.scale / other_params.scale
65 }
66}
67pub struct Unitless;
69impl Unit for Unitless {
70 type Dimension = Dimensionless;
71 fn parameters() -> UnitParameters {
72 UnitParameters {
73 scale: 1.0,
74 offset: 0.0,
75 symbol: "",
76 name: "Unitless",
77 }
78 }
79}
80impl Default for Unitless {
82 fn default() -> Self {
83 Unitless
84 }
85}
86
87use std::marker::PhantomData;
90
91pub struct UnitMul<L: Unit, R: Unit>(PhantomData<(L, R)>);
94
95impl<L: Unit, R: Unit> Unit for UnitMul<L, R>
96where
97 L::Dimension: MultiplyDimensions<R::Dimension>,
98{
99 type Dimension = dim_mul!((<L as Unit>::Dimension), (<R as Unit>::Dimension));
100 fn parameters() -> UnitParameters {
101 let lhs_params = L::parameters();
102 let rhs_params = R::parameters();
103 UnitParameters {
104 scale: lhs_params.scale * rhs_params.scale,
105 offset: 0.0,
106 symbol: "", name: "", }
109 }
110}
111
112pub struct UnitInv<T: Unit>(PhantomData<T>);
115
116impl<T: Unit> Unit for UnitInv<T>
117where
118 T::Dimension: InvertDimension,
119{
120 type Dimension = dim_inv!((<T as Unit>::Dimension));
122 fn parameters() -> UnitParameters {
123 let params = T::parameters();
124 UnitParameters {
125 scale: 1.0 / params.scale,
126 offset: 0.0,
127 symbol: "", name: "", }
130 }
131}
132
133#[macro_export]
136macro_rules! unit_mul {
137 ($lhs:ty, $rhs:ty) => {
138 UnitMul<$lhs, $rhs>
139 };
140}
141
142#[macro_export]
143macro_rules! unit_inv {
144 ($unit:ty) => {
145 UnitInv<$unit>
146 };
147}
148
149#[macro_export]
150macro_rules! unit_div {
151 ($lhs:ty, $rhs:ty) => {
152 UnitMul<$lhs, UnitInv<$rhs>>
153 };
154}
155