1#![cfg_attr(feature="unstable", feature(unboxed_closures, core, zero_one))]
2
3extern crate tylar;
4
5#[doc(no_inline)]
6pub use tylar::{NumType,Zero,P1};
7#[doc(no_inline,hidden)]
8pub use tylar::Sub as TSub;
9#[doc(no_inline,hidden)]
10pub use tylar::Add as TAdd;
11#[doc(no_inline,hidden)]
12pub use tylar::Halve as THalve;
13
14use std::fmt::{Formatter,Result};
15
16pub trait UnitFormat { fn fmt(&mut Formatter) -> Result; }
19pub trait UnitZero {}
20pub trait UnitAdd<RHS> { type Out; }
21pub trait UnitSub<RHS> { type Out; }
22pub trait UnitMul<RHS> { type Out; }
23pub trait UnitDiv<RHS> { type Out; }
24pub trait UnitSqrt { type Out; }
25
26#[macro_export]
27macro_rules! units {( $name:ident { $( $dim:ident[$unit:ident]),+ } ) => {
28 use $crate::{UnitZero,UnitAdd,UnitSub,UnitMul,UnitDiv,UnitSqrt,UnitFormat};
29 use std::marker::PhantomData;
30 use std::fmt::{Debug,Formatter,Result};
31 use std::ops::{Add,Sub,Mul,Div,Deref};
32 use $crate::{NumType,Zero,P1,TAdd,TSub,THalve};
33
34 #[derive(Copy,Clone,PartialEq,PartialOrd,Eq,Ord)]
36 pub struct $name<D,N=f64> {
37 amount: N,
38 phantom: PhantomData<D>
39 }
40
41 impl<D,N> $name<D,N> {
42 fn new(v: N) -> Self {
43 $name { amount: v, phantom: PhantomData }
44 }
45 }
46
47 impl<D:UnitFormat,N> Debug for $name<D,N> where N:Debug {
48 fn fmt(&self, formatter: &mut Formatter) -> Result {
49 try!(self.amount.fmt(formatter));
50 D::fmt(formatter)
51 }
52 }
53
54 impl<D1,D2,N1,N2> Add<$name<D2,N2>> for $name<D1,N1> where D1:UnitAdd<D2>, N1:Add<N2> {
57 type Output = $name<D1::Out, N1::Output>;
58
59 fn add(self, rhs: $name<D2,N2>) -> Self::Output {
60 $name::new(self.amount + rhs.amount)
61 }
62 }
63
64 impl<D1,D2,N1,N2> Sub<$name<D2,N2>> for $name<D1,N1> where D1:UnitSub<D2>, N1:Sub<N2> {
65 type Output = $name<D1::Out, N1::Output>;
66
67 fn sub(self, rhs: $name<D2,N2>) -> Self::Output {
68 $name::new(self.amount - rhs.amount)
69 }
70 }
71
72 impl<D1,D2,N1,N2> Mul<$name<D2,N2>> for $name<D1,N1> where D1:UnitMul<D2>, N1:Mul<N2> {
73 type Output = $name<D1::Out, N1::Output>;
74
75 fn mul(self, rhs: $name<D2,N2>) -> Self::Output {
76 $name::new(self.amount * rhs.amount)
77 }
78 }
79
80 impl<D1,D2,N1,N2> Div<$name<D2,N2>> for $name<D1,N1> where D1:UnitDiv<D2>, N1: Div<N2> {
81 type Output = $name<D1::Out, N1::Output>;
82
83 fn div(self, rhs: $name<D2,N2>) -> Self::Output {
84 $name::new(self.amount / rhs.amount)
85 }
86 }
87
88 #[allow(dead_code)]
92 impl<D1> $name<D1,f64> where D1:UnitSqrt {
93 pub fn sqrt(self) -> $name<D1::Out,f64> {
94 $name::new(self.amount.sqrt())
95 }
96 }
97
98 #[allow(dead_code)]
99 impl<D1> $name<D1,f32> where D1:UnitSqrt {
100 pub fn sqrt(self) -> $name<D1::Out,f32> {
101 $name::new(self.amount.sqrt())
102 }
103 }
104
105 impl<D:UnitZero,N> Deref for $name<D,N> {
107 type Target = N;
108 fn deref(&self) -> &Self::Target { &self.amount }
109 }
110
111 #[cfg(feature = "unstable")]
114 impl <D,N> ::std::num::Zero for $name<D,N> where N: ::std::num::Zero {
115 fn zero() -> Self {
116 $name::new(N::zero())
117 }
118 }
119
120 __dim_fn_call_helper!($name);
123
124 #[cfg(not(feature = "unstable"))]
126 impl<D> Mul<$name<D,f64>> for f64 {
127 type Output = $name<D,f64>;
128 fn mul(self, rhs: $name<D,f64>) -> Self::Output {
129 $name::new(self * rhs.amount)
130 }
131 }
132
133 #[cfg(not(feature = "unstable"))]
134 impl<D> Mul<$name<D,f32>> for f32 {
135 type Output = $name<D,f32>;
136 fn mul(self, rhs: $name<D,f32>) -> Self::Output {
137 $name::new(self * rhs.amount)
138 }
139 }
140
141 #[derive(Copy,Clone,PartialEq,PartialOrd,Eq,Ord)]
142 #[allow(non_snake_case)]
143 pub struct Unit<$($dim:NumType=Zero),+> {
144 $($dim: PhantomData<$dim>),+
145 }
146
147 impl<$($dim:NumType),+> UnitFormat for Unit<$($dim),+> {
150 fn fmt(formatter: &mut Formatter) -> Result {
151 let mut exp: i32;
152 $(
153 exp = $dim::new().into();
154 match exp {
155 0 => (),
156 1 => try!(write!(formatter, " {}", stringify!($unit))),
157 _ => try!(write!(formatter, " {}^{:?}", stringify!($unit), exp))
158 }
159 )+
160 Ok(())
161 }
162 }
163
164 impl<$($dim:NumType),+> UnitAdd<Unit<$($dim),+>> for Unit<$($dim),+> { type Out = Unit<$($dim),+>; }
165
166 impl<$($dim:NumType),+> UnitSub<Unit<$($dim),+>> for Unit<$($dim),+> { type Out = Unit<$($dim),+>; }
167
168 #[allow(non_camel_case_types)]
171 impl<$($dim:NumType),+ , $($unit:NumType),+> UnitMul<Unit<$($unit),+>> for Unit<$($dim),+>
172 where $($dim:TAdd<$unit>),+ { type Out = Unit<$(<$dim as TAdd<$unit>>::Out),+>; }
173
174 #[allow(non_camel_case_types)]
175 impl<$($dim:NumType),+ , $($unit:NumType),+> UnitDiv<Unit<$($unit),+>> for Unit<$($dim),+>
176 where $($dim:TSub<$unit>),+ { type Out = Unit<$(<$dim as TSub<$unit>>::Out),+>; }
177
178 impl<$($dim:NumType),+> UnitSqrt for Unit<$($dim),+>
179 where $($dim:THalve),+ { type Out = Unit<$(<$dim as THalve>::Out),+>; }
180
181 pub type One = Unit;
183 impl UnitZero for One {}
184
185 __dim_type_alias_helper! { $($dim),+ -> P1 }
187
188 pub mod f64 {
189 use std::marker::PhantomData;
190 use super::{$name,One,$($dim),+};
191
192 #[allow(non_upper_case_globals, dead_code)]
193 pub const one: $name<One, f64> = $name {
194 amount: 1.0,
195 phantom: PhantomData
196 };
197
198 $(
199 #[allow(non_upper_case_globals, dead_code)]
200 pub const $unit: $name<$dim, f64> = $name {
201 amount: 1.0,
202 phantom: PhantomData
203 };
204 )+
205 }
206
207 pub mod f32 {
208 use std::marker::PhantomData;
209 use super::{$name,One,$($dim),+};
210
211 #[allow(non_upper_case_globals, dead_code)]
212 pub const one: $name<One, f32> = $name {
213 amount: 1.0,
214 phantom: PhantomData
215 };
216
217 $(
218 #[allow(non_upper_case_globals, dead_code)]
219 pub const $unit: $name<$dim, f32> = $name {
220 amount: 1.0,
221 phantom: PhantomData
222 };
223 )+
224 }
225}}
226
227#[macro_export]
228#[doc(hidden)]
229macro_rules! __dim_type_alias_helper {
230 ( $dim:ident -> $($types:ty),+ ) => (
231 pub type $dim = Unit<$($types),+>;
232 );
233
234 ( $dim:ident, $($dims:ident),* -> $($types:ty),+ ) => (
235 pub type $dim = Unit<$($types),+>; __dim_type_alias_helper!( $($dims),* -> Zero, $($types),+);
236 )
237}
238
239#[macro_export]
240#[doc(hidden)]
241#[cfg(feature = "unstable")]
242macro_rules! __dim_fn_call_helper {
243 ($name:ident) => (
244 impl<D,N> FnOnce<(N,)> for $name<D,N> where N:Mul<N,Output=N> {
245 type Output = $name<D,N>;
246 extern "rust-call" fn call_once(self, args: (N,)) -> Self::Output {
247 $name::new(self.amount * args.0)
248 }
249 }
250 );
251}
252
253#[macro_export]
254#[doc(hidden)]
255#[cfg(not(feature = "unstable"))]
256macro_rules! __dim_fn_call_helper {
257 ($name:ident) => ()
259}
260
261mod smoke_test {
263 units! {
264 Units {
265 Meter[m],
266 Second[s]
267 }
268 }
269}