1#[macro_export]
2macro_rules! units {
3 (
4 $(#[$blanket_meta:meta])*
5 $blanket:ident($($super:tt)*);
6 #[$derive:meta] $base:ty:
7 $(
8 $(#[$meta:meta])*
9 $tys:ident;
10 )*
11 $(
12 <$a:path> * <$b:path> = $c:path;
13 )*
14 ) => {
15 $(#[$blanket_meta])*
16 pub trait $blanket : $($super)* {
17 fn value(self) -> $base;
19 }
20
21 $(
22 $(#[$meta])*
23 #[$derive]
24 pub struct $tys(pub $base);
25
26 impl From<$base> for $tys {
27 #[inline(always)]
28 fn from(base: $base) -> Self {
29 Self(base)
30 }
31 }
32
33 impl $tys {
34 #[inline(always)]
36 pub fn value(self) -> $base {
37 self.0
38 }
39 }
40
41 impl $blanket for $tys {
42 #[inline(always)]
43 fn value(self) -> $base {
44 self.0
45 }
46 }
47
48 impl ::std::ops::Add for $tys {
49 type Output = Self;
50
51 #[inline(always)]
52 fn add(self, other: Self) -> Self {
53 $tys(self.value() + other.value())
54 }
55 }
56
57 impl ::std::ops::AddAssign for $tys {
58 #[inline(always)]
59 fn add_assign(&mut self, other: Self) {
60 self.0 += other.value();
61 }
62 }
63
64 impl ::std::ops::Sub for $tys {
65 type Output = Self;
66
67 #[inline(always)]
68 fn sub(self, other: Self) -> Self {
69 $tys(self.value() - other.value())
70 }
71 }
72
73 impl ::std::ops::SubAssign for $tys {
74 #[inline(always)]
75 fn sub_assign(&mut self, other: Self) {
76 self.0 -= other.value();
77 }
78 }
79
80 impl ::std::ops::Mul<$base> for $tys {
81 type Output = Self;
82
83 #[inline(always)]
84 fn mul(self, other: $base) -> Self {
85 Self(self.0 * other)
86 }
87 }
88
89 impl ::std::ops::MulAssign<$base> for $tys {
90 #[inline(always)]
91 fn mul_assign(&mut self, other: $base) {
92 self.0 *= other;
93 }
94 }
95
96 impl ::std::ops::DivAssign<$base> for $tys {
97 #[inline(always)]
98 fn div_assign(&mut self, other: $base) {
99 self.0 /= other;
100 }
101 }
102 )*
103
104 $(
105 impl ::std::ops::Mul<$b> for $a {
106 type Output = $c;
107
108 #[inline(always)]
109 fn mul(self, other: $b) -> $c {
110 $c(self.value() * other.value())
111 }
112 }
113
114 impl ::std::ops::Mul<$a> for $b {
115 type Output = $c;
116
117 #[inline(always)]
118 fn mul(self, other: $a) -> $c {
119 $c(self.value() * other.value())
120 }
121 }
122
123 impl ::std::ops::Div<$b> for $c {
124 type Output = $a;
125
126 #[inline(always)]
127 fn div(self, other: $b) -> $a {
128 $a(self.value() / other.value())
129 }
130 }
131
132 impl ::std::ops::Div<$a> for $c {
133 type Output = $b;
134
135 #[inline(always)]
136 fn div(self, other: $a) -> $b {
137 $b(self.value() / other.value())
138 }
139 }
140 )*
141 };
142}
143
144#[cfg(test)]
145mod tests {
146 units! {
147 Blanket(std::fmt::Debug + Clone + Copy + Default + PartialEq + PartialOrd);
148
149 #[derive(Debug, Clone, Copy, Default, PartialEq, PartialOrd)] f64:
150 Accel; Veloc; Length; Time; Mass; Force; Energy;
151
152 <Accel> * <Time> = Veloc;
153 <Veloc> * <Time> = Length;
154 <Mass> * <Accel> = Force;
155 <Force> * <Length> = Energy;
156 }
157}