1use float_cmp::{ApproxEq, F64Margin};
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::iter::Sum;
7use std::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign};
8
9pub trait UnitType:
11 fmt::Debug
12 + Copy
13 + PartialEq
14 + PartialOrd
15 + Serialize
16 + Add
17 + Sub
18 + Div
19 + Mul<Dimensionless, Output = Self>
20 + AddAssign
21 + SubAssign
22 + Sum
23 + ApproxEq<Margin = F64Margin>
24 + fmt::Display
25 + Default
26{
27 fn new(value: f64) -> Self;
29 fn value(&self) -> f64;
31 fn is_normal(&self) -> bool;
33 fn is_finite(&self) -> bool;
35 fn abs(&self) -> Self;
37 fn max(&self, other: Self) -> Self;
39 fn min(&self, other: Self) -> Self;
41 fn total_cmp(&self, other: &Self) -> std::cmp::Ordering;
43}
44
45macro_rules! base_unit_struct {
46 ($name:ident) => {
47 #[derive(
49 Debug,
50 Clone,
51 Copy,
52 PartialEq,
53 PartialOrd,
54 Default,
55 Serialize,
56 derive_more::Add,
57 derive_more::Sub,
58 )]
59 pub struct $name(pub f64);
60
61 impl std::ops::Div<$name> for $name {
62 type Output = Dimensionless;
63 fn div(self, rhs: $name) -> Dimensionless {
64 Dimensionless(self.0 / rhs.0)
65 }
66 }
67 impl std::iter::Sum for $name {
68 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
69 iter.fold($name(0.0), |a, b| $name(a.0 + b.0))
70 }
71 }
72 impl AddAssign for $name {
73 fn add_assign(&mut self, other: Self) {
74 self.0 += other.0;
75 }
76 }
77 impl SubAssign for $name {
78 fn sub_assign(&mut self, other: Self) {
79 self.0 -= other.0;
80 }
81 }
82 impl fmt::Display for $name {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 write!(f, "{}", self.0)
85 }
86 }
87 impl float_cmp::ApproxEq for $name {
88 type Margin = float_cmp::F64Margin;
89 fn approx_eq<T: Into<Self::Margin>>(self, other: Self, margin: T) -> bool {
90 self.0.approx_eq(other.0, margin)
91 }
92 }
93 impl std::ops::Neg for $name {
94 type Output = $name;
95 fn neg(self) -> $name {
96 $name(-self.0)
97 }
98 }
99 impl $name {
100 pub fn new(value: f64) -> Self {
102 $name(value)
103 }
104 pub fn value(&self) -> f64 {
106 self.0
107 }
108 pub fn is_normal(&self) -> bool {
110 self.0.is_normal()
111 }
112 pub fn is_finite(&self) -> bool {
114 self.0.is_finite()
115 }
116 pub fn abs(&self) -> Self {
118 $name(self.0.abs())
119 }
120 pub fn max(&self, other: Self) -> Self {
122 Self(self.0.max(other.0))
123 }
124 pub fn min(&self, other: Self) -> Self {
126 Self(self.0.min(other.0))
127 }
128 pub fn total_cmp(&self, other: &Self) -> std::cmp::Ordering {
130 self.0.total_cmp(&other.0)
131 }
132 }
133 impl<'de> Deserialize<'de> for $name {
134 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
135 where
136 D: serde::Deserializer<'de>,
137 {
138 let value = f64::deserialize(deserializer)?;
139 if !value.is_finite() {
140 Err(serde::de::Error::custom("Value cannot be NaN or infinite"))?;
141 }
142
143 Ok($name(value))
144 }
145 }
146 impl UnitType for $name {
147 fn new(value: f64) -> Self {
149 Self::new(value)
150 }
151 fn value(&self) -> f64 {
153 Self::value(&self)
154 }
155 fn is_normal(&self) -> bool {
157 Self::is_normal(&self)
158 }
159 fn is_finite(&self) -> bool {
161 Self::is_finite(&self)
162 }
163 fn abs(&self) -> Self {
165 Self::abs(&self)
166 }
167 fn max(&self, other: Self) -> Self {
169 Self::max(&self, other)
170 }
171 fn min(&self, other: Self) -> Self {
173 Self::min(&self, other)
174 }
175 fn total_cmp(&self, other: &Self) -> std::cmp::Ordering {
177 Self::total_cmp(&self, other)
178 }
179 }
180 };
181}
182
183base_unit_struct!(Dimensionless);
185
186impl From<f64> for Dimensionless {
188 fn from(val: f64) -> Self {
189 Self(val)
190 }
191}
192impl From<Dimensionless> for f64 {
193 fn from(val: Dimensionless) -> Self {
194 val.0
195 }
196}
197
198impl Mul for Dimensionless {
199 type Output = Dimensionless;
200
201 fn mul(self, rhs: Self) -> Self::Output {
202 Dimensionless(self.0 * rhs.0)
203 }
204}
205
206impl Dimensionless {
207 pub fn powi(self, rhs: i32) -> Self {
209 Dimensionless(self.0.powi(rhs))
210 }
211}
212
213macro_rules! unit_struct {
215 ($name:ident) => {
216 base_unit_struct!($name);
217
218 impl std::ops::Mul<Dimensionless> for $name {
219 type Output = $name;
220 fn mul(self, rhs: Dimensionless) -> $name {
221 $name(self.0 * rhs.0)
222 }
223 }
224 impl std::ops::Mul<$name> for Dimensionless {
225 type Output = $name;
226 fn mul(self, rhs: $name) -> $name {
227 $name(self.0 * rhs.0)
228 }
229 }
230 impl std::ops::Div<Dimensionless> for $name {
231 type Output = $name;
232 fn div(self, rhs: Dimensionless) -> $name {
233 $name(self.0 / rhs.0)
234 }
235 }
236 };
237}
238
239unit_struct!(Money);
241unit_struct!(Flow);
242unit_struct!(Activity);
243unit_struct!(Capacity);
244unit_struct!(Year);
245
246unit_struct!(MoneyPerYear);
248unit_struct!(MoneyPerFlow);
249unit_struct!(MoneyPerCapacity);
250unit_struct!(MoneyPerCapacityPerYear);
251unit_struct!(MoneyPerActivity);
252unit_struct!(ActivityPerCapacity);
253unit_struct!(FlowPerActivity);
254unit_struct!(FlowPerCapacity);
255
256macro_rules! impl_div {
257 ($Lhs:ident, $Rhs:ident, $Out:ident) => {
258 impl std::ops::Div<$Rhs> for $Lhs {
259 type Output = $Out;
260 fn div(self, rhs: $Rhs) -> $Out {
261 $Out(self.0 / rhs.0)
262 }
263 }
264 impl std::ops::Div<$Out> for $Lhs {
265 type Output = $Rhs;
266 fn div(self, rhs: $Out) -> $Rhs {
267 $Rhs(self.0 / rhs.0)
268 }
269 }
270 impl std::ops::Mul<$Rhs> for $Out {
271 type Output = $Lhs;
272 fn mul(self, by: $Rhs) -> $Lhs {
273 $Lhs(self.0 * by.0)
274 }
275 }
276 impl std::ops::Mul<$Lhs> for $Out {
277 type Output = $Rhs;
278 fn mul(self, by: $Lhs) -> $Rhs {
279 $Rhs(self.0 * by.0)
280 }
281 }
282 impl std::ops::Mul<$Out> for $Rhs {
283 type Output = $Lhs;
284 fn mul(self, by: $Out) -> $Lhs {
285 $Lhs(self.0 * by.0)
286 }
287 }
288 impl std::ops::Mul<$Out> for $Lhs {
289 type Output = $Rhs;
290 fn mul(self, by: $Out) -> $Rhs {
291 $Rhs(self.0 * by.0)
292 }
293 }
294 };
295}
296
297impl_div!(Flow, Activity, FlowPerActivity);
299impl_div!(Flow, Capacity, FlowPerCapacity);
300impl_div!(Money, Year, MoneyPerYear);
301impl_div!(Money, Flow, MoneyPerFlow);
302impl_div!(Money, Capacity, MoneyPerCapacity);
303impl_div!(Money, Activity, MoneyPerActivity);
304impl_div!(Activity, Capacity, ActivityPerCapacity);
305impl_div!(MoneyPerYear, Capacity, MoneyPerCapacityPerYear);
306impl_div!(MoneyPerActivity, FlowPerActivity, MoneyPerFlow);
307impl_div!(MoneyPerCapacity, Year, MoneyPerCapacityPerYear);
308impl_div!(FlowPerCapacity, ActivityPerCapacity, FlowPerActivity);