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{
26 fn new(value: f64) -> Self;
28 fn value(&self) -> f64;
30 fn is_normal(&self) -> bool;
32 fn is_finite(&self) -> bool;
34 fn abs(&self) -> Self;
36 fn max(&self, other: Self) -> Self;
38 fn min(&self, other: Self) -> Self;
40 fn total_cmp(&self, other: &Self) -> std::cmp::Ordering;
42}
43
44macro_rules! base_unit_struct {
45 ($name:ident) => {
46 #[derive(
48 Debug,
49 Clone,
50 Copy,
51 PartialEq,
52 PartialOrd,
53 Serialize,
54 derive_more::Add,
55 derive_more::Sub,
56 )]
57 pub struct $name(pub f64);
58
59 impl std::ops::Div<$name> for $name {
60 type Output = Dimensionless;
61 fn div(self, rhs: $name) -> Dimensionless {
62 Dimensionless(self.0 / rhs.0)
63 }
64 }
65 impl std::iter::Sum for $name {
66 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
67 iter.fold($name(0.0), |a, b| $name(a.0 + b.0))
68 }
69 }
70 impl AddAssign for $name {
71 fn add_assign(&mut self, other: Self) {
72 self.0 += other.0;
73 }
74 }
75 impl SubAssign for $name {
76 fn sub_assign(&mut self, other: Self) {
77 self.0 -= other.0;
78 }
79 }
80 impl fmt::Display for $name {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 write!(f, "{}", self.0)
83 }
84 }
85 impl float_cmp::ApproxEq for $name {
86 type Margin = float_cmp::F64Margin;
87 fn approx_eq<T: Into<Self::Margin>>(self, other: Self, margin: T) -> bool {
88 self.0.approx_eq(other.0, margin)
89 }
90 }
91 impl std::ops::Neg for $name {
92 type Output = $name;
93 fn neg(self) -> $name {
94 $name(-self.0)
95 }
96 }
97 impl $name {
98 pub const EPSILON: $name = $name(f64::EPSILON);
100
101 pub fn new(value: f64) -> Self {
103 $name(value)
104 }
105 pub fn value(&self) -> f64 {
107 self.0
108 }
109 pub fn is_normal(&self) -> bool {
111 self.0.is_normal()
112 }
113 pub fn is_finite(&self) -> bool {
115 self.0.is_finite()
116 }
117 pub fn abs(&self) -> Self {
119 $name(self.0.abs())
120 }
121 pub fn max(&self, other: Self) -> Self {
123 Self(self.0.max(other.0))
124 }
125 pub fn min(&self, other: Self) -> Self {
127 Self(self.0.min(other.0))
128 }
129 pub fn total_cmp(&self, other: &Self) -> std::cmp::Ordering {
131 self.0.total_cmp(&other.0)
132 }
133 }
134 impl<'de> Deserialize<'de> for $name {
135 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
136 where
137 D: serde::Deserializer<'de>,
138 {
139 let value = f64::deserialize(deserializer)?;
140 if !value.is_finite() {
141 Err(serde::de::Error::custom("Value cannot be NaN or infinite"))?;
142 }
143
144 Ok($name(value))
145 }
146 }
147 impl UnitType for $name {
148 fn new(value: f64) -> Self {
150 Self::new(value)
151 }
152 fn value(&self) -> f64 {
154 Self::value(&self)
155 }
156 fn is_normal(&self) -> bool {
158 Self::is_normal(&self)
159 }
160 fn is_finite(&self) -> bool {
162 Self::is_finite(&self)
163 }
164 fn abs(&self) -> Self {
166 Self::abs(&self)
167 }
168 fn max(&self, other: Self) -> Self {
170 Self::max(&self, other)
171 }
172 fn min(&self, other: Self) -> Self {
174 Self::min(&self, other)
175 }
176 fn total_cmp(&self, other: &Self) -> std::cmp::Ordering {
178 Self::total_cmp(&self, other)
179 }
180 }
181 };
182}
183
184base_unit_struct!(Dimensionless);
186
187impl From<f64> for Dimensionless {
189 fn from(val: f64) -> Self {
190 Self(val)
191 }
192}
193impl From<Dimensionless> for f64 {
194 fn from(val: Dimensionless) -> Self {
195 val.0
196 }
197}
198
199impl Mul for Dimensionless {
200 type Output = Dimensionless;
201
202 fn mul(self, rhs: Self) -> Self::Output {
203 Dimensionless(self.0 * rhs.0)
204 }
205}
206
207impl Dimensionless {
208 pub fn powi(self, rhs: i32) -> Self {
210 Dimensionless(self.0.powi(rhs))
211 }
212}
213
214macro_rules! unit_struct {
216 ($name:ident) => {
217 base_unit_struct!($name);
218
219 impl std::ops::Mul<Dimensionless> for $name {
220 type Output = $name;
221 fn mul(self, rhs: Dimensionless) -> $name {
222 $name(self.0 * rhs.0)
223 }
224 }
225 impl std::ops::Mul<$name> for Dimensionless {
226 type Output = $name;
227 fn mul(self, rhs: $name) -> $name {
228 $name(self.0 * rhs.0)
229 }
230 }
231 impl std::ops::Div<Dimensionless> for $name {
232 type Output = $name;
233 fn div(self, rhs: Dimensionless) -> $name {
234 $name(self.0 / rhs.0)
235 }
236 }
237 };
238}
239
240unit_struct!(Money);
242unit_struct!(Flow);
243unit_struct!(Activity);
244unit_struct!(Capacity);
245unit_struct!(Year);
246
247unit_struct!(MoneyPerYear);
249unit_struct!(MoneyPerFlow);
250unit_struct!(MoneyPerCapacity);
251unit_struct!(MoneyPerCapacityPerYear);
252unit_struct!(MoneyPerActivity);
253unit_struct!(ActivityPerCapacity);
254unit_struct!(FlowPerActivity);
255unit_struct!(FlowPerCapacity);
256unit_struct!(CapacityPerYear);
257
258macro_rules! impl_div {
259 ($Lhs:ident, $Rhs:ident, $Out:ident) => {
260 impl std::ops::Div<$Rhs> for $Lhs {
261 type Output = $Out;
262 fn div(self, rhs: $Rhs) -> $Out {
263 $Out(self.0 / rhs.0)
264 }
265 }
266 impl std::ops::Div<$Out> for $Lhs {
267 type Output = $Rhs;
268 fn div(self, rhs: $Out) -> $Rhs {
269 $Rhs(self.0 / rhs.0)
270 }
271 }
272 impl std::ops::Mul<$Rhs> for $Out {
273 type Output = $Lhs;
274 fn mul(self, by: $Rhs) -> $Lhs {
275 $Lhs(self.0 * by.0)
276 }
277 }
278 impl std::ops::Mul<$Lhs> for $Out {
279 type Output = $Rhs;
280 fn mul(self, by: $Lhs) -> $Rhs {
281 $Rhs(self.0 * by.0)
282 }
283 }
284 impl std::ops::Mul<$Out> for $Rhs {
285 type Output = $Lhs;
286 fn mul(self, by: $Out) -> $Lhs {
287 $Lhs(self.0 * by.0)
288 }
289 }
290 impl std::ops::Mul<$Out> for $Lhs {
291 type Output = $Rhs;
292 fn mul(self, by: $Out) -> $Rhs {
293 $Rhs(self.0 * by.0)
294 }
295 }
296 };
297}
298
299impl_div!(Flow, Activity, FlowPerActivity);
301impl_div!(Flow, Capacity, FlowPerCapacity);
302impl_div!(Money, Year, MoneyPerYear);
303impl_div!(Money, Flow, MoneyPerFlow);
304impl_div!(Money, Capacity, MoneyPerCapacity);
305impl_div!(Money, Activity, MoneyPerActivity);
306impl_div!(Activity, Capacity, ActivityPerCapacity);
307impl_div!(MoneyPerYear, Capacity, MoneyPerCapacityPerYear);
308impl_div!(MoneyPerActivity, FlowPerActivity, MoneyPerFlow);
309impl_div!(MoneyPerCapacity, Year, MoneyPerCapacityPerYear);
310impl_div!(FlowPerCapacity, ActivityPerCapacity, FlowPerActivity);
311impl_div!(Capacity, Year, CapacityPerYear);