dlt/
units.rs

1use crate::dimension::*;
2use crate::*;
3
4use crate::complex::c64;
5use crate::tensor::element::*;
6
7// define units for our dimensions
8// units will be used as interfaces to our dimensions
9#[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; // Associated dimension type
19    
20    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    // print
47    fn symbol() -> &'static str {
48        Self::parameters().symbol
49    }
50    fn name() -> &'static str {
51        Self::parameters().name
52    }
53
54    /// Returns the conversion ratio from the current unit into unit T.
55    ///
56    /// The ratio is computed as:
57    /// 
58    ///     self.scale / T::parameters().scale
59    ///
60    /// This function assumes that both units share the same Dimension.
61    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}
67// Unitless trait unit
68pub 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}
80// implement default for Unitless
81impl Default for Unitless {
82    fn default() -> Self {
83        Unitless
84    }
85}
86
87// ---------- MACROS ----------
88
89use std::marker::PhantomData;
90
91// --- UnitMul definition and impl ---
92
93pub 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: "", // Optionally, combine lhs_params.symbol and rhs_params.symbol
107            name: "",   // Optionally, combine lhs_params.name and rhs_params.name
108        }
109    }
110}
111
112// --- UnitInv definition and impl ---
113
114pub struct UnitInv<T: Unit>(PhantomData<T>);
115
116impl<T: Unit> Unit for UnitInv<T>
117where
118    T::Dimension: InvertDimension,
119{
120    // Wrap the type expression in parentheses.
121    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: "", // Optionally, adjust to display inversion (e.g., "1/<symbol>")
128            name: "",   // Optionally, adjust to display inversion (e.g., "per <name>")
129        }
130    }
131}
132
133// --- Macros for unit multiplication, inversion, division, and ratio ---
134
135#[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