cgmath/
macros.rs

1// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
2// refer to the Cargo.toml file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Utility macros for code generation
17
18#![macro_use]
19
20#[cfg(feature = "simd")]
21macro_rules! default_fn {
22    { $($tt:tt)* } => { default fn $( $tt )* };
23}
24
25#[cfg(not(feature = "simd"))]
26macro_rules! default_fn {
27    { $($tt:tt)* } => { fn $( $tt )* };
28}
29
30/// Generates a binary operator implementation for the permutations of by-ref and by-val
31macro_rules! impl_operator {
32    // When it is an unary operator
33    (<$S:ident: $Constraint:ident> $Op:ident for $Lhs:ty {
34        fn $op:ident($x:ident) -> $Output:ty { $body:expr }
35    }) => {
36        impl<$S: $Constraint> $Op for $Lhs {
37            type Output = $Output;
38            #[inline]
39            default_fn!($op(self) -> $Output {
40                let $x = self; $body
41            });
42        }
43
44        impl<'a, $S: $Constraint> $Op for &'a $Lhs {
45            type Output = $Output;
46            #[inline]
47            default_fn!($op(self) -> $Output {
48                let $x = self; $body
49            });
50        }
51    };
52    // When the right operand is a scalar
53    (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ident> for $Lhs:ty {
54        fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
55    }) => {
56        impl<$S: $Constraint> $Op<$Rhs> for $Lhs {
57            type Output = $Output;
58            #[inline]
59            default_fn!($op(self, other: $Rhs) -> $Output {
60                let ($lhs, $rhs) = (self, other); $body
61            });
62        }
63
64        impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs {
65            type Output = $Output;
66            #[inline]
67            default_fn!($op(self, other: $Rhs) -> $Output {
68                let ($lhs, $rhs) = (self, other); $body
69            });
70        }
71    };
72    // When the right operand is a compound type
73    (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty {
74        fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
75    }) => {
76        impl<$S: $Constraint> $Op<$Rhs> for $Lhs {
77            type Output = $Output;
78            #[inline]
79            default_fn!( $op(self, other: $Rhs) -> $Output {
80                let ($lhs, $rhs) = (self, other); $body
81            });
82        }
83
84        impl<'a, $S: $Constraint> $Op<&'a $Rhs> for $Lhs {
85            type Output = $Output;
86            #[inline]
87            default_fn!( $op(self, other: &'a $Rhs) -> $Output {
88                let ($lhs, $rhs) = (self, other); $body
89            });
90        }
91
92        impl<'a, $S: $Constraint> $Op<$Rhs> for &'a $Lhs {
93            type Output = $Output;
94            #[inline]
95            default_fn!( $op(self, other: $Rhs) -> $Output {
96                let ($lhs, $rhs) = (self, other); $body
97            });
98        }
99
100        impl<'a, 'b, $S: $Constraint> $Op<&'a $Rhs> for &'b $Lhs {
101            type Output = $Output;
102            #[inline]
103            default_fn!( $op(self, other: &'a $Rhs) -> $Output {
104                let ($lhs, $rhs) = (self, other); $body
105            });
106        }
107    };
108    // When the left operand is a scalar
109    ($Op:ident<$Rhs:ident<$S:ident>> for $Lhs:ty {
110        fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
111    }) => {
112        impl $Op<$Rhs<$S>> for $Lhs {
113            type Output = $Output;
114            #[inline]
115            default_fn!( $op(self, other: $Rhs<$S>) -> $Output {
116                let ($lhs, $rhs) = (self, other); $body
117            });
118        }
119
120        impl<'a> $Op<&'a $Rhs<$S>> for $Lhs {
121            type Output = $Output;
122            #[inline]
123            default_fn!( $op(self, other: &'a $Rhs<$S>) -> $Output {
124                let ($lhs, $rhs) = (self, other); $body
125            });
126        }
127    };
128}
129
130macro_rules! impl_assignment_operator {
131    (<$S:ident: $Constraint:ident> $Op:ident<$Rhs:ty> for $Lhs:ty {
132        fn $op:ident(&mut $lhs:ident, $rhs:ident) $body:block
133    }) => {
134        impl<$S: $Constraint + $Op<$S>> $Op<$Rhs> for $Lhs {
135            #[inline]
136            default_fn!( $op(&mut $lhs, $rhs: $Rhs) $body );
137        }
138    };
139}
140
141macro_rules! fold_array {
142    (&$method:ident, { $x:expr }) => {
143        *$x
144    };
145    (&$method:ident, { $x:expr, $y:expr }) => {
146        $x.$method(&$y)
147    };
148    (&$method:ident, { $x:expr, $y:expr, $z:expr }) => {
149        $x.$method(&$y).$method(&$z)
150    };
151    (&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => {
152        $x.$method(&$y).$method(&$z).$method(&$w)
153    };
154    ($method:ident, { $x:expr }) => {
155        $x
156    };
157    ($method:ident, { $x:expr, $y:expr }) => {
158        $x.$method($y)
159    };
160    ($method:ident, { $x:expr, $y:expr, $z:expr }) => {
161        $x.$method($y).$method($z)
162    };
163    ($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => {
164        $x.$method($y).$method($z).$method($w)
165    };
166}
167
168/// Generate array conversion implementations for a compound array type
169macro_rules! impl_fixed_array_conversions {
170    ($ArrayN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => {
171        impl<$S> Into<[$S; $n]> for $ArrayN<$S> {
172            #[inline]
173            fn into(self) -> [$S; $n] {
174                match self { $ArrayN { $($field),+ } => [$($field),+] }
175            }
176        }
177
178        impl<$S> AsRef<[$S; $n]> for $ArrayN<$S> {
179            #[inline]
180            fn as_ref(&self) -> &[$S; $n] {
181                unsafe { mem::transmute(self) }
182            }
183        }
184
185        impl<$S> AsMut<[$S; $n]> for $ArrayN<$S> {
186            #[inline]
187            fn as_mut(&mut self) -> &mut [$S; $n] {
188                unsafe { mem::transmute(self) }
189            }
190        }
191
192        impl<$S: Clone> From<[$S; $n]> for $ArrayN<$S> {
193            #[inline]
194            fn from(v: [$S; $n]) -> $ArrayN<$S> {
195                // We need to use a clone here because we can't pattern match on arrays yet
196                $ArrayN { $($field: v[$index].clone()),+ }
197            }
198        }
199
200        impl<'a, $S> From<&'a [$S; $n]> for &'a $ArrayN<$S> {
201            #[inline]
202            fn from(v: &'a [$S; $n]) -> &'a $ArrayN<$S> {
203                unsafe { mem::transmute(v) }
204            }
205        }
206
207        impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $ArrayN<$S> {
208            #[inline]
209            fn from(v: &'a mut [$S; $n]) -> &'a mut $ArrayN<$S> {
210                unsafe { mem::transmute(v) }
211            }
212        }
213    }
214}
215
216/// Generate homogeneous tuple conversion implementations for a compound array type
217macro_rules! impl_tuple_conversions {
218    ($ArrayN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => {
219        impl<$S> Into<$Tuple> for $ArrayN<$S> {
220            #[inline]
221            fn into(self) -> $Tuple {
222                match self { $ArrayN { $($field),+ } => ($($field),+,) }
223            }
224        }
225
226        impl<$S> AsRef<$Tuple> for $ArrayN<$S> {
227            #[inline]
228            fn as_ref(&self) -> &$Tuple {
229                unsafe { mem::transmute(self) }
230            }
231        }
232
233        impl<$S> AsMut<$Tuple> for $ArrayN<$S> {
234            #[inline]
235            fn as_mut(&mut self) -> &mut $Tuple {
236                unsafe { mem::transmute(self) }
237            }
238        }
239
240        impl<$S> From<$Tuple> for $ArrayN<$S> {
241            #[inline]
242            fn from(v: $Tuple) -> $ArrayN<$S> {
243                match v { ($($field),+,) => $ArrayN { $($field: $field),+ } }
244            }
245        }
246
247        impl<'a, $S> From<&'a $Tuple> for &'a $ArrayN<$S> {
248            #[inline]
249            fn from(v: &'a $Tuple) -> &'a $ArrayN<$S> {
250                unsafe { mem::transmute(v) }
251            }
252        }
253
254        impl<'a, $S> From<&'a mut $Tuple> for &'a mut $ArrayN<$S> {
255            #[inline]
256            fn from(v: &'a mut $Tuple) -> &'a mut $ArrayN<$S> {
257                unsafe { mem::transmute(v) }
258            }
259        }
260    }
261}
262
263/// Generates index operators for a compound type
264macro_rules! impl_index_operators {
265    ($VectorN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {
266        impl<$S> Index<$I> for $VectorN<$S> {
267            type Output = $Output;
268
269            #[inline]
270            fn index<'a>(&'a self, i: $I) -> &'a $Output {
271                let v: &[$S; $n] = self.as_ref();
272                &v[i]
273            }
274        }
275
276        impl<$S> IndexMut<$I> for $VectorN<$S> {
277            #[inline]
278            fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
279                let v: &mut [$S; $n] = self.as_mut();
280                &mut v[i]
281            }
282        }
283    };
284}
285
286/// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd
287#[cfg(feature = "simd")]
288macro_rules! impl_operator_simd {
289    // When it is an unary operator
290    ([$Simd:ident]; $Op:ident for $Lhs:ty {
291        fn $op:ident($x:ident) -> $Output:ty { $body:expr }
292    }) => {
293        impl $Op for $Lhs {
294            #[inline]
295            fn $op(self) -> $Output {
296                let $x: $Simd = self.into();
297                $body
298            }
299        }
300    };
301    // When the right operand is a scalar
302    (@rs [$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty {
303        fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
304    }) => {
305        impl $Op<$Rhs> for $Lhs {
306            #[inline]
307            fn $op(self, other: $Rhs) -> $Output {
308                let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), $Simd::splat(other));
309                $body
310            }
311        }
312
313        impl<'a> $Op<$Rhs> for &'a $Lhs {
314            #[inline]
315            fn $op(self, other: $Rhs) -> $Output {
316                let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), $Simd::splat(other));
317                $body
318            }
319        }
320    };
321
322    // When the right operand is a compound type
323    ([$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty {
324        fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
325    }) => {
326        impl $Op<$Rhs> for $Lhs {
327            #[inline]
328            fn $op(self, other: $Rhs) -> $Output {
329                let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), other.into());
330                $body
331            }
332        }
333
334        impl<'a> $Op<&'a $Rhs> for $Lhs {
335            #[inline]
336            fn $op(self, other: &'a $Rhs) -> $Output {
337                let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), (*other).into());
338                $body
339            }
340        }
341
342        impl<'a> $Op<$Rhs> for &'a $Lhs {
343            #[inline]
344            fn $op(self, other: $Rhs) -> $Output {
345                let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), other.into());
346                $body
347            }
348        }
349
350        impl<'a, 'b> $Op<&'a $Rhs> for &'b $Lhs {
351            #[inline]
352            fn $op(self, other: &'a $Rhs) -> $Output {
353                let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), (*other).into());
354                $body
355            }
356        }
357    };
358
359    // When the left operand is a scalar
360    (@ls [$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ident {
361        fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
362    }) => {
363        impl $Op<$Rhs> for $Lhs {
364            #[inline]
365            fn $op(self, other: $Rhs) -> $Output {
366                let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), other.into());
367                $body
368            }
369        }
370
371        impl<'a> $Op<&'a $Rhs> for $Lhs {
372            #[inline]
373            fn $op(self, other: &'a $Rhs) -> $Output {
374                let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), (*other).into());
375                $body
376            }
377        }
378    };
379}
380
381/// Generate `mint` types conversion implementations
382#[cfg(feature = "mint")]
383macro_rules! impl_mint_conversions {
384    ($ArrayN:ident { $($field:ident),+ }, $Mint:ident) => {
385        impl<S: Clone> Into<mint::$Mint<S>> for $ArrayN<S> {
386            #[inline]
387            fn into(self) -> mint::$Mint<S> {
388                mint::$Mint::from([$(self.$field),+])
389            }
390        }
391
392        impl<S> From<mint::$Mint<S>> for $ArrayN<S> {
393            #[inline]
394            fn from(v: mint::$Mint<S>) -> Self {
395                $ArrayN { $( $field: v.$field, )+ }
396            }
397        }
398    }
399}
400
401include!(concat!(env!("OUT_DIR"), "/swizzle_operator_macro.rs"));