1macro_rules! impl_unitstruct {
8 ($struct_type:ident, $units_type: ident, $($slf:ty)+) => {
9 impl $crate::units::UnitStruct<$units_type> for $($slf)+ {
10 type Output = $struct_type;
11
12 fn new(value: f64, units: $units_type) -> $struct_type {
13 $struct_type { value, units }
14 }
15
16 fn value(&self) -> f64 {
17 self.value
18 }
19
20 fn units(&self) -> $units_type {
21 self.units
22 }
23 }
24 impl Unit<$units_type> for $($slf)+ {
25 type Output = $struct_type;
26 fn as_unit(&self, units: $units_type) -> $struct_type
27 where
28 Self: Sized,
29 {
30 $struct_type {
31 value: units.from(self.value, self.units),
32 units,
33 }
34 }
35 }
36 };
37}
38
39macro_rules! impl_sub {
40 ($($out:ty)+, $units_type:ident, $($sub:ty)+, $($slf:ty)+) => {
41 impl<'a> core::ops::Sub<$($sub)+> for $($slf)+ {
42 type Output = $($out)+;
43
44 fn sub(self, rhs: $($sub)+) -> $($out)+ {
45 let val = <$($sub)+ as $crate::units::Unit::<$units_type>>::as_unit(&rhs, self.units()).value();
46 <$($slf)+ as $crate::units::UnitStruct::<$units_type>>::new(self.value() - val, self.units())
47 }
48 }
49 };
50}
51macro_rules! impl_add {
52 ($($out:ty)+, $units_type:ident, $($add:ty)+, $($slf:ty)+) => {
53 impl<'a> core::ops::Add<$($add)+> for $($slf)+ {
54 type Output = $($out)+;
55
56 fn add(self, rhs: $($add)+) -> $($out)+ {
57 let val = <$($add)+ as $crate::units::Unit::<$units_type>>::as_unit(&rhs, self.units()).value();
58 <$($slf)+ as $crate::units::UnitStruct::<$units_type>>::new(self.value() + val, self.units())
59 }
60 }
61 };
62}
63macro_rules! impl_subassign {
64 ($($out:ty)+, $units_type:ident, $($sub:ty)+, $($slf:ty)+) => {
65 impl<'a> core::ops::SubAssign<$($sub)+> for $($slf)+ {
66 fn sub_assign(&mut self, rhs: $($sub)+) {
67 let val = <$($sub)+ as $crate::units::Unit::<$units_type>>::as_unit(&rhs, self.units()).value();
68 self.value -= val;
69 }
70
71 }
72 };
73}
74macro_rules! impl_addassign {
75 ($($out:ty)+, $units_type:ident, $($add:ty)+, $($slf:ty)+) => {
76 impl<'a> core::ops::AddAssign<$($add)+> for $($slf)+ {
77 fn add_assign(&mut self, rhs: $($add)+) {
78 let val = <$($add)+ as $crate::units::Unit::<$units_type>>::as_unit(&rhs, self.units()).value();
79 self.value += val;
80 }
81 }
82 };
83}
84macro_rules! impl_div {
85 ($($out:ty)+, $units_type:ident, $($div:ty)+, $($slf:ty)+) => {
86 impl<'a> core::ops::Div<$($div)+> for $($slf)+ {
87 type Output = $($out)+ ;
88 fn div(self, rhs: $($div)+) -> $($out)+ {
89 <$($slf)+ as $crate::units::UnitStruct::<$units_type>>::new(self.value() / rhs, self.units())
90 }
91 }
92 impl<'a> core::ops::Div<$($slf)+> for $($slf)+ {
93 type Output = f64;
94 fn div(self, rhs: $($slf)+) -> Self::Output {
95 let upper = self.value();
96 let lower = <$($slf)+ as $crate::units::Unit::<$units_type>>::as_unit(&rhs, self.units()).value();
97 upper / lower
98 }
99 }
100 };
101}
102
103macro_rules! impl_divassign {
104 ($($out:ty)+, $units_type:ident, $($div:ty)+, $($slf:ty)+) => {
105 impl<'a> core::ops::DivAssign<$($div)+> for $($slf)+ {
106 fn div_assign(&mut self, rhs: $($div)+) {
107 self.value /= rhs;
108 }
109 }
110 };
111}
112
113macro_rules! impl_mul {
114 ($($out:ty)+, $units_type:ident, $($mul:ty)+, $($slf:ty)+) => {
115 impl<'a> core::ops::Mul<$($mul)+> for $($slf)+ {
116 type Output = $($out)+ ;
117 fn mul(self, rhs: $($mul)+) -> $($out)+ {
118 <$($slf)+ as $crate::units::UnitStruct::<$units_type>>::new(self.value() * rhs, self.units())
119 }
120 }
121 impl<'a> core::ops::Mul<$($slf)+> for $($slf)+ {
122 type Output = $($mul)+;
123 fn mul(self, rhs: $($slf)+) -> Self::Output {
124 let upper = self.value();
125 let lower = <$($slf)+ as $crate::units::Unit::<$units_type>>::as_unit(&rhs, self.units()).value();
126 upper * lower
127 }
128 }
129 impl<'a> core::ops::Mul<$($slf)+> for f64 {
130 type Output = $($out)+;
131 fn mul(self, rhs: $($slf)+) -> Self::Output {
132 rhs * self
133 }
134 }
135 };
136}
137macro_rules! impl_mulassign {
138 ($($out:ty)+, $units_type:ident, $($mul:ty)+, $($slf:ty)+) => {
139 impl<'a> core::ops::MulAssign<$($mul)+> for $($slf)+ {
140 fn mul_assign(&mut self, rhs: $($mul)+) {
141 self.value *= rhs;
142 }
143 }
144 };
150}
151
152macro_rules! impl_op {
153 ($op:ident, $units_type:ident, $($operand:ty)+) => {
154 $op!($($operand)+, $units_type, $($operand)+, $($operand)+);
155 $op!($($operand)+, $units_type, $($operand)+, &$($operand)+);
156 $op!($($operand)+, $units_type, $($operand)+, &mut $($operand)+);
157 $op!($($operand)+, $units_type, &$($operand)+, $($operand)+);
158 $op!($($operand)+, $units_type, &$($operand)+, &$($operand)+);
159 $op!($($operand)+, $units_type, &$($operand)+, &mut $($operand)+);
160 $op!($($operand)+, $units_type, &mut $($operand)+, $($operand)+);
161 $op!($($operand)+, $units_type, &mut $($operand)+, &$($operand)+);
162 $op!($($operand)+, $units_type, &mut $($operand)+, &mut $($operand)+);
163 };
164}
165macro_rules! impl_mutop {
166 ($op:ident, $units_type:ident, $($operand:ty)+) => {
167 $op!($($operand)+, $units_type, $($operand)+, $($operand)+);
168 $op!($($operand)+, $units_type, $($operand)+, &mut $($operand)+);
169 $op!($($operand)+, $units_type, &$($operand)+, $($operand)+);
170 $op!($($operand)+, $units_type, &$($operand)+, &mut $($operand)+);
171 $op!($($operand)+, $units_type, &mut $($operand)+, $($operand)+);
172 $op!($($operand)+, $units_type, &mut $($operand)+, &mut $($operand)+);
173 };
174}
175
176#[macro_export]
177macro_rules! basic_unit {
178 ($struct_type:ident, $units_type: ident, $default_units: ident) => {
179 #[derive(Debug, Clone, Copy, Default)]
180 pub struct $struct_type {
181 value: f64,
182 units: $units_type,
183 }
184
185 impl $struct_type {
186 #[must_use]
187 pub const fn new(value: f64, units: $units_type) -> Self {
188 Self { value, units }
189 }
190
191 #[must_use]
192 pub fn value(&self) -> f64 {
193 self.value
194 }
195
196 #[must_use]
197 pub fn units(&self) -> $units_type {
198 self.units
199 }
200 }
201
202 impl_unitstruct!($struct_type, $units_type, $struct_type);
203 impl_unitstruct!($struct_type, $units_type, &$struct_type);
204 impl_unitstruct!($struct_type, $units_type, &mut $struct_type);
205
206 impl_op!(impl_sub, $units_type, $struct_type);
207 impl_mutop!(impl_subassign, $units_type, $struct_type);
208 impl_op!(impl_add, $units_type, $struct_type);
209 impl_mutop!(impl_addassign, $units_type, $struct_type);
210 impl_div!($struct_type, $units_type, f64, $struct_type);
211 impl_div!($struct_type, $units_type, f64, &$struct_type);
212 impl_div!($struct_type, $units_type, f64, &mut $struct_type);
213 impl_divassign!($struct_type, $units_type, f64, $struct_type);
214 impl_divassign!($struct_type, $units_type, f64, &mut $struct_type);
215 impl_mul!($struct_type, $units_type, f64, $struct_type);
216 impl_mul!($struct_type, $units_type, f64, &$struct_type);
217 impl_mul!($struct_type, $units_type, f64, &mut $struct_type);
218 impl_mulassign!($struct_type, $units_type, f64, $struct_type);
219 impl_mulassign!($struct_type, $units_type, f64, &mut $struct_type);
220
221 impl core::cmp::PartialOrd<$struct_type> for $struct_type {
222 fn partial_cmp(&self, rhs: &$struct_type) -> Option<core::cmp::Ordering> {
223 Some(self.cmp(rhs))
224 }
225 }
226 impl core::cmp::Ord for $struct_type {
227 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
228 self.value.total_cmp(&other.as_unit(self.units).value)
229 }
230 }
231 impl core::cmp::Eq for $struct_type {}
232
233 impl core::cmp::PartialEq<$struct_type> for $struct_type {
234 fn eq(&self, rhs: &$struct_type) -> bool {
235 if let Some(val) = self.partial_cmp(rhs) {
236 return val == core::cmp::Ordering::Equal;
237 }
238 false
239 }
240 }
241
242 pub const ZERO: $struct_type = $struct_type::new(0.0, $units_type::$default_units);
243 };
244}
245
246pub trait FromUnits<T> {
249 fn from(&self, value: T, units: Self) -> T;
251}
252
253pub trait UnitStruct<T>: Unit<T> {
256 type Output;
257
258 fn new(value: f64, units: T) -> <Self as UnitStruct<T>>::Output;
260
261 fn value(&self) -> f64;
263
264 fn units(&self) -> T;
266}
267
268pub trait Unit<T> {
271 type Output;
272 #[must_use]
273 fn as_unit(&self, unit: T) -> Self::Output
274 where
275 Self: Sized;
276}
277
278pub mod angle;
279pub mod compass;
280pub mod datasize;
281pub mod duration;
282pub mod length;
283pub mod speed;
284pub mod temperature;