1use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::ops::{AddAssign, Mul, SubAssign};
6
7macro_rules! base_unit_struct {
8 ($name:ident) => {
9 #[derive(
11 Debug,
12 Clone,
13 Copy,
14 PartialEq,
15 PartialOrd,
16 Serialize,
17 Deserialize,
18 derive_more::Add,
19 derive_more::Sub,
20 )]
21 pub struct $name(pub f64);
22
23 impl std::ops::Div<$name> for $name {
24 type Output = Dimensionless;
25 fn div(self, rhs: $name) -> Dimensionless {
26 Dimensionless(self.0 / rhs.0)
27 }
28 }
29 impl std::iter::Sum for $name {
30 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
31 iter.fold($name(0.0), |a, b| $name(a.0 + b.0))
32 }
33 }
34 impl AddAssign for $name {
35 fn add_assign(&mut self, other: Self) {
36 self.0 += other.0;
37 }
38 }
39 impl SubAssign for $name {
40 fn sub_assign(&mut self, other: Self) {
41 self.0 -= other.0;
42 }
43 }
44 impl fmt::Display for $name {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 write!(f, "{}", self.0)
47 }
48 }
49 impl float_cmp::ApproxEq for $name {
50 type Margin = float_cmp::F64Margin;
51 fn approx_eq<T: Into<Self::Margin>>(self, other: Self, margin: T) -> bool {
52 self.0.approx_eq(other.0, margin)
53 }
54 }
55 impl $name {
56 pub fn value(&self) -> f64 {
58 self.0
59 }
60 pub fn is_normal(&self) -> bool {
62 self.0.is_normal()
63 }
64 pub fn is_finite(&self) -> bool {
66 self.0.is_finite()
67 }
68 pub fn abs(&self) -> Self {
70 $name(self.0.abs())
71 }
72 pub fn max(&self, other: Self) -> Self {
74 Self(self.0.max(other.0))
75 }
76 pub fn min(&self, other: Self) -> Self {
78 Self(self.0.min(other.0))
79 }
80 }
81 };
82}
83
84base_unit_struct!(Dimensionless);
86
87impl From<f64> for Dimensionless {
89 fn from(val: f64) -> Self {
90 Self(val)
91 }
92}
93impl From<Dimensionless> for f64 {
94 fn from(val: Dimensionless) -> Self {
95 val.0
96 }
97}
98
99impl Mul for Dimensionless {
100 type Output = Dimensionless;
101
102 fn mul(self, rhs: Self) -> Self::Output {
103 Dimensionless(self.0 * rhs.0)
104 }
105}
106
107impl Dimensionless {
108 pub fn powi(self, rhs: i32) -> Self {
110 Dimensionless(self.0.powi(rhs))
111 }
112}
113
114macro_rules! unit_struct {
116 ($name:ident) => {
117 base_unit_struct!($name);
118
119 impl std::ops::Mul<Dimensionless> for $name {
120 type Output = $name;
121 fn mul(self, rhs: Dimensionless) -> $name {
122 $name(self.0 * rhs.0)
123 }
124 }
125 impl std::ops::Mul<$name> for Dimensionless {
126 type Output = $name;
127 fn mul(self, rhs: $name) -> $name {
128 $name(self.0 * rhs.0)
129 }
130 }
131 impl std::ops::Div<Dimensionless> for $name {
132 type Output = $name;
133 fn div(self, rhs: Dimensionless) -> $name {
134 $name(self.0 / rhs.0)
135 }
136 }
137 };
138}
139
140unit_struct!(Money);
142unit_struct!(Flow);
143unit_struct!(Activity);
144unit_struct!(Capacity);
145unit_struct!(Year);
146
147unit_struct!(MoneyPerYear);
149unit_struct!(MoneyPerFlow);
150unit_struct!(MoneyPerCapacity);
151unit_struct!(MoneyPerCapacityPerYear);
152unit_struct!(MoneyPerActivity);
153unit_struct!(ActivityPerCapacity);
154unit_struct!(FlowPerActivity);
155
156macro_rules! impl_div {
157 ($Lhs:ident, $Rhs:ident, $Out:ident) => {
158 impl std::ops::Div<$Rhs> for $Lhs {
159 type Output = $Out;
160 fn div(self, rhs: $Rhs) -> $Out {
161 $Out(self.0 / rhs.0)
162 }
163 }
164 impl std::ops::Mul<$Rhs> for $Out {
165 type Output = $Lhs;
166 fn mul(self, by: $Rhs) -> $Lhs {
167 $Lhs(self.0 * by.0)
168 }
169 }
170 impl std::ops::Mul<$Lhs> for $Out {
171 type Output = $Rhs;
172 fn mul(self, by: $Lhs) -> $Rhs {
173 $Rhs(self.0 * by.0)
174 }
175 }
176 impl std::ops::Mul<$Out> for $Rhs {
177 type Output = $Lhs;
178 fn mul(self, by: $Out) -> $Lhs {
179 $Lhs(self.0 * by.0)
180 }
181 }
182 impl std::ops::Mul<$Out> for $Lhs {
183 type Output = $Rhs;
184 fn mul(self, by: $Out) -> $Rhs {
185 $Rhs(self.0 * by.0)
186 }
187 }
188 };
189}
190
191impl_div!(Flow, Activity, FlowPerActivity);
193impl_div!(Money, Year, MoneyPerYear);
194impl_div!(Money, Flow, MoneyPerFlow);
195impl_div!(Money, Capacity, MoneyPerCapacity);
196impl_div!(Money, Activity, MoneyPerActivity);
197impl_div!(Activity, Capacity, ActivityPerCapacity);
198impl_div!(MoneyPerYear, Capacity, MoneyPerCapacityPerYear);
199impl_div!(MoneyPerActivity, FlowPerActivity, MoneyPerFlow);